mirror of
https://github.com/imsyy/SPlayer.git
synced 2025-11-25 03:14:57 +08:00
✨ feat: 支持解锁配置
This commit is contained in:
@@ -32,8 +32,12 @@
|
|||||||
|
|
||||||
## 💬 交流群
|
## 💬 交流群
|
||||||
|
|
||||||
|
<a href="https://qm.qq.com/cgi-bin/qm/qr?k=2-cVSf1bE0AvAehCib00qFEFdUvPaJ_k&jump_from=webapi&authKey=1NEhib9+GsmsXVo2rCc0IbRaVHeeRXJJ0gbsyKDcIwDdAzYySOubkFCvkV32+7Cw" target="_blank">
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
</a>
|
||||||
|
|
||||||
## 👀 Demo
|
## 👀 Demo
|
||||||
|
|
||||||
- [SPlayer](https://music.imsyy.top/)
|
- [SPlayer](https://music.imsyy.top/)
|
||||||
|
|||||||
1
components.d.ts
vendored
1
components.d.ts
vendored
@@ -146,6 +146,7 @@ declare module 'vue' {
|
|||||||
SongList: typeof import('./src/components/List/SongList.vue')['default']
|
SongList: typeof import('./src/components/List/SongList.vue')['default']
|
||||||
SongListCard: typeof import('./src/components/Card/SongListCard.vue')['default']
|
SongListCard: typeof import('./src/components/Card/SongListCard.vue')['default']
|
||||||
SongListMenu: typeof import('./src/components/Menu/SongListMenu.vue')['default']
|
SongListMenu: typeof import('./src/components/Menu/SongListMenu.vue')['default']
|
||||||
|
SongUnlockManager: typeof import('./src/components/Modal/SongUnlockManager.vue')['default']
|
||||||
SvgIcon: typeof import('./src/components/Global/SvgIcon.vue')['default']
|
SvgIcon: typeof import('./src/components/Global/SvgIcon.vue')['default']
|
||||||
TextContainer: typeof import('./src/components/Global/TextContainer.vue')['default']
|
TextContainer: typeof import('./src/components/Global/TextContainer.vue')['default']
|
||||||
UpdateApp: typeof import('./src/components/Modal/UpdateApp.vue')['default']
|
UpdateApp: typeof import('./src/components/Modal/UpdateApp.vue')['default']
|
||||||
|
|||||||
@@ -49,6 +49,7 @@
|
|||||||
"@pixi/filter-color-matrix": "^7.4.3",
|
"@pixi/filter-color-matrix": "^7.4.3",
|
||||||
"@pixi/sprite": "^7.4.3",
|
"@pixi/sprite": "^7.4.3",
|
||||||
"@vueuse/core": "^13.9.0",
|
"@vueuse/core": "^13.9.0",
|
||||||
|
"@vueuse/integrations": "^14.0.0",
|
||||||
"axios": "^1.13.2",
|
"axios": "^1.13.2",
|
||||||
"axios-retry": "^4.5.0",
|
"axios-retry": "^4.5.0",
|
||||||
"change-case": "^5.4.4",
|
"change-case": "^5.4.4",
|
||||||
@@ -72,6 +73,7 @@
|
|||||||
"pinia": "^3.0.4",
|
"pinia": "^3.0.4",
|
||||||
"pinia-plugin-persistedstate": "^4.7.1",
|
"pinia-plugin-persistedstate": "^4.7.1",
|
||||||
"plyr": "^3.8.3",
|
"plyr": "^3.8.3",
|
||||||
|
"sortablejs": "^1",
|
||||||
"vue-virt-list": "^1.6.1"
|
"vue-virt-list": "^1.6.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
91
pnpm-lock.yaml
generated
91
pnpm-lock.yaml
generated
@@ -60,6 +60,9 @@ importers:
|
|||||||
'@vueuse/core':
|
'@vueuse/core':
|
||||||
specifier: ^13.9.0
|
specifier: ^13.9.0
|
||||||
version: 13.9.0(vue@3.5.24(typescript@5.9.3))
|
version: 13.9.0(vue@3.5.24(typescript@5.9.3))
|
||||||
|
'@vueuse/integrations':
|
||||||
|
specifier: ^14.0.0
|
||||||
|
version: 14.0.0(async-validator@4.2.5)(axios@1.13.2)(change-case@5.4.4)(qrcode@1.5.4)(sortablejs@1.15.6)(vue@3.5.24(typescript@5.9.3))
|
||||||
axios:
|
axios:
|
||||||
specifier: ^1.13.2
|
specifier: ^1.13.2
|
||||||
version: 1.13.2
|
version: 1.13.2
|
||||||
@@ -129,6 +132,9 @@ importers:
|
|||||||
plyr:
|
plyr:
|
||||||
specifier: ^3.8.3
|
specifier: ^3.8.3
|
||||||
version: 3.8.3
|
version: 3.8.3
|
||||||
|
sortablejs:
|
||||||
|
specifier: ^1
|
||||||
|
version: 1.15.6
|
||||||
vue-virt-list:
|
vue-virt-list:
|
||||||
specifier: ^1.6.1
|
specifier: ^1.6.1
|
||||||
version: 1.6.1(vue@3.5.24(typescript@5.9.3))
|
version: 1.6.1(vue@3.5.24(typescript@5.9.3))
|
||||||
@@ -1514,14 +1520,69 @@ packages:
|
|||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.5.0
|
vue: ^3.5.0
|
||||||
|
|
||||||
|
'@vueuse/core@14.0.0':
|
||||||
|
resolution: {integrity: sha512-d6tKRWkZE8IQElX2aHBxXOMD478fHIYV+Dzm2y9Ag122ICBpNKtGICiXKOhWU3L1kKdttDD9dCMS4bGP3jhCTQ==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.0
|
||||||
|
|
||||||
|
'@vueuse/integrations@14.0.0':
|
||||||
|
resolution: {integrity: sha512-5A0X7q9qyLtM3xyghq5nK/NEESf7cpcZlkQgXTMuW4JWiAMYxc1ImdhhGrk4negFBsq3ejvAlRmLdNrkcTzk1Q==}
|
||||||
|
peerDependencies:
|
||||||
|
async-validator: ^4
|
||||||
|
axios: ^1
|
||||||
|
change-case: ^5
|
||||||
|
drauu: ^0.4
|
||||||
|
focus-trap: ^7
|
||||||
|
fuse.js: ^7
|
||||||
|
idb-keyval: ^6
|
||||||
|
jwt-decode: ^4
|
||||||
|
nprogress: ^0.2
|
||||||
|
qrcode: ^1.5
|
||||||
|
sortablejs: ^1
|
||||||
|
universal-cookie: ^7 || ^8
|
||||||
|
vue: ^3.5.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
async-validator:
|
||||||
|
optional: true
|
||||||
|
axios:
|
||||||
|
optional: true
|
||||||
|
change-case:
|
||||||
|
optional: true
|
||||||
|
drauu:
|
||||||
|
optional: true
|
||||||
|
focus-trap:
|
||||||
|
optional: true
|
||||||
|
fuse.js:
|
||||||
|
optional: true
|
||||||
|
idb-keyval:
|
||||||
|
optional: true
|
||||||
|
jwt-decode:
|
||||||
|
optional: true
|
||||||
|
nprogress:
|
||||||
|
optional: true
|
||||||
|
qrcode:
|
||||||
|
optional: true
|
||||||
|
sortablejs:
|
||||||
|
optional: true
|
||||||
|
universal-cookie:
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@vueuse/metadata@13.9.0':
|
'@vueuse/metadata@13.9.0':
|
||||||
resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==}
|
resolution: {integrity: sha512-1AFRvuiGphfF7yWixZa0KwjYH8ulyjDCC0aFgrGRz8+P4kvDFSdXLVfTk5xAN9wEuD1J6z4/myMoYbnHoX07zg==}
|
||||||
|
|
||||||
|
'@vueuse/metadata@14.0.0':
|
||||||
|
resolution: {integrity: sha512-6yoGqbJcMldVCevkFiHDBTB1V5Hq+G/haPlGIuaFZHpXC0HADB0EN1ryQAAceiW+ryS3niUwvdFbGiqHqBrfVA==}
|
||||||
|
|
||||||
'@vueuse/shared@13.9.0':
|
'@vueuse/shared@13.9.0':
|
||||||
resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==}
|
resolution: {integrity: sha512-e89uuTLMh0U5cZ9iDpEI2senqPGfbPRTHM/0AaQkcxnpqjkZqDYP8rpfm7edOz8s+pOCOROEy1PIveSW8+fL5g==}
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
vue: ^3.5.0
|
vue: ^3.5.0
|
||||||
|
|
||||||
|
'@vueuse/shared@14.0.0':
|
||||||
|
resolution: {integrity: sha512-mTCA0uczBgurRlwVaQHfG0Ja7UdGe4g9mwffiJmvLiTtp1G4AQyIjej6si/k8c8pUwTfVpNufck+23gXptPAkw==}
|
||||||
|
peerDependencies:
|
||||||
|
vue: ^3.5.0
|
||||||
|
|
||||||
'@xmldom/xmldom@0.8.11':
|
'@xmldom/xmldom@0.8.11':
|
||||||
resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
|
resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==}
|
||||||
engines: {node: '>=10.0.0'}
|
engines: {node: '>=10.0.0'}
|
||||||
@@ -3932,6 +3993,9 @@ packages:
|
|||||||
resolution: {integrity: sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==}
|
resolution: {integrity: sha512-vzn8aSqKgytVik0iwdBEi+zevbTYZogewTUM6dtpmGwEcdzbub/TX4bCzRhebDCRC3QzXgJsLRKB2V/Oof7HXg==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
sortablejs@1.15.6:
|
||||||
|
resolution: {integrity: sha512-aNfiuwMEpfBM/CN6LY0ibyhxPfPbyFeBTYJKCvzkJ2GkUpazIt3H+QIPAMHwqQ7tMKaHz1Qj+rJJCqljnf4p3A==}
|
||||||
|
|
||||||
source-map-js@1.2.1:
|
source-map-js@1.2.1:
|
||||||
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
@@ -5876,12 +5940,37 @@ snapshots:
|
|||||||
'@vueuse/shared': 13.9.0(vue@3.5.24(typescript@5.9.3))
|
'@vueuse/shared': 13.9.0(vue@3.5.24(typescript@5.9.3))
|
||||||
vue: 3.5.24(typescript@5.9.3)
|
vue: 3.5.24(typescript@5.9.3)
|
||||||
|
|
||||||
|
'@vueuse/core@14.0.0(vue@3.5.24(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
'@types/web-bluetooth': 0.0.21
|
||||||
|
'@vueuse/metadata': 14.0.0
|
||||||
|
'@vueuse/shared': 14.0.0(vue@3.5.24(typescript@5.9.3))
|
||||||
|
vue: 3.5.24(typescript@5.9.3)
|
||||||
|
|
||||||
|
'@vueuse/integrations@14.0.0(async-validator@4.2.5)(axios@1.13.2)(change-case@5.4.4)(qrcode@1.5.4)(sortablejs@1.15.6)(vue@3.5.24(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
'@vueuse/core': 14.0.0(vue@3.5.24(typescript@5.9.3))
|
||||||
|
'@vueuse/shared': 14.0.0(vue@3.5.24(typescript@5.9.3))
|
||||||
|
vue: 3.5.24(typescript@5.9.3)
|
||||||
|
optionalDependencies:
|
||||||
|
async-validator: 4.2.5
|
||||||
|
axios: 1.13.2
|
||||||
|
change-case: 5.4.4
|
||||||
|
qrcode: 1.5.4
|
||||||
|
sortablejs: 1.15.6
|
||||||
|
|
||||||
'@vueuse/metadata@13.9.0': {}
|
'@vueuse/metadata@13.9.0': {}
|
||||||
|
|
||||||
|
'@vueuse/metadata@14.0.0': {}
|
||||||
|
|
||||||
'@vueuse/shared@13.9.0(vue@3.5.24(typescript@5.9.3))':
|
'@vueuse/shared@13.9.0(vue@3.5.24(typescript@5.9.3))':
|
||||||
dependencies:
|
dependencies:
|
||||||
vue: 3.5.24(typescript@5.9.3)
|
vue: 3.5.24(typescript@5.9.3)
|
||||||
|
|
||||||
|
'@vueuse/shared@14.0.0(vue@3.5.24(typescript@5.9.3))':
|
||||||
|
dependencies:
|
||||||
|
vue: 3.5.24(typescript@5.9.3)
|
||||||
|
|
||||||
'@xmldom/xmldom@0.8.11': {}
|
'@xmldom/xmldom@0.8.11': {}
|
||||||
|
|
||||||
abbrev@1.1.1: {}
|
abbrev@1.1.1: {}
|
||||||
@@ -8598,6 +8687,8 @@ snapshots:
|
|||||||
dependencies:
|
dependencies:
|
||||||
is-plain-obj: 1.1.0
|
is-plain-obj: 1.1.0
|
||||||
|
|
||||||
|
sortablejs@1.15.6: {}
|
||||||
|
|
||||||
source-map-js@1.2.1: {}
|
source-map-js@1.2.1: {}
|
||||||
|
|
||||||
source-map-support@0.5.21:
|
source-map-support@0.5.21:
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { isElectron } from "@/utils/env";
|
import { isElectron } from "@/utils/env";
|
||||||
import { songLevelData } from "@/utils/meta";
|
import { songLevelData } from "@/utils/meta";
|
||||||
|
import { SongUnlockServer } from "@/utils/songManager";
|
||||||
import request from "@/utils/request";
|
import request from "@/utils/request";
|
||||||
|
|
||||||
// 获取歌曲详情
|
// 获取歌曲详情
|
||||||
@@ -47,16 +48,12 @@ export const songUrl = (
|
|||||||
};
|
};
|
||||||
|
|
||||||
// 获取解锁歌曲 URL
|
// 获取解锁歌曲 URL
|
||||||
export const unlockSongUrl = (
|
export const unlockSongUrl = (id: number, keyword: string, server: SongUnlockServer) => {
|
||||||
id: number,
|
const params = server === SongUnlockServer.NETEASE ? { id } : { keyword };
|
||||||
keyword: string,
|
|
||||||
server: "netease" | "kuwo" | "bodian",
|
|
||||||
) => {
|
|
||||||
const params = server === "netease" ? { id } : { keyword };
|
|
||||||
return request({
|
return request({
|
||||||
baseURL: "/api/unblock",
|
baseURL: "/api/unblock",
|
||||||
url: `/${server}`,
|
url: `/${server}`,
|
||||||
params,
|
params: { ...params, noCookie: true },
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
62
src/components/Modal/SongUnlockManager.vue
Normal file
62
src/components/Modal/SongUnlockManager.vue
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
<template>
|
||||||
|
<div class="song-unlock-manager">
|
||||||
|
<n-alert title="免责声明" type="info">
|
||||||
|
本功能仅作为测试使用,资源来自网络,若侵犯到您的权益,请及时联系我们删除
|
||||||
|
</n-alert>
|
||||||
|
<div ref="sortableRef" class="sortable-list">
|
||||||
|
<n-card
|
||||||
|
v-for="item in settingStore.songUnlockServer"
|
||||||
|
:key="item.key"
|
||||||
|
:content-style="{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: '12px',
|
||||||
|
padding: '16px',
|
||||||
|
}"
|
||||||
|
class="sortable-item"
|
||||||
|
>
|
||||||
|
<SvgIcon :depth="3" name="Menu" />
|
||||||
|
<n-text class="name">{{ item.key }}</n-text>
|
||||||
|
<n-switch v-model:value="item.enabled" :round="false" />
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup lang="ts">
|
||||||
|
import { useSettingStore } from "@/stores";
|
||||||
|
import { useSortable } from "@vueuse/integrations/useSortable";
|
||||||
|
|
||||||
|
const settingStore = useSettingStore();
|
||||||
|
|
||||||
|
const sortableRef = ref<HTMLElement | null>(null);
|
||||||
|
|
||||||
|
// 拖拽
|
||||||
|
useSortable(sortableRef, settingStore.songUnlockServer, {
|
||||||
|
animation: 150,
|
||||||
|
handle: ".n-icon",
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style scoped lang="scss">
|
||||||
|
.sortable-list {
|
||||||
|
margin-top: 12px;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 12px;
|
||||||
|
.sortable-item {
|
||||||
|
border-radius: 8px;
|
||||||
|
.n-icon {
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: move;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
font-size: 16px;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
.n-switch {
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
@@ -34,7 +34,7 @@
|
|||||||
|
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import { LyricPlayer } from "@applemusic-like-lyrics/vue";
|
import { LyricPlayer } from "@applemusic-like-lyrics/vue";
|
||||||
import { LyricLine } from "@applemusic-like-lyrics/core";
|
import { type LyricLine } from "@applemusic-like-lyrics/lyric";
|
||||||
import { useMusicStore, useSettingStore, useStatusStore } from "@/stores";
|
import { useMusicStore, useSettingStore, useStatusStore } from "@/stores";
|
||||||
import { getLyricLanguage } from "@/utils/format";
|
import { getLyricLanguage } from "@/utils/format";
|
||||||
import { usePlayer } from "@/utils/player";
|
import { usePlayer } from "@/utils/player";
|
||||||
|
|||||||
@@ -36,6 +36,21 @@
|
|||||||
</n-card>
|
</n-card>
|
||||||
</n-collapse-transition>
|
</n-collapse-transition>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="set-list">
|
||||||
|
<n-h3 prefix="bar"> 社区与资讯 </n-h3>
|
||||||
|
<n-flex class="link">
|
||||||
|
<n-card
|
||||||
|
v-for="(item, index) in communityData"
|
||||||
|
:key="index"
|
||||||
|
class="link-item"
|
||||||
|
hoverable
|
||||||
|
@click="openLink(item.url)"
|
||||||
|
>
|
||||||
|
<SvgIcon :name="item.icon" :size="26" />
|
||||||
|
<n-text class="name"> {{ item.name }} </n-text>
|
||||||
|
</n-card>
|
||||||
|
</n-flex>
|
||||||
|
</div>
|
||||||
<div class="set-list">
|
<div class="set-list">
|
||||||
<n-h3 prefix="bar"> 历史版本 </n-h3>
|
<n-h3 prefix="bar"> 历史版本 </n-h3>
|
||||||
<n-collapse-transition :show="oldVersion?.length > 0">
|
<n-collapse-transition :show="oldVersion?.length > 0">
|
||||||
@@ -59,21 +74,6 @@
|
|||||||
</n-collapse>
|
</n-collapse>
|
||||||
</n-collapse-transition>
|
</n-collapse-transition>
|
||||||
</div>
|
</div>
|
||||||
<div class="set-list">
|
|
||||||
<n-h3 prefix="bar"> 社区与资讯 </n-h3>
|
|
||||||
<n-flex class="link">
|
|
||||||
<n-card
|
|
||||||
v-for="(item, index) in communityData"
|
|
||||||
:key="index"
|
|
||||||
class="link-item"
|
|
||||||
hoverable
|
|
||||||
@click="openLink(item.url)"
|
|
||||||
>
|
|
||||||
<SvgIcon :name="item.icon" :size="26" />
|
|
||||||
<n-text class="name"> {{ item.name }} </n-text>
|
|
||||||
</n-card>
|
|
||||||
</n-flex>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -89,6 +89,11 @@ const statusStore = useStatusStore();
|
|||||||
|
|
||||||
// 社区数据
|
// 社区数据
|
||||||
const communityData = [
|
const communityData = [
|
||||||
|
{
|
||||||
|
name: "加入交流群",
|
||||||
|
url: "https://qm.qq.com/cgi-bin/qm/qr?k=2-cVSf1bE0AvAehCib00qFEFdUvPaJ_k&jump_from=webapi&authKey=1NEhib9+GsmsXVo2rCc0IbRaVHeeRXJJ0gbsyKDcIwDdAzYySOubkFCvkV32+7Cw",
|
||||||
|
icon: "QQ",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "GitHub",
|
name: "GitHub",
|
||||||
url: packageJson.github,
|
url: packageJson.github,
|
||||||
|
|||||||
@@ -251,9 +251,7 @@
|
|||||||
<div class="label">
|
<div class="label">
|
||||||
<n-text class="name">
|
<n-text class="name">
|
||||||
启用在线 TTML 歌词
|
启用在线 TTML 歌词
|
||||||
<n-tag type="warning" size="small" round style="display: inline; vertical-align: middle"
|
<n-tag type="warning" size="small" round> Beta </n-tag>
|
||||||
>Beta</n-tag
|
|
||||||
>
|
|
||||||
</n-text>
|
</n-text>
|
||||||
<n-text class="tip" :depth="3">
|
<n-text class="tip" :depth="3">
|
||||||
是否从 AMLL TTML DB 获取歌词(如有),TTML
|
是否从 AMLL TTML DB 获取歌词(如有),TTML
|
||||||
|
|||||||
@@ -66,13 +66,6 @@
|
|||||||
</div>
|
</div>
|
||||||
<n-switch v-model:value="settingStore.playSongDemo" class="set" :round="false" />
|
<n-switch v-model:value="settingStore.playSongDemo" class="set" :round="false" />
|
||||||
</n-card>
|
</n-card>
|
||||||
<n-card v-if="isElectron" class="set-item">
|
|
||||||
<div class="label">
|
|
||||||
<n-text class="name">音乐解锁</n-text>
|
|
||||||
<n-text class="tip" :depth="3">在无法正常播放时进行替换,可能会与原曲不符</n-text>
|
|
||||||
</div>
|
|
||||||
<n-switch v-model:value="settingStore.useSongUnlock" class="set" :round="false" />
|
|
||||||
</n-card>
|
|
||||||
<n-card v-if="isElectron" class="set-item">
|
<n-card v-if="isElectron" class="set-item">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
<n-text class="name">音频输出设备</n-text>
|
<n-text class="name">音频输出设备</n-text>
|
||||||
@@ -87,6 +80,35 @@
|
|||||||
/>
|
/>
|
||||||
</n-card>
|
</n-card>
|
||||||
</div>
|
</div>
|
||||||
|
<div v-if="isElectron" class="set-list">
|
||||||
|
<n-h3 prefix="bar">
|
||||||
|
音乐解锁
|
||||||
|
<n-tag type="warning" size="small" round>Beta</n-tag>
|
||||||
|
</n-h3>
|
||||||
|
<n-card class="set-item">
|
||||||
|
<div class="label">
|
||||||
|
<n-text class="name">音乐解锁</n-text>
|
||||||
|
<n-text class="tip" :depth="3"> 在无法正常播放时进行替换,可能会与原曲不符 </n-text>
|
||||||
|
</div>
|
||||||
|
<n-switch v-model:value="settingStore.useSongUnlock" class="set" :round="false" />
|
||||||
|
</n-card>
|
||||||
|
<!-- 音源配置 -->
|
||||||
|
<n-card class="set-item">
|
||||||
|
<div class="label">
|
||||||
|
<n-text class="name">音源配置</n-text>
|
||||||
|
<n-text class="tip" :depth="3"> 配置歌曲解锁的音源顺序或是否启用 </n-text>
|
||||||
|
</div>
|
||||||
|
<n-button
|
||||||
|
:disabled="!settingStore.useSongUnlock"
|
||||||
|
type="primary"
|
||||||
|
strong
|
||||||
|
secondary
|
||||||
|
@click="openSongUnlockManager"
|
||||||
|
>
|
||||||
|
配置
|
||||||
|
</n-button>
|
||||||
|
</n-card>
|
||||||
|
</div>
|
||||||
<div class="set-list">
|
<div class="set-list">
|
||||||
<n-h3 prefix="bar"> 播放器 </n-h3>
|
<n-h3 prefix="bar"> 播放器 </n-h3>
|
||||||
<n-card class="set-item">
|
<n-card class="set-item">
|
||||||
@@ -228,6 +250,7 @@ import { renderOption } from "@/utils/helper";
|
|||||||
import { isElectron } from "@/utils/env";
|
import { isElectron } from "@/utils/env";
|
||||||
import { uniqBy } from "lodash";
|
import { uniqBy } from "lodash";
|
||||||
import { usePlayer } from "@/utils/player";
|
import { usePlayer } from "@/utils/player";
|
||||||
|
import { openSongUnlockManager } from "@/utils/modal";
|
||||||
|
|
||||||
const player = usePlayer();
|
const player = usePlayer();
|
||||||
const settingStore = useSettingStore();
|
const settingStore = useSettingStore();
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { defineStore } from "pinia";
|
import { defineStore } from "pinia";
|
||||||
import { keywords, regexes } from "@/assets/data/exclude";
|
import { keywords, regexes } from "@/assets/data/exclude";
|
||||||
|
import { SongUnlockServer } from "@/utils/songManager";
|
||||||
|
|
||||||
export interface SettingState {
|
export interface SettingState {
|
||||||
/** 明暗模式 */
|
/** 明暗模式 */
|
||||||
@@ -99,6 +100,8 @@ export interface SettingState {
|
|||||||
songVolumeFadeTime: number;
|
songVolumeFadeTime: number;
|
||||||
/** 是否使用解灰 */
|
/** 是否使用解灰 */
|
||||||
useSongUnlock: boolean;
|
useSongUnlock: boolean;
|
||||||
|
/** 歌曲解锁音源 */
|
||||||
|
songUnlockServer: { key: SongUnlockServer; enabled: boolean }[];
|
||||||
/** 显示倒计时 */
|
/** 显示倒计时 */
|
||||||
countDownShow: boolean;
|
countDownShow: boolean;
|
||||||
/** 显示歌词条 */
|
/** 显示歌词条 */
|
||||||
@@ -201,6 +204,11 @@ export const useSettingStore = defineStore("setting", {
|
|||||||
songVolumeFade: true,
|
songVolumeFade: true,
|
||||||
songVolumeFadeTime: 300,
|
songVolumeFadeTime: 300,
|
||||||
useSongUnlock: true,
|
useSongUnlock: true,
|
||||||
|
songUnlockServer: [
|
||||||
|
{ key: SongUnlockServer.BODIAN, enabled: true },
|
||||||
|
{ key: SongUnlockServer.GEQUBAO, enabled: true },
|
||||||
|
{ key: SongUnlockServer.NETEASE, enabled: true },
|
||||||
|
],
|
||||||
countDownShow: true,
|
countDownShow: true,
|
||||||
barLyricShow: true,
|
barLyricShow: true,
|
||||||
playerType: "cover",
|
playerType: "cover",
|
||||||
|
|||||||
@@ -3,7 +3,6 @@
|
|||||||
padding: 0;
|
padding: 0;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
-webkit-user-drag: none;
|
|
||||||
::after {
|
::after {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
}
|
}
|
||||||
@@ -18,6 +17,12 @@ body {
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img,
|
||||||
|
video,
|
||||||
|
audio {
|
||||||
|
-webkit-user-drag: none;
|
||||||
|
}
|
||||||
|
|
||||||
#app {
|
#app {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ import ExcludeLyrics from "@/components/Modal/ExcludeLyrics.vue";
|
|||||||
import ChangeRate from "@/components/Modal/ChangeRate.vue";
|
import ChangeRate from "@/components/Modal/ChangeRate.vue";
|
||||||
import AutoClose from "@/components/Modal/AutoClose.vue";
|
import AutoClose from "@/components/Modal/AutoClose.vue";
|
||||||
import Equalizer from "@/components/Modal/Equalizer.vue";
|
import Equalizer from "@/components/Modal/Equalizer.vue";
|
||||||
|
import SongUnlockManager from "@/components/Modal/SongUnlockManager.vue";
|
||||||
import { NScrollbar } from "naive-ui";
|
import { NScrollbar } from "naive-ui";
|
||||||
|
|
||||||
// 用户协议
|
// 用户协议
|
||||||
@@ -319,3 +320,17 @@ export const openDescModal = (content: string, title: string = "歌单简介") =
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/** 打开音源管理弹窗 */
|
||||||
|
export const openSongUnlockManager = () => {
|
||||||
|
window.$modal.create({
|
||||||
|
preset: "card",
|
||||||
|
transformOrigin: "center",
|
||||||
|
autoFocus: false,
|
||||||
|
style: { width: "500px" },
|
||||||
|
title: "音源管理",
|
||||||
|
content: () => {
|
||||||
|
return h(SongUnlockManager);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|||||||
@@ -84,23 +84,34 @@ export const getUnlockSongUrl = async (songData: SongType): Promise<string | nul
|
|||||||
const artist = Array.isArray(songData.artists) ? songData.artists[0].name : songData.artists;
|
const artist = Array.isArray(songData.artists) ? songData.artists[0].name : songData.artists;
|
||||||
const keyWord = songData.name + "-" + artist;
|
const keyWord = songData.name + "-" + artist;
|
||||||
if (!songId || !keyWord) return null;
|
if (!songId || !keyWord) return null;
|
||||||
|
// 获取音源列表
|
||||||
const servers: any[] = [
|
const settingStore = useSettingStore();
|
||||||
"bodian",
|
const servers = settingStore.songUnlockServer
|
||||||
"netease",
|
.filter((server) => server.enabled)
|
||||||
];
|
.map((server) => server.key);
|
||||||
|
if (servers.length === 0) return null;
|
||||||
// 尝试解锁
|
// 并发请求
|
||||||
const promises = servers.map(server => unlockSongUrl(songId, keyWord, server));
|
const promises = servers.map((server) =>
|
||||||
const results = await Promise.allSettled(promises);
|
unlockSongUrl(songId, keyWord, server)
|
||||||
// 解析结果
|
.then((result) => ({
|
||||||
for (const result of results) {
|
server,
|
||||||
if (
|
result,
|
||||||
result.status === "fulfilled" &&
|
success: result.code === 200 && !!result.url,
|
||||||
result.value.code === 200 &&
|
}))
|
||||||
result.value.url
|
.catch((err) => {
|
||||||
) {
|
console.error(`Unlock failed with server ${server}:`, err);
|
||||||
return result.value.url;
|
return { server, result: null, success: false };
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
// 按优先级顺序处理结果
|
||||||
|
for (const p of promises) {
|
||||||
|
try {
|
||||||
|
const item = await p;
|
||||||
|
if (item.success && item.result) {
|
||||||
|
return item.result.url;
|
||||||
|
}
|
||||||
|
} catch {
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -1,3 +1,13 @@
|
|||||||
|
/**
|
||||||
|
* 歌曲解锁服务器
|
||||||
|
*/
|
||||||
|
export enum SongUnlockServer {
|
||||||
|
NETEASE = "netease",
|
||||||
|
BODIAN = "bodian",
|
||||||
|
// KUWO = "kuwo",
|
||||||
|
GEQUBAO = "gequbao",
|
||||||
|
}
|
||||||
|
|
||||||
class SongManager {}
|
class SongManager {}
|
||||||
|
|
||||||
export default new SongManager();
|
export default new SongManager();
|
||||||
|
|||||||
Reference in New Issue
Block a user