-
Notifications
You must be signed in to change notification settings - Fork 1.1k
✨ feat: 音质鉴权 #779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
✨ feat: 音质鉴权 #779
Conversation
Summary of ChangesHello @kazukokawagawa, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! 此拉取请求通过引入强大的多账号管理功能,显著提升了用户体验,允许用户在不同配置文件之间无缝切换。同时,它实现了一个全面的音质鉴权系统,根据用户的VIP订阅级别动态调整可用的播放和下载选项,确保符合服务层级并提供量身定制的体验。 Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
这个 Pull Request 引入了两个主要功能:基于 VIP 状态的音质鉴权和多账号管理。代码改动涉及面较广,实现得比较全面。基于 VIP 的音质过滤逻辑在多个组件中都得到了正确的实现,但在代码优化和类型安全方面还有一些提升空间,例如移除 @ts-ignore 和 as any。多账号切换功能设计良好,添加、切换和移除账号的流程清晰。我的审查主要关注于提升代码的清晰度、可维护性和类型安全。
| // @ts-ignore | ||
| allData = allData.filter((item) => allowedLevels.includes(item.level)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // @ts-ignore | ||
| allData = allData.filter((item) => AUTHORIZED_QUALITY_LEVELS.NORMAL.includes(item.level)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // @ts-ignore | ||
| allData = allData.filter((item) => allowedLevels.includes(item.level)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // @ts-ignore | ||
| allData = allData.filter((item) => AUTHORIZED_QUALITY_LEVELS.NORMAL.includes(item.level)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
可以通过对 AUTHORIZED_QUALITY_LEVELS.NORMAL 添加类型断言来移除 @ts-ignore,这能让代码更安全、更清晰。
| // @ts-ignore | |
| allData = allData.filter((item) => AUTHORIZED_QUALITY_LEVELS.NORMAL.includes(item.level)); | |
| allData = allData.filter((item) => (AUTHORIZED_QUALITY_LEVELS.NORMAL as readonly string[]).includes(item.level)); |
| // @ts-ignore | ||
| options = options.filter((o) => allowedLevels.includes(o.value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // @ts-ignore | ||
| options = options.filter((o) => AUTHORIZED_QUALITY_LEVELS.NORMAL.includes(o.value)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应该避免使用 @ts-ignore。对 AUTHORIZED_QUALITY_LEVELS.NORMAL 进行类型断言可以解决类型错误并提高类型安全性。
| // @ts-ignore | |
| options = options.filter((o) => AUTHORIZED_QUALITY_LEVELS.NORMAL.includes(o.value)); | |
| options = options.filter((o) => (AUTHORIZED_QUALITY_LEVELS.NORMAL as readonly string[]).includes(o.value)); |
src/composables/useQualityControl.ts
Outdated
| console.log("[QualityControl] Levels from API:", levels); | ||
| console.log("[QualityControl] User VIP Type:", dataStore.userData.vipType, "Login Status:", dataStore.userLoginStatus); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/composables/useQualityControl.ts
Outdated
| if (dataStore.userLoginStatus) { | ||
| const vipType = dataStore.userData.vipType || 0; | ||
| // SVIP 拥有所有权限,不需要过滤 | ||
| if (!isSvip(vipType)) { | ||
| const allowedLevels = isVip(vipType) | ||
| ? AUTHORIZED_QUALITY_LEVELS.VIP | ||
| : AUTHORIZED_QUALITY_LEVELS.NORMAL; | ||
|
|
||
| statusStore.availableQualities = levels.filter((q) => | ||
| (allowedLevels as readonly string[]).includes(q.level), | ||
| ); | ||
| } else { | ||
| // SVIP | ||
| statusStore.availableQualities = levels; | ||
| } | ||
| } else { | ||
| // 未登录视同普通用户 | ||
| const allowedLevels = AUTHORIZED_QUALITY_LEVELS.NORMAL; | ||
| statusStore.availableQualities = levels.filter((q) => | ||
| (allowedLevels as readonly string[]).includes(q.level), | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
基于 VIP 状态过滤可用音质的逻辑可以被简化,使其更简洁。当前实现存在一些冗余,比如针对 SVIP 用户的 else 分支。重构这部分代码可以提高可读性和可维护性。
const vipType = dataStore.userLoginStatus ? dataStore.userData.vipType || 0 : 0;
if (isSvip(vipType)) {
statusStore.availableQualities = levels;
} else {
const allowedLevels = isVip(vipType)
? AUTHORIZED_QUALITY_LEVELS.VIP
: AUTHORIZED_QUALITY_LEVELS.NORMAL;
statusStore.availableQualities = levels.filter((q) =>
(allowedLevels as readonly string[]).includes(q.level),
);
}
src/core/player/SongManager.ts
Outdated
| if (!(allowedLevels as readonly string[]).includes(level)) { | ||
| console.warn(`⚠️ [${id}] 用户无权播放 ${level},降级至最高可用音质`); | ||
| // 降级策略: 使用允许列表中的最后一个(通常是最高质量) | ||
| level = allowedLevels[allowedLevels.length - 1] as any; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
/gemini review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
这个 PR 主要实现了音质鉴权和多账号管理两大功能,并新增了音乐百科页面。代码整体结构清晰,功能实现完整。
我发现了一些可以改进的地方,主要包括:
- 部分代码存在重复,可以提取为公共函数以提高可维护性。
- 代码中存在一些用于调试的
console.log,在合并前应移除。 - 部分逻辑可以重构得更简洁。
- 一些硬编码的魔法数字可以定义为常量,以提高代码可读性。
具体建议请看下面的评论。
| // 根据 VIP 状态过滤 | ||
| if (dataStore.userLoginStatus) { | ||
| const vipType = dataStore.userData.vipType || 0; | ||
| if (!isSvip(vipType)) { | ||
| const allowedLevels = isVip(vipType) | ||
| ? AUTHORIZED_QUALITY_LEVELS.VIP | ||
| : AUTHORIZED_QUALITY_LEVELS.NORMAL; | ||
| allData = allData.filter((item) => (allowedLevels as readonly string[]).includes(item.level)); | ||
| } | ||
| } else { | ||
| // 未登录 | ||
| allData = allData.filter((item) => (AUTHORIZED_QUALITY_LEVELS.NORMAL as readonly string[]).includes(item.level)); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/components/Card/SongCard.vue
Outdated
| </n-tag> | ||
| <!-- 脏标 --> | ||
| <n-tag | ||
| v-if="settingStore.showSongExplicitTag && (song.mark && (song.mark & 1048576))" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/components/Layout/User.vue
Outdated
|
|
||
| userMenuShow.value = false; | ||
|
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/composables/useQualityControl.ts
Outdated
| console.log("[QualityControl] Levels from API:", levels); | ||
| console.log("[QualityControl] User VIP Type:", dataStore.userData.vipType, "Login Status:", dataStore.userLoginStatus); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // 根据 VIP 类型过滤音质 | ||
| if (dataStore.userLoginStatus) { | ||
| const vipType = dataStore.userData.vipType || 0; | ||
| // SVIP 拥有所有权限,不需要过滤 | ||
| if (!isSvip(vipType)) { | ||
| const allowedLevels = isVip(vipType) | ||
| ? AUTHORIZED_QUALITY_LEVELS.VIP | ||
| : AUTHORIZED_QUALITY_LEVELS.NORMAL; | ||
|
|
||
| statusStore.availableQualities = levels.filter((q) => | ||
| (allowedLevels as readonly string[]).includes(q.level), | ||
| ); | ||
| } else { | ||
| // SVIP | ||
| statusStore.availableQualities = levels; | ||
| } | ||
| } else { | ||
| // 未登录视同普通用户 | ||
| const allowedLevels = AUTHORIZED_QUALITY_LEVELS.NORMAL; | ||
| statusStore.availableQualities = levels.filter((q) => | ||
| (allowedLevels as readonly string[]).includes(q.level), | ||
| ); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
基于 VIP 状态过滤可用音质的逻辑有些嵌套,可以简化以提高可读性。可以先根据用户状态确定 allowedLevels,然后应用一次过滤。
// 根据 VIP 类型过滤音质
const vipType = dataStore.userLoginStatus ? (dataStore.userData.vipType || 0) : 0;
if (isSvip(vipType)) {
statusStore.availableQualities = levels;
} else {
const allowedLevels = isVip(vipType)
? AUTHORIZED_QUALITY_LEVELS.VIP
: AUTHORIZED_QUALITY_LEVELS.NORMAL;
statusStore.availableQualities = levels.filter((q) =>
(allowedLevels as readonly string[]).includes(q.level),
);
}
src/core/player/SongManager.ts
Outdated
|
|
||
| // 如果请求的音质不在允许列表中 | ||
| if (!(allowedLevels as readonly string[]).includes(level)) { | ||
| console.warn(`⚠️ [${id}] 用户无权播放 ${level},降级至最高可用音质`); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/utils/auth.ts
Outdated
|
|
||
| // 校验:如果必须信息缺失,不保存 | ||
| if (!userId || !name || name === "未知用户名") { | ||
| console.warn("User data incomplete, skipping save"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/utils/meta.ts
Outdated
| /** 检查是否为 SVIP */ | ||
| export const isSvip = (vipType: number) => { | ||
| // 11 is standard SVIP code | ||
| if (vipType === VIP_LEVELS.SVIP) return true; | ||
| // Check enriched data from store | ||
| const dataStore = useDataStore(); | ||
| return !!dataStore.userData.isSvip; | ||
| }; | ||
|
|
||
| /** 检查是否为 VIP (包括 SVIP) */ | ||
| export const isVip = (vipType: number) => { | ||
| const vipCodes: number[] = [VIP_LEVELS.VIP, VIP_LEVELS.VIP_ANNUAL]; | ||
| return vipCodes.includes(vipType) || isSvip(vipType); | ||
| }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/views/Song/wiki.vue
Outdated
| <template v-if="Array.isArray(songInfo.artists)"> | ||
| <span v-for="(ar, index) in songInfo.artists" :key="ar.id"> | ||
| <n-text>{{ ar.name }}</n-text> | ||
| <span v-if="Number(index) < songInfo.artists.length - 1"> / </span> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
src/views/Song/wiki.vue
Outdated
| white-space: normal !important; | ||
| overflow: visible !important; | ||
| display: block !important; | ||
| -webkit-line-clamp: unset !important; | ||
| line-clamp: unset !important; | ||
| height: auto !important; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No description provided.