Skip to content

Commit

Permalink
fix: use linolabs/qq-music-api for music searching
Browse files Browse the repository at this point in the history
Signed-off-by: ZTL-UwU <zhangtianli2006@163.com>
  • Loading branch information
ZTL-UwU committed Sep 8, 2024
1 parent 7ad8f70 commit 4e72116
Show file tree
Hide file tree
Showing 8 changed files with 180 additions and 15 deletions.
4 changes: 2 additions & 2 deletions components/MusicPlayerCard.vue
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ onMounted(() => {
<div class="space-y-1 w-full">
<UiCardTitle>
<span :class="`${compact ? 'text-lg' : ''}`">
{{ song.title }}
{{ song.name }}
</span>
<div class="float-right">
<UiTooltipProvider v-if="isError">
Expand All @@ -78,7 +78,7 @@ onMounted(() => {
</div>
</UiCardTitle>
<UiCardDescription>
{{ song.author }}
{{ song.singer }}
<audio ref="audio" />
<div class="flex align-middle">
<UiButton variant="ghost" size="icon" class="h-8 ml-[-8px] mr-1 text-slate-950" @click="playing = !playing">
Expand Down
19 changes: 6 additions & 13 deletions pages/manage/review.vue
Original file line number Diff line number Diff line change
Expand Up @@ -60,22 +60,15 @@ async function getSearchList(song?: TSong) {
if (mapVal)
return mapVal;
const formData = new FormData();
formData.append('input', name);
formData.append('filter', 'name');
formData.append('type', 'netease');
const res: any = (await useFetch('/liuzhijin', {
method: 'post',
body: formData,
headers: {
'X-Requested-With': 'XMLHttpRequest',
const res: any = (await useFetch('/api/search/song', {
method: 'get',
params: {
key: name,
},
mode: 'cors',
})).data;
}));
// Store cache
const data = JSON.parse(res.value).data;
const data = res.data.value;
searchListCache.value.set(name, data);
return data;
};
Expand Down
48 changes: 48 additions & 0 deletions server/api/search/song.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { getMusicURL } from '~/server/lib/song';
import type { TSearchResponse } from '~~/types';
import { searchSchema } from '~~/types';

export default eventHandler(async (event) => {
const paramsParse = await getValidatedQuery(event, params => searchSchema.safeParse(params));
if (!paramsParse.success)
throw createError({ message: 'Invalid params', status: 400 });

const searchBaseURL = 'https://c6.y.qq.com/splcloud/fcgi-bin/smartbox_new.fcg';

const res = await $fetch<TSearchResponse>(searchBaseURL, {
method: 'GET',
params: {
_: Date.now(),
cv: '4747474',
ct: '24',
format: 'json',
inCharset: 'utf-8',
outCharset: 'utf-8',
notice: '0',
platform: 'yqq.json',
needNewCode: '1',
uin: '0',
g_tk_new_20200303: '5381',
g_tk: '5381',
hostUin: '0',
is_xml: '0',
key: paramsParse.data.key,
},
parseResponse(responseText) {
try {
return JSON.parse(responseText);
} catch {
return responseText;
}
},
});
const songMidArray = res.data.song.itemlist.map(item => item.mid);
const urls = await getMusicURL(songMidArray);
const songList = res.data.song.itemlist.map(item => ({
mid: item.mid,
name: item.name,
singer: item.singer,
url: urls[item.mid],
}));
return songList;
});
9 changes: 9 additions & 0 deletions server/api/stream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { getMusicURL } from '~/server/lib/song';
import { streamSchema } from '~~/types/stream';

export default eventHandler(async (event) => {
const paramsParse = await getValidatedQuery(event, params => streamSchema.safeParse(params));
if (!paramsParse.success)
throw createError({ message: 'Invalid params', status: 400 });
return await getMusicURL([paramsParse.data.songMid]);
});
60 changes: 60 additions & 0 deletions server/lib/song.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import type { TStreamResponse } from '~~/types/stream';

export async function getMusicURL(midArray: string[]) {
const musicBaseURL = 'https://u6.y.qq.com/cgi-bin/musicu.fcg';
const guid = Math.round(2147483647 * Math.random()) * Date.now() % 1e10;
const res = await $fetch<TStreamResponse>(musicBaseURL, {
method: 'POST',
params: {
_: Date.now(),
},
body: `
{
"comm": {
"cv": 4747474,
"ct": 24,
"format": "json",
"inCharset": "utf-8",
"outCharset": "utf-8",
"notice": 0,
"platform": "yqq.json",
"needNewCode": 1,
"uin": 0,
"g_tk_new_20200303": 5381,
"g_tk": 5381
},
"req_1": {
"module": "vkey.GetVkeyServer",
"method": "CgiGetVkey",
"param": {
"guid": "${guid}",
"songmid": ${JSON.stringify(midArray)},
"songtype": [
0
],
"uin": "0",
"loginflag": 1,
"platform": "20"
}
}
}
`,
parseResponse(responseText) {
try {
return JSON.parse(responseText);
} catch {
return responseText;
}
},
});
const data: Record<string, string> = {};
if (res.code !== 0 || res.req_1.code !== 0)
throw createError({ message: 'Failed to get music URL', status: 500 });
for (const item of res.req_1.data.midurlinfo) {
if (!item.purl)
data[item.songmid] = '';
else
data[item.songmid] = `https://ws.stream.qqmusic.qq.com/${item.purl}`;
}
return data;
}
2 changes: 2 additions & 0 deletions types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,5 @@ export type TTime = RouterOutput['time']['content'];
export type TTimeList = RouterOutput['time']['list'];

export type TStatus = 'unset' | 'approved' | 'rejected' | 'used';

export * from './search';
33 changes: 33 additions & 0 deletions types/search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { z } from 'zod';

export const searchSchema = z.object({
key: z.string(),
});

export interface TItem {
docid: string;
id: string;
mid: string;
name: string;
singer: string;
pic?: string;
}

export interface TSearchDataItem {
count: number;
itemlist: TItem[];
name: string;
order: number;
type: number;
}

export interface TSearchResponse {
code: number;
data: {
album: TSearchDataItem;
mv: TSearchDataItem;
singer: TSearchDataItem;
song: TSearchDataItem;
};
subcode: number;
}
20 changes: 20 additions & 0 deletions types/stream.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { z } from 'zod';

export const streamSchema = z.object({
songMid: z.string(),
});
export interface TMidUrlInfoItem {
filename: string;
purl: string;
songmid: string;
vkey: string;
}
export interface TStreamResponse {
code: number;
req_1: {
code: number;
data: {
midurlinfo: TMidUrlInfoItem[];
};
};
}

0 comments on commit 4e72116

Please sign in to comment.