diff --git a/src/api/album.ts b/src/api/album.ts new file mode 100644 index 0000000..38d6b1c --- /dev/null +++ b/src/api/album.ts @@ -0,0 +1,17 @@ +import { get } from "@/utils/request" +import Source from "@/types/global" + +const AlbumApi = { + /** + * 获取专辑详情 + * @description 传入源平台的专辑 ID,返回专辑内歌曲列表。 + * @param id 专辑 ID + * @param source 音乐来源平台 + * @returns + */ + detail: (id: string, source: Source) => { + return get(`/api/v1/album/detail?id=${id}&source=${source}`) + }, +} + +export default AlbumApi diff --git a/src/api/music.ts b/src/api/music.ts new file mode 100644 index 0000000..85a24f0 --- /dev/null +++ b/src/api/music.ts @@ -0,0 +1,101 @@ +import { get } from "@/utils/request" +import Source from "@/types/global" + +/** 音乐直链 */ +export interface MusicUrl { + url: string +} + +const MusicApi = { + /** + * 代理请求并下载封面图 + * @description 发送带伪造标头的请求拉取远端封面大图,避开网易云、QQ 音乐的图片防盗链 403 问题。 + * @param url 封面图原始 URL (需经过 urlencode) + * @param name 歌曲名(用于生成下载文件名) + * @param artist 歌手名(用于生成下载文件名) + * @returns + */ + cover: (url: string, name?: string, artist?: string) => { + return get(`/api/v1/music/cover?url=${url}&name=${name}&artist=${artist}`) + }, + /** + * 探测音频大小与码率 + * @description 快速探测音频直链的可访问性,并根据 Content-Range 推算文件大小及大概码率。 + * @param id 音乐 ID + * @param source 音乐来源平台 + * @param duration 音乐时长(秒),提供可精确预估码率(kbps) + */ + inspect: (id: string, source: Source, duration?: string) => { + return get(`/api/v1/music/inspect?id=${id}&source=${source}&duration=${duration}`) + }, + /** + * 获取 JSON 格式歌词 + * @description 抓取对应歌曲的完整 LRC 歌词文本,以 JSON 格式返回。 + * @param id 音乐 ID + * @param source 音乐来源平台 + * @returns + */ + lyric: (id: string, source: Source) => { + return get(`/api/v1/music/lyric?id=${id}&source=${source}`) + }, + /** + * 下载 LRC 歌词文件 + * @description 作为附件直接下载 .lrc 后缀的歌词文件到本地。 + * @param id 音乐 ID + * @param source 音乐来源平台 + * @param name 音乐名称 (生成保存文件名) + * @param artist 歌手名称 (生成保存文件名) + * @returns + */ + lyricFile: (id: string, source: Source, name?: string, artist?: string) => { + return get(`/api/v1/music/lyric/file?id=${id}&source=${source}&name=${name}&artist=${artist}`) + }, + /** + * 综合搜索与链接解析 + * @description 兼容多源并发搜索以及链接智能解析,自动返回单曲、歌单或专辑数组。支持直接输入关键词或粘贴音乐平台的分享链接。 + * @param keyword 关键词 + * @param type 搜索类型: song (单曲)、playlist (歌单) 或 album (专辑) + * @param sources 来源列表 + * @returns + */ + search: (keyword: string, type: string, sources?: Source[]) => { + return get(`/api/v1/music/search?q=${keyword}&type=${type}&sources=${sources}`) + }, + /** + * 串流代理与下载音频 + * @description 包含完整的各平台流代理逻辑(解决跨域防盗链),并特殊支持 Soda(汽水音乐) 加密流数据的后端解密。 + * @param id 音乐 ID + * @param source 音乐来源平台 + * @param name 音乐名称 (生成保存文件名) + * @param artist 歌手名称 (生成保存文件名) + * @returns + */ + stream: (id: string, source: Source, name?: string, artist?: string) => { + return get(`/api/v1/music/stream?id=${id}&source=${source}&name=${name}&artist=${artist}`) + }, + /** + * 智能切换可用的平替音源 + * @description 当某一平台的歌曲灰掉(无版权)时,智能寻源切换到其他存在该歌曲的可用平台。 + * @param name 歌曲名称 + * @param source 当前损坏的音源(将跳过此源搜索) + * @param artist 歌手名称 + * @param target 指定目标尝试的音源,为空则遍历主流平台搜索 + * @param duration 原音频时长(秒),提供此时长可极大提高匹配准确度 + * @returns + */ + switch: (name: string, source: Source, artist?: string, target?: string, duration?: string) => { + return get(`/api/v1/music/switch?name=${name}&source=${source}&artist=${artist}&target=${target}&duration=${duration}`) + }, + /** + * 获取音频裸直链 + * @description 获取解析到的原始音频播放链接。注:部分平台需要客户端带上特定的防盗链 header。 + * @param id 音乐 ID + * @param source 音乐来源平台 + * @returns + */ + url: (id: string, source: Source) => { + return get(`/api/v1/music/url?id=${id}&source=${source}`) + }, +} + +export default MusicApi diff --git a/src/api/playlist.ts b/src/api/playlist.ts index 73ec53b..0ad5f25 100644 --- a/src/api/playlist.ts +++ b/src/api/playlist.ts @@ -1,6 +1,7 @@ -import { get } from "@/utils/request"; -import Source from "@/types/global"; +import { get } from "@/utils/request" +import Source from "@/types/global" +/** 歌单分类 */ interface PlayListCategory { id: string name: string @@ -9,6 +10,7 @@ interface PlayListCategory { count: number } +/** 分类歌单接口返回的数据结构 */ interface PlayListCategoryRes { source: string name: string @@ -81,39 +83,57 @@ interface PlayListSong { } /** 歌单摘要缓存:详情页通过它读取歌单标题、封面等元信息 */ -const playListSummaryCache = new Map(); +const playListSummaryCache = new Map() export function cachePlayListSummary(summary: PlayListSummary) { - playListSummaryCache.set(summary.id, summary); + playListSummaryCache.set(summary.id, summary) } export function getCachedPlayListSummary(id: string): PlayListSummary | undefined { - return playListSummaryCache.get(id); + return playListSummaryCache.get(id) } const PlayListApi = { - // 获取歌单分类 - getCategoryList: (sources?: Source[]) => { - return get(`/api/v1/playlist/categories?sources=${sources}`); + /** + * 获取歌单分类 + * @param sources 音乐来源平台列表 + * @returns + */ + categoryList: (sources?: Source[]) => { + return get(`/api/v1/playlist/categories?sources=${sources}`) }, - // 获取分类歌单 - getCategoryPlayList: ( - categoryId: string, - source?: Source, - page?: number, - limit?: number, - ) => { - return get( - `/api/v1/playlist/category?source=${source}&category_id=${categoryId}&page=${page}&limit=${limit}`, - ); + /** + * 获取分类歌单 + * @description 按平台和分类 ID 分页获取歌单。 + * @param categoryId 分类 ID + * @param source 音乐来源平台 + * @param page 页码 + * @param limit 每页数量 + * @returns + */ + categoryPlayList: (categoryId: string, source?: Source, page?: number, limit?: number) => { + return get(`/api/v1/playlist/category?source=${source}&category_id=${categoryId}&page=${page}&limit=${limit}`) }, - // 获取歌单详情 - getPlayListDetail: (source: Source, id: string) => { - return get( - `/api/v1/playlist/detail?source=${source}&id=${id}`, - ); + /** + * 获取歌单详情 + * @param source 歌单所属平台 + * @param id 歌单的内部 ID + * @returns + */ + detail: (source: Source, id: string) => { + return get(`/api/v1/playlist/detail?source=${source}&id=${id}`) }, -}; -export default PlayListApi; + /** + * 获取每日推荐热门歌单 + * @description 异步并发调用所勾选平台的接口,聚合返回他们各自首页推荐的当红歌单数据。 + * @param sources 要获取的推荐平台列表 (留空则使用默认配置) + * @returns + */ + recommend: (sources?: Source[]) => { + return get(`/api/v1/playlist/recommend?sources=${sources}`) + }, +} + +export default PlayListApi export type { PlayListCategory, PlayListCategoryRes, PlayListSummary, CategoryPlayListRes, PlayListSong } diff --git a/src/api/system.ts b/src/api/system.ts new file mode 100644 index 0000000..bd40855 --- /dev/null +++ b/src/api/system.ts @@ -0,0 +1,49 @@ +import { get, post } from "@/utils/request" +import Source from "@/types/global" + +const SystemApi = { + /** + * 获取当前系统加载的 Cookies + * @description 读取并在 JSON 格式下返回当前系统已配置的各平台 Cookies。 + * @returns + */ + cookies: () => { + return get(`/api/v1/system/cookies`) + }, + /** + * 设置系统 Cookies + * @description 接收 JSON 格式的平台 cookie 键值对,覆盖并保存到系统,实时生效。 + * @returns + */ + setCookies: (data: Record) => { + return post(`/api/v1/system/cookies`, data) + }, + /** + * 获取支持扫码登录的平台 + * @description 返回当前 API 支持创建二维码登录会话的平台列表。 + * @returns + */ + qrLoginSource: () => { + return get(`/api/v1/system/qr_login/sources`) + }, + /** + * 轮询扫码登录状态 + * @description 使用创建扫码登录会话返回的 key 轮询登录状态;成功时自动写入 cookies.json。 + * @param source 扫码登录平台 + * @returns + */ + loginStatus: (source: Source) => { + return get(`/api/v1/system/qr_login/${source}`) + }, + /** + * 创建扫码登录会话 + * @description 为指定平台创建扫码登录会话,返回二维码 URL、二维码图片地址或平台登录 key。 + * @param source 扫码登录平台 + * @returns + */ + qrLogin: (source: Source) => { + return post(`/api/v1/system/qr_login/${source}`) + }, +} + +export default SystemApi diff --git a/src/components/PlayerBar.vue b/src/components/PlayerBar.vue index c036378..bec5318 100644 --- a/src/components/PlayerBar.vue +++ b/src/components/PlayerBar.vue @@ -1,5 +1,13 @@