diff --git a/package.json b/package.json
index b7b75f0a..d4f77c08 100644
--- a/package.json
+++ b/package.json
@@ -67,7 +67,7 @@
"@uiw/codemirror-extensions-events": "4.21.3",
"@urql/core": "4.0.10",
"ahooks": "3.7.7",
- "aplayer-react": "1.4.0",
+ "aplayer": "^1.10.1",
"async-lock": "1.4.0",
"canvas": "2.11.2",
"canvas-confetti": "1.6.0",
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 19d35637..b865fddf 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -116,9 +116,9 @@ dependencies:
ahooks:
specifier: 3.7.7
version: 3.7.7(react@18.2.0)
- aplayer-react:
- specifier: 1.4.0
- version: 1.4.0(react@18.2.0)
+ aplayer:
+ specifier: ^1.10.1
+ version: 1.10.1
async-lock:
specifier: 1.4.0
version: 1.4.0
@@ -5658,15 +5658,12 @@ packages:
normalize-path: 3.0.0
picomatch: 2.3.1
- /aplayer-react@1.4.0(react@18.2.0):
- resolution: {integrity: sha512-gYEWk1ynBSdF7qjMCo1wl2itg595iVj5jdo0Ewep9RhX7aHxdCykwp22t/cwce+KSQ6BAXg4JhUPCsm1oopiLw==}
- peerDependencies:
- react: ^18.2.0
+ /aplayer@1.10.1:
+ resolution: {integrity: sha512-HAfyxgCUTLAqtYlxzzK9Fyqg6y+kZ9CqT1WfeWE8FSzwspT6oBqWOZHANPHF3RGTtC33IsyEgrfthPDzU5r9kQ==}
dependencies:
- clsx: 1.2.1
- fast-average-color: 9.3.0
- react: 18.2.0
- use-sync-external-store: 1.2.0(react@18.2.0)
+ balloon-css: 0.5.2
+ promise-polyfill: 7.1.0
+ smoothscroll: 0.4.0
dev: false
/aproba@2.0.0:
@@ -5948,6 +5945,10 @@ packages:
/balanced-match@1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
+ /balloon-css@0.5.2:
+ resolution: {integrity: sha512-zheJpzwyNrG4t39vusA67v3BYg1HTVXOF8cErPEHzWK88PEOFwgo6Ea9VHOgOWNMgeuOtFVtB73NE2NWl9uDyQ==}
+ dev: false
+
/balloon-css@1.2.0:
resolution: {integrity: sha512-urXwkHgwp6GsXVF+it01485Z2Cj4pnW02ICnM0TemOlkKmCNnDLmyy+ZZiRXBpwldUXO+aRNr7Hdia4CBvXJ5A==}
dev: false
@@ -11243,6 +11244,10 @@ packages:
resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==}
dev: false
+ /promise-polyfill@7.1.0:
+ resolution: {integrity: sha512-P6NJ2wU/8fac44ENORsuqT8TiolKGB2u0fEClPtXezn7w5cmLIjM/7mhPlTebke2EPr6tmqZbXvnX0TxwykGrg==}
+ dev: false
+
/promise-polyfill@8.3.0:
resolution: {integrity: sha512-H5oELycFml5yto/atYqmjyigJoAo3+OXwolYiH7OfQuYlAqhxNvTfiNMbV9hsC6Yp83yE5r2KTVmtrG6R9i6Pg==}
dev: false
@@ -12330,6 +12335,10 @@ packages:
is-fullwidth-code-point: 4.0.0
dev: true
+ /smoothscroll@0.4.0:
+ resolution: {integrity: sha512-sggQ3U2Un38b3+q/j1P4Y4fCboCtoUIaBYoge+Lb6Xg1H8RTIif/hugVr+ErMtIDpvBbhQfTjtiTeYAfbw1ZGQ==}
+ dev: false
+
/sonic-boom@2.8.0:
resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==}
dependencies:
diff --git a/src/app/site/[site]/layout.tsx b/src/app/site/[site]/layout.tsx
index eb41ba12..84c1d8fb 100644
--- a/src/app/site/[site]/layout.tsx
+++ b/src/app/site/[site]/layout.tsx
@@ -5,6 +5,7 @@ import { notFound } from "next/navigation"
import { Hydrate, dehydrate } from "@tanstack/react-query"
import { BlockchainInfo } from "~/components/common/BlockchainInfo"
+import { SitePlayerContainer } from "~/components/common/SitePlayer"
import Style from "~/components/common/Style"
import { BackToTopFAB } from "~/components/site/BackToTopFAB"
import SiteFooter from "~/components/site/SiteFooter"
@@ -208,6 +209,8 @@ export default async function SiteLayout({
+
+
)
}
diff --git a/src/components/common/SitePlayer.tsx b/src/components/common/SitePlayer.tsx
new file mode 100644
index 00000000..ed1a4fa1
--- /dev/null
+++ b/src/components/common/SitePlayer.tsx
@@ -0,0 +1,44 @@
+"use client"
+
+// @ts-ignore
+import APlayer from "aplayer"
+import "aplayer/dist/APlayer.min.css"
+
+let siteAPlayer: APlayer
+
+const playerId = "site-aplayer"
+
+// APlayer Container
+export const SitePlayerContainer = () => {
+ return
+}
+
+export interface AudioInfo {
+ name?: string
+ artist?: string
+ cover?: string
+ lrc?: string
+ url: string
+}
+
+export const sitePlayerAddToPlaylist = (audio: AudioInfo) => {
+ // Check if player is initialized
+ if (!siteAPlayer) {
+ // Initialize
+ siteAPlayer = new APlayer({
+ container: document.getElementById(playerId),
+ fixed: true,
+ listFolded: false,
+ })
+ }
+ // Add
+ siteAPlayer.list.add(audio)
+}
+
+export const sitePlayerPlayNow = (audio: AudioInfo) => {
+ // Add to playlist
+ sitePlayerAddToPlaylist(audio)
+ // Play now
+ siteAPlayer.list.switch(siteAPlayer.list.audios.length - 1)
+ siteAPlayer.play()
+}
diff --git a/src/components/ui/APlayer.tsx b/src/components/ui/APlayer.tsx
index 3fcffd6c..2080d23d 100644
--- a/src/components/ui/APlayer.tsx
+++ b/src/components/ui/APlayer.tsx
@@ -1,9 +1,14 @@
"use client"
-import { APlayer as AplayerReact } from "aplayer-react"
-import "aplayer-react/dist/index.css"
+import Image from "next/image"
import { memo } from "react"
+import {
+ sitePlayerAddToPlaylist,
+ sitePlayerPlayNow,
+} from "~/components/common/SitePlayer"
+import { Tooltip } from "~/components/ui/Tooltip"
+import { useTranslation } from "~/lib/i18n/client"
import { toGateway } from "~/lib/ipfs-parser"
const APlayer = memo(function APlayer({
@@ -21,6 +26,8 @@ const APlayer = memo(function APlayer({
cover?: string
lrc?: string
} & React.AudioHTMLAttributes) {
+ const { t } = useTranslation("common")
+
if (!src) return null
src = toGateway(src)
@@ -31,19 +38,74 @@ const APlayer = memo(function APlayer({
name = name.replace(/^user-content-/, "")
}
+ const audioInfo = {
+ name: name || "xLog audio",
+ artist: artist || "",
+ cover: cover || "/assets/logo.png",
+ lrc,
+ url: src,
+ }
+
+ const addToList = () => {
+ sitePlayerAddToPlaylist(audioInfo)
+ }
+
+ const playNow = () => {
+ sitePlayerPlayNow(audioInfo)
+ }
+
return (
-
+
+ {/*Info*/}
+
+ {/*Cover*/}
+
+
+
+
+ {/*Name & Artist*/}
+
+ {/*Name*/}
+
{audioInfo.name}
+
+ {/*Artist*/}
+
{audioInfo.artist}
+
+
+
+ {/*Control buttons*/}
+
+ {/*Play Now*/}
+
+
+
+
+
+
+
+
+ {/*Add to playlist*/}
+
+
+
+
+
+
+
+
+
)
})
diff --git a/src/lib/i18n/locales/ja/common.json b/src/lib/i18n/locales/ja/common.json
index 2dd0cc98..700531be 100644
--- a/src/lib/i18n/locales/ja/common.json
+++ b/src/lib/i18n/locales/ja/common.json
@@ -55,5 +55,7 @@
"Showcase": "ショーケース",
"AI-generated summary": "AIが生成した要約",
"Generating": "生成中",
- "Show more": "もっと表示する"
+ "Show more": "もっと表示する",
+ "Play": "再生",
+ "Add to playlist": "プレイリストに追加する"
}
diff --git a/src/lib/i18n/locales/zh-TW/common.json b/src/lib/i18n/locales/zh-TW/common.json
index 0d226379..513ce475 100644
--- a/src/lib/i18n/locales/zh-TW/common.json
+++ b/src/lib/i18n/locales/zh-TW/common.json
@@ -83,5 +83,7 @@
"Refreshing": "重新載入中",
"Search for your interest": "搜你所想",
"results": "項結果",
- "My xLog": "你的 xLog"
-}
\ No newline at end of file
+ "My xLog": "你的 xLog",
+ "Play": "播放",
+ "Add to playlist": "添加到播放列表"
+}
diff --git a/src/lib/i18n/locales/zh/common.json b/src/lib/i18n/locales/zh/common.json
index a6918022..bab0aae2 100644
--- a/src/lib/i18n/locales/zh/common.json
+++ b/src/lib/i18n/locales/zh/common.json
@@ -88,5 +88,7 @@
"Comment Without Login": "免登录评论",
"Name": "昵称",
"Email": "电子邮箱",
- "You'll use an official public account for comments and give up blockchain ownership": "你将使用官方公共账号进行评论并放弃区块链所有权"
+ "You'll use an official public account for comments and give up blockchain ownership": "你将使用官方公共账号进行评论并放弃区块链所有权",
+ "Play": "播放",
+ "Add to playlist": "添加到播放列表"
}