↩ revert: 回退部分修改

This commit is contained in:
imsyy
2024-05-24 10:47:14 +08:00
parent d64cfb40ec
commit e5f9ecd7b5
83 changed files with 1046 additions and 1062 deletions

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
* text eol=lf

View File

@@ -15,12 +15,12 @@ jobs:
steps:
# 检出 Git 仓库
- name: Check out git repository
uses: actions/checkout@v4
uses: actions/checkout@v4.1.1
# 安装 Node.js
- name: Install Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v4.0.0
with:
node-version: "20.x"
node-version: "18.x"
# 复制环境变量文件
- name: Copy .env.example
run: |
@@ -43,22 +43,7 @@ jobs:
npx rimraf "dist/!(*.exe)"
# 上传构建产物
- name: Upload artifacts
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.3
with:
name: SPlayer-dev
path: dist
# 自动生成标签
- name: Autotag
run: |
$tag = "v$(date +'%Y%m%d%H%M%S')"
git tag $tag
git push origin $tag
# 创建 GitHub Release
- name: Release
uses: softprops/action-gh-release@v2
with:
draft: false
prerelease: true
files: dist/*.exe
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}

View File

@@ -16,12 +16,12 @@ jobs:
steps:
# 检出 Git 仓库
- name: Check out git repository
uses: actions/checkout@v4
uses: actions/checkout@v4.1.1
# 安装 Node.js
- name: Install Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v4.0.0
with:
node-version: "20.x"
node-version: "18.x"
# 复制环境变量文件
- name: Copy .env.example
run: |
@@ -41,14 +41,14 @@ jobs:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
# 上传构建产物
- name: Upload Windows artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.3
with:
name: SPlarer-Win
if-no-files-found: ignore
path: dist/*.*
# 创建 GitHub Release
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v0.1.15
if: startsWith(github.ref, 'refs/tags/v')
with:
draft: true
@@ -63,12 +63,12 @@ jobs:
steps:
# 检出 Git 仓库
- name: Check out git repository
uses: actions/checkout@v4
uses: actions/checkout@v4.1.1
# 安装 Node.js
- name: Install Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v4.0.0
with:
node-version: "20.x"
node-version: "18.x"
# 复制环境变量文件
- name: Copy .env.example
run: |
@@ -88,14 +88,14 @@ jobs:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
# 上传构建产物
- name: Upload macOS artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.3
with:
name: SPlarer-Macos
if-no-files-found: ignore
path: dist/*.*
# 创建 GitHub Release
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v0.1.15
if: startsWith(github.ref, 'refs/tags/v')
with:
draft: true
@@ -110,12 +110,12 @@ jobs:
steps:
# 检出 Git 仓库
- name: Check out git repository
uses: actions/checkout@v4
uses: actions/checkout@v4.1.1
# 安装 Node.js
- name: Install Node.js
uses: actions/setup-node@v4
uses: actions/setup-node@v4.0.0
with:
node-version: "20.x"
node-version: "18.x"
# 更新 Ubuntu 软件源
- name: Ubuntu Update with sudo
run: sudo apt-get update
@@ -138,14 +138,14 @@ jobs:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }}
# 上传构建产物
- name: Upload Linux artifact
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@v3.1.3
with:
name: SPlarer-Linux
if-no-files-found: ignore
path: dist/*.*
# 创建 GitHub Release
- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v0.1.15
if: startsWith(github.ref, 'refs/tags/v')
with:
draft: true

2
.gitignore vendored
View File

@@ -15,8 +15,6 @@ coverage
*.local
out
.env
components.d.ts
auto-imports.d.ts
/cypress/videos/
/cypress/screenshots/

70
auto-imports.d.ts vendored Normal file
View File

@@ -0,0 +1,70 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
export {}
declare global {
const EffectScope: typeof import('vue')['EffectScope']
const computed: typeof import('vue')['computed']
const createApp: typeof import('vue')['createApp']
const customRef: typeof import('vue')['customRef']
const defineAsyncComponent: typeof import('vue')['defineAsyncComponent']
const defineComponent: typeof import('vue')['defineComponent']
const effectScope: typeof import('vue')['effectScope']
const getCurrentInstance: typeof import('vue')['getCurrentInstance']
const getCurrentScope: typeof import('vue')['getCurrentScope']
const h: typeof import('vue')['h']
const inject: typeof import('vue')['inject']
const isProxy: typeof import('vue')['isProxy']
const isReactive: typeof import('vue')['isReactive']
const isReadonly: typeof import('vue')['isReadonly']
const isRef: typeof import('vue')['isRef']
const markRaw: typeof import('vue')['markRaw']
const nextTick: typeof import('vue')['nextTick']
const onActivated: typeof import('vue')['onActivated']
const onBeforeMount: typeof import('vue')['onBeforeMount']
const onBeforeUnmount: typeof import('vue')['onBeforeUnmount']
const onBeforeUpdate: typeof import('vue')['onBeforeUpdate']
const onDeactivated: typeof import('vue')['onDeactivated']
const onErrorCaptured: typeof import('vue')['onErrorCaptured']
const onMounted: typeof import('vue')['onMounted']
const onRenderTracked: typeof import('vue')['onRenderTracked']
const onRenderTriggered: typeof import('vue')['onRenderTriggered']
const onScopeDispose: typeof import('vue')['onScopeDispose']
const onServerPrefetch: typeof import('vue')['onServerPrefetch']
const onUnmounted: typeof import('vue')['onUnmounted']
const onUpdated: typeof import('vue')['onUpdated']
const provide: typeof import('vue')['provide']
const reactive: typeof import('vue')['reactive']
const readonly: typeof import('vue')['readonly']
const ref: typeof import('vue')['ref']
const resolveComponent: typeof import('vue')['resolveComponent']
const shallowReactive: typeof import('vue')['shallowReactive']
const shallowReadonly: typeof import('vue')['shallowReadonly']
const shallowRef: typeof import('vue')['shallowRef']
const toRaw: typeof import('vue')['toRaw']
const toRef: typeof import('vue')['toRef']
const toRefs: typeof import('vue')['toRefs']
const toValue: typeof import('vue')['toValue']
const triggerRef: typeof import('vue')['triggerRef']
const unref: typeof import('vue')['unref']
const useAttrs: typeof import('vue')['useAttrs']
const useCssModule: typeof import('vue')['useCssModule']
const useCssVars: typeof import('vue')['useCssVars']
const useDialog: typeof import('naive-ui')['useDialog']
const useLoadingBar: typeof import('naive-ui')['useLoadingBar']
const useMessage: typeof import('naive-ui')['useMessage']
const useNotification: typeof import('naive-ui')['useNotification']
const useSlots: typeof import('vue')['useSlots']
const watch: typeof import('vue')['watch']
const watchEffect: typeof import('vue')['watchEffect']
const watchPostEffect: typeof import('vue')['watchPostEffect']
const watchSyncEffect: typeof import('vue')['watchSyncEffect']
}
// for type re-export
declare global {
// @ts-ignore
export type { Component, ComponentPublicInstance, ComputedRef, ExtractDefaultPropTypes, ExtractPropTypes, ExtractPublicPropTypes, InjectionKey, PropType, Ref, VNode, WritableComputedRef } from 'vue'
import('vue')
}

112
components.d.ts vendored Normal file
View File

@@ -0,0 +1,112 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// Generated by unplugin-vue-components
// Read more: https://github.com/vuejs/core/pull/3399
export {}
declare module 'vue' {
export interface GlobalComponents {
AddPlaylist: typeof import('./src/components/Modal/AddPlaylist.vue')['default']
CloudSongMatch: typeof import('./src/components/Modal/CloudSongMatch.vue')['default']
CommentList: typeof import('./src/components/List/CommentList.vue')['default']
CountDown: typeof import('./src/components/Player/CountDown.vue')['default']
CoverDropdown: typeof import('./src/components/Cover/CoverDropdown.vue')['default']
CoverPlayBtn: typeof import('./src/components/Cover/CoverPlayBtn.vue')['default']
CreatePlaylist: typeof import('./src/components/Modal/CreatePlaylist.vue')['default']
DownloadSong: typeof import('./src/components/Modal/DownloadSong.vue')['default']
FullPlayer: typeof import('./src/components/Player/FullPlayer.vue')['default']
Login: typeof import('./src/components/Modal/Login.vue')['default']
LoginPhone: typeof import('./src/components/Modal/LoginPhone.vue')['default']
LoginQRCode: typeof import('./src/components/Modal/LoginQRCode.vue')['default']
Lyric: typeof import('./src/components/Player/Lyric.vue')['default']
MainControl: typeof import('./src/components/Player/MainControl.vue')['default']
MainCover: typeof import('./src/components/Cover/MainCover.vue')['default']
MainLayout: typeof import('./src/components/Global/MainLayout.vue')['default']
MainNav: typeof import('./src/components/Nav/MainNav.vue')['default']
Menu: typeof import('./src/components/Global/Menu.vue')['default']
NAlert: typeof import('naive-ui')['NAlert']
NAvatar: typeof import('naive-ui')['NAvatar']
NBackTop: typeof import('naive-ui')['NBackTop']
NBadge: typeof import('naive-ui')['NBadge']
NButton: typeof import('naive-ui')['NButton']
NCard: typeof import('naive-ui')['NCard']
NCheckbox: typeof import('naive-ui')['NCheckbox']
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
NDivider: typeof import('naive-ui')['NDivider']
NDrawer: typeof import('naive-ui')['NDrawer']
NDrawerContent: typeof import('naive-ui')['NDrawerContent']
NDropdown: typeof import('naive-ui')['NDropdown']
NEllipsis: typeof import('naive-ui')['NEllipsis']
NEmpty: typeof import('naive-ui')['NEmpty']
NFlex: typeof import('naive-ui')['NFlex']
NForm: typeof import('naive-ui')['NForm']
NFormItem: typeof import('naive-ui')['NFormItem']
NGi: typeof import('naive-ui')['NGi']
NGlobalStyle: typeof import('naive-ui')['NGlobalStyle']
NGrid: typeof import('naive-ui')['NGrid']
NH1: typeof import('naive-ui')['NH1']
NH3: typeof import('naive-ui')['NH3']
NH4: typeof import('naive-ui')['NH4']
NH6: typeof import('naive-ui')['NH6']
NIcon: typeof import('naive-ui')['NIcon']
NImage: typeof import('naive-ui')['NImage']
NInput: typeof import('naive-ui')['NInput']
NInputNumber: typeof import('naive-ui')['NInputNumber']
NLayout: typeof import('naive-ui')['NLayout']
NLayoutContent: typeof import('naive-ui')['NLayoutContent']
NLayoutHeader: typeof import('naive-ui')['NLayoutHeader']
NLayoutSider: typeof import('naive-ui')['NLayoutSider']
NList: typeof import('naive-ui')['NList']
NListItem: typeof import('naive-ui')['NListItem']
NLoadingBarProvider: typeof import('naive-ui')['NLoadingBarProvider']
NMenu: typeof import('naive-ui')['NMenu']
NMessageProvider: typeof import('naive-ui')['NMessageProvider']
NModal: typeof import('naive-ui')['NModal']
NNotificationProvider: typeof import('naive-ui')['NNotificationProvider']
NNumberAnimation: typeof import('naive-ui')['NNumberAnimation']
NPagination: typeof import('naive-ui')['NPagination']
NPopover: typeof import('naive-ui')['NPopover']
NProgress: typeof import('naive-ui')['NProgress']
NQrCode: typeof import('naive-ui')['NQrCode']
NRadio: typeof import('naive-ui')['NRadio']
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
NResult: typeof import('naive-ui')['NResult']
NScrollbar: typeof import('naive-ui')['NScrollbar']
NSelect: typeof import('naive-ui')['NSelect']
NSkeleton: typeof import('naive-ui')['NSkeleton']
NSlider: typeof import('naive-ui')['NSlider']
NSpin: typeof import('naive-ui')['NSpin']
NSwitch: typeof import('naive-ui')['NSwitch']
NTab: typeof import('naive-ui')['NTab']
NTabPane: typeof import('naive-ui')['NTabPane']
NTabs: typeof import('naive-ui')['NTabs']
NTag: typeof import('naive-ui')['NTag']
NText: typeof import('naive-ui')['NText']
NThing: typeof import('naive-ui')['NThing']
NVirtualList: typeof import('naive-ui')['NVirtualList']
Pagination: typeof import('./src/components/Global/Pagination.vue')['default']
PlayerControl: typeof import('./src/components/Player/PlayerControl.vue')['default']
PlayerCover: typeof import('./src/components/Player/PlayerCover.vue')['default']
Playlist: typeof import('./src/components/Global/Playlist.vue')['default']
PlaylistUpdate: typeof import('./src/components/Modal/PlaylistUpdate.vue')['default']
PrivateFm: typeof import('./src/components/Player/PrivateFm.vue')['default']
Provider: typeof import('./src/components/Global/Provider.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
SearchHot: typeof import('./src/components/Search/SearchHot.vue')['default']
SearchInp: typeof import('./src/components/Search/SearchInp.vue')['default']
SearchSuggestions: typeof import('./src/components/Search/SearchSuggestions.vue')['default']
SongList: typeof import('./src/components/List/SongList.vue')['default']
SongListDrawer: typeof import('./src/components/List/SongListDrawer.vue')['default']
SongListDropdown: typeof import('./src/components/List/SongListDropdown.vue')['default']
SpecialCover: typeof import('./src/components/Cover/SpecialCover.vue')['default']
SpecialCoverCard: typeof import('./src/components/Cover/SpecialCoverCard.vue')['default']
Spectrum: typeof import('./src/components/Player/Spectrum.vue')['default']
SvgIcon: typeof import('./src/components/Global/SvgIcon.vue')['default']
TitleBar: typeof import('./src/components/WinDom/TitleBar.vue')['default']
UpCloudSong: typeof import('./src/components/Modal/UpCloudSong.vue')['default']
UserData: typeof import('./src/components/Nav/UserData.vue')['default']
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "splayer",
"version": "2.0.8",
"version": "2.0.7",
"description": "A minimalist music player",
"main": "./out/main/index.js",
"author": "imsyy",
@@ -30,7 +30,7 @@
"@electron-toolkit/preload": "^3.0.1",
"@electron-toolkit/utils": "^3.0.0",
"@material/material-color-utilities": "^0.2.7",
"NeteaseCloudMusicApi": "^4.19.5",
"NeteaseCloudMusicApi": "^4.15.8",
"axios": "^1.6.8",
"colorthief": "^2.4.0",
"electron-dl": "^3.5.2",
@@ -48,7 +48,7 @@
"pinia-plugin-persistedstate": "^3.2.1",
"plyr": "^3.7.8",
"screenfull": "^6.0.2",
"vue-router": "^4.3.2",
"vue-router": "^4.3.0",
"vue-slider-component": "4.1.0-beta.7"
},
"devDependencies": {
@@ -56,20 +56,20 @@
"@rushstack/eslint-patch": "^1.10.2",
"@vitejs/plugin-vue": "^5.0.4",
"@vue/eslint-config-prettier": "^9.0.0",
"ajv": "^8.13.0",
"electron": "^28.3.1",
"ajv": "^8.12.0",
"electron": "^28.3.0",
"electron-builder": "^24.13.3",
"electron-log": "^5.1.4",
"electron-vite": "^2.2.0",
"electron-log": "^5.1.2",
"electron-vite": "^2.1.0",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.26.0",
"naive-ui": "^2.38.2",
"eslint-plugin-vue": "^9.25.0",
"naive-ui": "^2.38.1",
"prettier": "^3.2.5",
"sass": "^1.77.0",
"terser": "^5.31.0",
"sass": "^1.75.0",
"terser": "^5.30.3",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0",
"vite": "^5.2.11",
"vite": "^5.2.9",
"vite-plugin-compression": "^0.5.1",
"vite-plugin-pwa": "^0.17.5",
"vue": "3.4.8"

1556
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

After

Width:  |  Height:  |  Size: 17 KiB

BIN
public/images/pic/album.png Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

After

Width:  |  Height:  |  Size: 158 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

BIN
public/images/pic/video.png Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 164 KiB

After

Width:  |  Height:  |  Size: 243 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 176 KiB

After

Width:  |  Height:  |  Size: 261 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 241 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 90 KiB

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 149 KiB

After

Width:  |  Height:  |  Size: 208 KiB

View File

@@ -95,24 +95,3 @@ export const likeComment = (id, cid, t, type = 0) => {
},
});
};
/**
* 电台节目评论
* @param {number} id - 电台节目的 id
* @param {number} limit - 取出评论数量 , 默认为 20
* @param {number} offset - 偏移数量 , 用于分页 , 如 :( 评论页数 -1)*20, 其中 20 为 limit 的值
* @param {string} before - 分页参数,取上一页最后一项的 time 获取下一页数据(获取超过 5000 条评论的时候需要用到)
*/
export const commentDj = (id, limit, offset, before) => {
return axios({
method: "GET",
url: "/comment/dj",
params: {
id,
limit,
offset,
before,
timestamp: new Date().getTime(),
},
});
};

