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
|
| // @ts-ignore | ||
| allData = allData.filter((item) => allowedLevels.includes(item.level)); |
| // @ts-ignore | ||
| allData = allData.filter((item) => AUTHORIZED_QUALITY_LEVELS.NORMAL.includes(item.level)); |
| // @ts-ignore | ||
| allData = allData.filter((item) => allowedLevels.includes(item.level)); |
| // @ts-ignore | ||
| allData = allData.filter((item) => AUTHORIZED_QUALITY_LEVELS.NORMAL.includes(item.level)); |
There was a problem hiding this comment.
可以通过对 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)); |
| // @ts-ignore | ||
| options = options.filter((o) => AUTHORIZED_QUALITY_LEVELS.NORMAL.includes(o.value)); |
There was a problem hiding this comment.
应该避免使用 @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)); |
| console.log("[QualityControl] Levels from API:", levels); | ||
| console.log("[QualityControl] User VIP Type:", dataStore.userData.vipType, "Login Status:", dataStore.userLoginStatus); |
| 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.
基于 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),
);
}| if (!(allowedLevels as readonly string[]).includes(level)) { | ||
| console.warn(`⚠️ [${id}] 用户无权播放 ${level},降级至最高可用音质`); | ||
| // 降级策略: 使用允许列表中的最后一个(通常是最高质量) | ||
| level = allowedLevels[allowedLevels.length - 1] as any; |
|
/gemini review |
| // 根据 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)); | ||
| } |
| </n-tag> | ||
| <!-- 脏标 --> | ||
| <n-tag | ||
| v-if="settingStore.showSongExplicitTag && (song.mark && (song.mark & 1048576))" |
|
|
||
| userMenuShow.value = false; | ||
|
|
| console.log("[QualityControl] Levels from API:", levels); | ||
| console.log("[QualityControl] User VIP Type:", dataStore.userData.vipType, "Login Status:", dataStore.userLoginStatus); |
| // 根据 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.
基于 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),
);
}|
|
||
| // 如果请求的音质不在允许列表中 | ||
| if (!(allowedLevels as readonly string[]).includes(level)) { | ||
| console.warn(`⚠️ [${id}] 用户无权播放 ${level},降级至最高可用音质`); |
|
|
||
| // 校验:如果必须信息缺失,不保存 | ||
| if (!userId || !name || name === "未知用户名") { | ||
| console.warn("User data incomplete, skipping save"); |
| /** 检查是否为 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); | ||
| }; |
| <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> |
| white-space: normal !important; | ||
| overflow: visible !important; | ||
| display: block !important; | ||
| -webkit-line-clamp: unset !important; | ||
| line-clamp: unset !important; | ||
| height: auto !important; |
|
/gemini review |
| } catch (error) { | ||
| console.error("Login update failed", error); | ||
| } |
| <KeepAlive v-if="settingStore.useKeepAlive" :max="20" :exclude="['layout']"> | ||
| <component :is="Component" class="router-view" /> | ||
| <component | ||
| :is="Component" | ||
| :key="$route.fullPath + dataStore.userData.userId" | ||
| class="router-view" | ||
| /> | ||
| </KeepAlive> | ||
| <component v-else :is="Component" class="router-view" /> | ||
| <component | ||
| v-else | ||
| :is="Component" | ||
| :key="$route.fullPath + dataStore.userData.userId" | ||
| class="router-view" | ||
| /> |
| const wikiData = wikiRes.status === "fulfilled" ? wikiRes.value.data || wikiRes.value : {}; | ||
| const listenData = | ||
| listenRes.status === "fulfilled" | ||
| ? listenRes.value.data?.data || listenRes.value.data || listenRes.value | ||
| : {}; | ||
| const sheetData = sheetRes.status === "fulfilled" ? sheetRes.value.data || sheetRes.value : {}; |
No description provided.