View File

@@ -118,20 +118,6 @@ export const getDjProgram = (rid, limit = 50, offset = 0) => {
});
};
/**
* 电台 - 节目详情
* @param {string} id - 电台 的 id
*/
export const getDjProgramDetail = (id) => {
return axios({
method: "GET",
url: "/dj/program/detail",
params: {
id,
},
});
};
/**
* 电台 - 订阅
* @param {number} rid - 电台 的 id

View File

@@ -40,7 +40,7 @@
class="loading-img"
:src="
type === 'mv'
? '/images/pic/video.jpg?assest'
? '/images/pic/video.png?assest'
: type === 'artist'
? '/images/pic/artist.jpg?assest'
: '/images/pic/album.jpg?assest'

View File

@@ -25,7 +25,7 @@
>
<template #placeholder>
<div class="cover-loading">
<img class="loading-img" src="/images/pic/avatar.png?assest" alt="avatar" />
<img class="loading-img" src="/images/pic/avatar.jpg?assest" alt="avatar" />
</div>
</template>
</n-image>

View File

@@ -77,11 +77,7 @@
</n-text>
<!-- 特权 -->
<n-tag
v-if="
showPrivilege &&
item.fee === 1 &&
(userData.detail?.profile?.vipType !== 11 || !hiddenVipTags)
"
v-if="showPrivilege && item.fee === 1 && userData.detail?.profile?.vipType !== 11"
:bordered="false"
type="error"
size="small"
@@ -285,7 +281,7 @@ const dataStore = siteData();
const status = siteStatus();
const settings = siteSettings();
const { userData } = storeToRefs(dataStore);
const { loadSize, playSearch, useMusicCache, hiddenVipTags } = storeToRefs(settings);
const { loadSize, playSearch, useMusicCache } = storeToRefs(settings);
const { playList, playSongData, playSongSource } = storeToRefs(music);
const { playIndex, playMode, playHeartbeatMode, playLoading } = storeToRefs(status);

View File

@@ -50,7 +50,7 @@
<div class="left">
<!-- 歌词模式 -->
<n-icon
v-if="isHasLrc && playMode !== 'dj'"
v-if="isHasLrc"
:class="['lrc-open', { open: pureLyricMode }]"
size="28"
@click="pureLyricMode = !pureLyricMode"
@@ -78,17 +78,11 @@
:key="`${pureLyricMode}-${playCoverType}-${isHasLrc}-${music.getPlaySongData?.id}`"
class="main-player"
>
<div
v-show="!(pureLyricMode && isHasLrc) || playMode === 'dj'"
:class="['content', { 'no-lrc': !isHasLrc || playMode === 'dj' }]"
>
<div v-show="!(pureLyricMode && isHasLrc)" :class="['content', { 'no-lrc': !isHasLrc }]">
<!-- 封面 -->
<PlayerCover />
<!-- 信息 -->
<div
v-show="playCoverType === 'cover' || !isHasLrc || playMode === 'dj'"
:class="['data', playCoverType]"
>
<div v-show="playCoverType === 'cover' || !isHasLrc" :class="['data', playCoverType]">
<div class="desc">
<div class="title">
<span class="name">{{ music.getPlaySongData.name || "未知曲目" }}</span>
@@ -121,7 +115,7 @@
<span v-if="music.getPlaySongData.alia" class="alia">
{{ music.getPlaySongData.alia }}
</span>
<div v-if="playMode !== 'dj'" class="artist">
<div class="artist">
<n-icon depth="3" size="20">
<SvgIcon icon="account-music" />
</n-icon>
@@ -145,7 +139,6 @@
</div>
</div>
<div
v-if="playMode !== 'dj'"
class="album"
@click.stop="
() => {
@@ -168,28 +161,10 @@
</span>
<span v-else class="album">未知专辑</span>
</div>
<div
v-if="playMode === 'dj'"
class="dj"
@click.stop="
() => {
if (!playSongSource) return;
showFullPlayer = false;
router.push(`/dj?id=${playSongSource}`);
}
"
>
<n-icon depth="3" size="20">
<SvgIcon icon="record" />
</n-icon>
<span class="dj-name">
{{ music.getPlaySongData.creator?.brand || "未知电台" }}
</span>
</div>
</div>
</div>
</div>
<div v-if="playMode !== 'dj'" :class="['right', { pure: pureLyricMode && isHasLrc }]">
<div :class="['right', { pure: pureLyricMode && isHasLrc }]">
<!-- 唱片模式下信息 -->
<div
v-show="(pureLyricMode && isHasLrc) || (playCoverType === 'record' && isHasLrc)"
@@ -274,7 +249,7 @@ const router = useRouter();
const music = musicData();
const status = siteStatus();
const settings = siteSettings();
const { playList, playSongLyric, playSongSource } = storeToRefs(music);
const { playList, playSongLyric } = storeToRefs(music);
const { playerBackgroundType, showYrc, playCoverType, showSpectrums } = storeToRefs(settings);
const {
playerControlShow,
@@ -284,7 +259,6 @@ const {
coverTheme,
coverBackground,
pureLyricMode,
playMode,
} = storeToRefs(status);
// 是否有歌词
@@ -414,11 +388,6 @@ onUnmounted(() => {
&.gradient {
background: var(--cover-bg);
}
&.none {
&::after {
display: none;
}
}
}
// 按钮
.menu {
@@ -578,25 +547,6 @@ onUnmounted(() => {
}
}
}
.dj {
margin-top: 12px;
font-size: 16px;
display: flex;
align-items: center;
.n-icon {
margin-right: 4px;
color: var(--cover-main-color);
}
.dj-name {
opacity: 0.7;
transition: opacity 0.3s;
-webkit-line-clamp: 2;
cursor: pointer;
&:hover {
opacity: 1;
}
}
}
}
&.record {
width: 100%;

View File

@@ -94,7 +94,7 @@
</n-icon>
<!-- 更多操作 -->
<n-dropdown
v-if="!music.getPlaySongData?.path"
v-if="playMode !== 'dj' && !music.getPlaySongData?.path"
:options="songMoreOptions"
:show-arrow="true"
placement="top-start"
@@ -415,7 +415,6 @@ const songMoreOptions = computed(() => [
{
key: "add-pl",
label: "添加到歌单",
show: playMode.value !== "dj",
props: {
onClick: () => {
addPlaylistRef.value?.openAddToPlaylist(music.getPlaySongData?.id);
@@ -432,7 +431,6 @@ const songMoreOptions = computed(() => [
path: "/comment",
query: {
id: music.getPlaySongData?.id,
type: playMode.value,
},
});
},
@@ -442,9 +440,7 @@ const songMoreOptions = computed(() => [
{
key: "mv",
label: "观看 MV",
show:
playMode.value !== "dj" &&
(music.getPlaySongData?.mv && music.getPlaySongData?.mv !== 0 ? true : false),
show: music.getPlaySongData?.mv && music.getPlaySongData?.mv !== 0 ? true : false,
props: {
onClick: () => {
router.push({
@@ -460,7 +456,7 @@ const songMoreOptions = computed(() => [
{
key: "download",
label: "下载歌曲",
show: playMode.value !== "dj" && (music.getPlaySongData?.path ? false : true),
show: music.getPlaySongData?.path ? false : true,
props: {
onClick: () => {
downloadSongRef.value?.openDownloadModal(music.getPlaySongData);
@@ -491,10 +487,10 @@ const songTimeSliderUpdate = (val) => {
// 开启播放器
const openFullPlayer = () => {
// if (playMode.value === "dj") {
// $message.warning("当前为电台模式,无法开启播放器");
// return false;
// }
if (playMode.value === "dj") {
$message.warning("当前为电台模式,无法开启播放器");
return false;
}
if (showSpectrums.value && typeof $player !== "undefined") processSpectrum($player);
showFullPlayer.value = true;
};

View File

@@ -10,7 +10,7 @@
<div class="left">
<!-- 喜欢歌曲 -->
<n-icon
v-if="!music.getPlaySongData.path && playMode !== 'dj'"
v-if="!music.getPlaySongData.path"
size="24"
@click.stop="
data.changeLikeList(
@@ -30,7 +30,7 @@
</n-icon>
<!-- 添加到歌单 -->
<n-icon
v-if="!music.getPlaySongData.path && playMode !== 'dj'"
v-if="!music.getPlaySongData.path"
class="hidden"
size="24"
@click.stop="addPlaylistRef?.openAddToPlaylist(music.getPlaySongData?.id)"
@@ -39,7 +39,7 @@
</n-icon>
<!-- 下载 -->
<n-icon
v-if="!music.getPlaySongData.path && playMode !== 'dj'"
v-if="!music.getPlaySongData.path"
class="hidden"
size="24"
@click.stop="downloadSongRef?.openDownloadModal(music.getPlaySongData)"
@@ -125,7 +125,9 @@
v-if="!music.getPlaySongData?.path"
class="hidden"
size="22"
@click.stop="jumpToComment"
@click.stop="
(showFullPlayer = false), router.push(`/comment?id=${music.getPlaySongData?.id}`)
"
>
<SvgIcon icon="comment-text" />
</n-icon>
@@ -185,7 +187,7 @@
/>
</n-icon>
<!-- 播放列表 -->
<n-icon v-if="playMode !== 'fm'" size="22" @click.stop="playListShow = !playListShow">
<n-icon v-if="playMode === 'normal'" size="22" @click.stop="playListShow = !playListShow">
<SvgIcon icon="queue-music-rounded" />
</n-icon>
</div>
@@ -309,18 +311,6 @@ const controlEnter = () => {
const controlMove = (e) => {
if (!e.target.closest(".slider")) e.stopPropagation();
};
// 跳转至评论
const jumpToComment = () => {
showFullPlayer.value = false;
router.push({
path: "/comment",
query: {
id: music.getPlaySongData?.id,
type: playMode.value,
},
});
};
</script>
<style lang="scss" scoped>

View File

@@ -1,6 +1,6 @@
<!-- 播放器 - 专辑封面 -->
<template>
<div :class="['mian-cover', playCoverType, { playing: playState }]">
<div :class="['cover', playCoverType]">
<!-- 指针 -->
<img
v-if="playCoverType === 'record'"
@@ -57,7 +57,7 @@ const { playState } = storeToRefs(status);
</script>
<style lang="scss" scoped>
.mian-cover {
.cover {
position: relative;
display: flex;
align-items: center;
@@ -66,14 +66,13 @@ const { playState } = storeToRefs(status);
max-width: 55vh;
height: auto;
aspect-ratio: 1 / 1;
transition: transform 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
.cover-img {
width: 100%;
height: 100%;
border-radius: 32px;
overflow: hidden;
z-index: 1;
box-shadow: 0 0 20px 10px rgb(0 0 0 / 10%);
box-shadow: 0 0 10px 6px #00000008;
transition: opacity 0.1s ease-in-out;
:deep(img) {
width: 100%;
@@ -207,13 +206,6 @@ const { playState } = storeToRefs(status);
display: none;
}
}
&.cover {
transform: scale(0.9);
&.playing {
transform: scale(1);
}
}
@media (max-width: 700px) {
&.record {
.pointer {

View File

@@ -16,7 +16,6 @@ const useSiteSettingsStore = defineStore("siteSettings", {
autoCheckUpdates: true, // 自动检查更新
systemFonts: "HarmonyOS Sans", // 全局字体
justLyricArea: false, // 仅在歌词区域生效
hiddenVipTags: false, // 隐藏 VIP 标签
// 主题部分
themeType: "dark",
themeAuto: false,

View File

@@ -32,7 +32,6 @@ const useSiteStatusStore = defineStore("siteStatus", {
pureLyricMode: false,
// 音乐频谱数据
spectrumsData: [],
spectrumsScaleData: 1,
// 当前歌曲歌词播放索引
playSongLyricIndex: -1,
// 播放时长数据

View File

@@ -23,7 +23,6 @@ let spectrumsData = {
audio: null,
analyser: null,
audioCtx: null,
scale: 1,
};
// 默认标题
let defaultTitle = document.title;
@@ -57,15 +56,13 @@ export const initPlayer = async (playNow = false) => {
if (playMode === "fm") music.playSongData = {};
// 在线歌曲
if (!isLocalSong) {
// 获取歌曲 ID
let songId = playSongData?.id;
if (!songId) return false;
// 若为电台模式
if (playMode === "dj") songId = music.getPlaySongData?.djId;
// 获取歌曲信息
const { id } = playSongData;
if (!id) return false;
// 开启加载状态
status.playLoading = true;
// 获取播放地址
const url = await getNormalSongUrl(songId, status, playNow);
const url = await getNormalSongUrl(id, status, playNow);
// 正常播放地址
if (url) {
status.playUseOtherSource = false;
@@ -93,7 +90,7 @@ export const initPlayer = async (playNow = false) => {
// 下一曲
else {
if (playIndex !== playList.length - 1) {
// changePlayIndex();
changePlayIndex();
} else {
status.playLoading = false;
status.playState = false;
@@ -238,7 +235,7 @@ export const createPlayer = async (src, autoPlay = true) => {
const audioDom = player._sounds[0]._node;
audioDom.crossOrigin = "anonymous";
// 写入播放历史
if (playMode !== "dj") music.setPlayHistory(playSongData);
music.setPlayHistory(playSongData);
// 生成音乐频谱
// 由于浏览器安全策略,无法在此处启动
if (showSpectrums && checkPlatform.electron()) processSpectrum(player);
@@ -758,12 +755,8 @@ export const processSpectrum = (sound) => {
const updateSpectrums = (analyser, dataArray) => {
// pinia
const status = siteStatus();
// 获取频率数据
analyser.getByteFrequencyData(dataArray);
status.spectrumsData = [...dataArray];
// 计算 scale
const averageAmplitude = dataArray.reduce((acc, val) => acc + val, 0) / dataArray.length;
status.spectrumsScaleData = (averageAmplitude / 512 + 1).toFixed(2);
// 递归调用,持续更新频谱数据
requestAnimationFrame(() => {
updateSpectrums(analyser, dataArray);

View File

@@ -112,8 +112,7 @@ const formatData = (data, type = "playlist", noTracks = false) => {
// dj
case "dj":
return {
id: v.id || v.vid,
djId: v.mainTrackId || v.id,
id: v.mainTrackId || v.id || v.vid,
name: v.name,
creator: v.dj,
count: v.programCount,

View File

@@ -11,6 +11,7 @@ const globalEvents = (router) => {
// 显示播放器
electron.ipcRenderer.on("showPlayer", () => {
const status = siteStatus();
if (status.playMode === "dj") return false;
status.showFullPlayer = true;
});
// 播放或暂停

View File

@@ -9,9 +9,6 @@ import { siteStatus } from "@/stores";
*/
const globalShortcut = (e, router) => {
if (!e) return false;
// 是否按下 Ctrl
if (!e.ctrlKey) return false;
e.preventDefault();
e.stopPropagation();

View File

@@ -18,7 +18,7 @@
>
<template #placeholder>
<div class="cover-loading">
<img class="loading-img" src="/images/pic/avatar.png?assest" alt="avatar" />
<img class="loading-img" src="/images/pic/avatar.jpg?assest" alt="avatar" />
</div>
</template>
</n-image>

View File

@@ -32,7 +32,7 @@
</n-image>
<div class="content">
<div class="name">{{ songDetail?.name || "未知曲目" }}</div>
<div v-if="commentType === 'normal'" class="artist">
<div class="artist">
<n-icon depth="3" size="20">
<SvgIcon icon="account-music" />
</n-icon>
@@ -45,14 +45,6 @@
<span class="ar"> {{ songDetail?.artists || "未知艺术家" }} </span>
</div>
</div>
<div v-else-if="songDetail?.creator" class="artist dj">
<n-icon depth="3" size="20">
<SvgIcon icon="record" />
</n-icon>
<span class="all-ar dj-name">
{{ songDetail.creator?.brand || "未知电台" }}
</span>
</div>
</div>
</n-card>
</Transition>
@@ -94,8 +86,7 @@
<script setup>
import { useRouter } from "vue-router";
import { getSongDetail } from "@/api/song";
import { getDjProgramDetail } from "@/api/dj";
import { getComment, getHotComment, commentDj } from "@/api/comment";
import { getComment, getHotComment } from "@/api/comment";
import formatData from "@/utils/formatData";
const router = useRouter();
@@ -103,9 +94,6 @@ const router = useRouter();
// 歌曲 id
const songId = ref(router.currentRoute.value.query.id);
// 评论类型
const commentType = ref(router.currentRoute.value.query.type || "normal");
// 歌曲信息
const songDetail = ref(null);
@@ -117,15 +105,9 @@ const hotCommentData = ref(null);
// 获取歌曲详情
const getSongDetailData = async (id) => {
try {
if (commentType.value === "normal") {
const detail = await getSongDetail(id);
const data = formatData(detail?.songs?.[0], "song");
songDetail.value = data?.[0] ?? null;
} else if (commentType.value === "dj") {
const detail = await getDjProgramDetail(id);
const data = formatData(detail?.program, "dj");
songDetail.value = data?.[0] ?? null;
}
const detail = await getSongDetail(id);
const data = formatData(detail?.songs?.[0], "song");
songDetail.value = data?.[0] ?? null;
} catch (error) {
console.error("获取歌曲详情失败:", error);
}
@@ -138,24 +120,14 @@ const getCommentData = async (id, pageNo = 1, sortType = 3, pageSize = 20) => {
const cursor =
pageNo !== 1 && commentData.value?.cursor !== "0" ? commentData.value.cursor : null;
// 获取热门评论和普通评论
if (commentType.value === "normal") {
const [hotComments, comments] = await Promise.all([
pageNo === 1 ? getHotComment(id, 0, 10) : null,
getComment(id, 0, pageNo, sortType, pageSize, cursor),
]);
// 更新数据
if (comments?.data.totalCount === 0) return (commentData.value = "empty");
commentData.value = comments?.data;
hotCommentData.value = hotComments?.hotComments?.[0] ? hotComments.hotComments : "no-comment";
} else if (commentType.value === "dj") {
const offset = (pageNo - 1) * pageSize;
const { hotComments, comments, total } = await commentDj(id, pageSize, offset, cursor);
// 更新数据
if (total === 0) return (commentData.value = "empty");
commentData.value = { totalCount: comments?.length, comments };
hotCommentData.value = hotComments?.[0] ? hotComments : "no-comment";
console.log(commentData.value, hotCommentData.value);
}
const [hotComments, comments] = await Promise.all([
pageNo === 1 ? getHotComment(id, 0, 10) : null,
getComment(id, 0, pageNo, sortType, pageSize, cursor),
]);
// 更新数据
if (comments?.data.totalCount === 0) return (commentData.value = "empty");
commentData.value = comments?.data;
hotCommentData.value = hotComments?.hotComments?.[0] ? hotComments.hotComments : "no-comment";
} catch (error) {
console.error("获取评论数据出错:", error);
$message.error("获取评论数据出错");
@@ -177,7 +149,7 @@ const scrollToComment = () => {
}
};
// 检查是否具有 id
// 检查是否具有视频 id
const isHasCommentId = (id) => {
if (!id) {
$message.error("参数不完整");

View File

@@ -34,7 +34,7 @@
<div class="creator">
<n-avatar
:src="(djDetail.creator?.avatarUrl + '?param=300y$300').replace(/^http:/, 'https:')"
fallback-src="/images/pic/avatar.png?assest"
fallback-src="/images/pic/avatar.jpg?assest"
round
/>
<n-text class="nickname">{{ djDetail.creator?.nickname || "未知创建者" }}</n-text>
@@ -170,9 +170,9 @@
<div v-if="djData !== 'empty'" class="list">
<Transition name="fade" mode="out-in">
<div v-if="!searchValue" class="song-list">
<SongList :data="djData" :sourceId="djId" type="dj" />
<SongList :data="djData" type="dj" />
</div>
<SongList v-else-if="searchData?.length" :data="searchData" :sourceId="djId" type="dj" />
<SongList v-else-if="searchData?.length" :data="searchData" type="dj" />
<n-empty
v-else
:description="`搜不到关于 ${searchValue} 的任何节目`"

View File

@@ -39,7 +39,7 @@
:src="
(playListDetail.creator?.avatarUrl + '?param=300y$300').replace(/^http:/, 'https:')
"
fallback-src="/images/pic/avatar.png?assest"
fallback-src="/images/pic/avatar.jpg?assest"
round
/>
<n-text class="nickname">{{ playListDetail.creator?.nickname || "未知创建者" }}</n-text>

View File

@@ -174,7 +174,7 @@
>
<template #placeholder>
<div class="cover-loading">
<img class="loading-img" src="/images/pic/avatar.png?assest" alt="song" />
<img class="loading-img" src="/images/pic/avatar.jpg?assest" alt="song" />
</div>
</template>
</n-image>

View File

@@ -122,13 +122,6 @@
class="set"
/>
</n-card>
<n-card class="set-item">
<div class="name">
隐藏 VIP 歌曲标签
<n-text class="tip">是否在歌曲列表中隐藏 VIP 歌曲标签</n-text>
</div>
<n-switch v-model:value="hiddenVipTags" :round="false" />
</n-card>
</div>
</template>
@@ -150,7 +143,6 @@ const {
showSearchHistory,
autoSignIn,
siderShowCover,
hiddenVipTags,
} = storeToRefs(settings);
// 基础数据

View File

@@ -103,10 +103,6 @@
label: '主色渐变',
value: 'gradient',
},
{
label: '无背景',
value: 'none',
},
]"
class="set"
/>

View File

@@ -5,15 +5,6 @@
<n-scrollbar style="max-height: 120px">
{{ status.spectrumsData }}
</n-scrollbar>
<n-scrollbar style="max-height: 120px">
{{ status.spectrumsScaleData }}
<div
:style="{
transform: `scale(${status.spectrumsScaleData})`,
}"
class="point"
></div>
</n-scrollbar>
</n-card>
<n-card title="频谱图">
<canvas ref="canvasRef" class="avBars" style="width: 100%" />
@@ -94,11 +85,4 @@ onMounted(() => {
hsla(0, 0%, 100%, 0)
);
}
.point {
width: 30px;
height: 30px;
margin: 20px;
border-radius: 50%;
background-color: var(--main-color);
}
</style>

View File

@@ -1,4 +1,3 @@
{
"cleanUrls": true,
"rewrites": [{ "source": "/:path*", "destination": "/index.html" }]
}