mirror of
https://github.com/GiriNeko/YesPlayMusic.git
synced 2025-12-17 05:38:04 +00:00
feat: updates
This commit is contained in:
parent
196a974a64
commit
8f4c3d8e5b
24 changed files with 572 additions and 93 deletions
84
packages/electron/main/appleMusic.ts
Normal file
84
packages/electron/main/appleMusic.ts
Normal file
|
|
@ -0,0 +1,84 @@
|
|||
import { logger } from '@sentry/utils'
|
||||
import axios from 'axios'
|
||||
|
||||
// 'https://mvod.itunes.apple.com/itunes-assets/HLSMusic116/v4/de/52/95/de52957b-fcf1-ae96-b114-0445cb8c41d4/P359420813_default.m3u8'
|
||||
|
||||
const searchAlbum = async (
|
||||
keyword: string
|
||||
): Promise<
|
||||
| {
|
||||
id: string
|
||||
href: string
|
||||
attributes: {
|
||||
artistName: string
|
||||
url: string
|
||||
name: string
|
||||
editorialNotes?: {
|
||||
standard: string
|
||||
short: string
|
||||
}
|
||||
}
|
||||
}
|
||||
| undefined
|
||||
> => {
|
||||
const r = await axios.get(
|
||||
`https://amp-api.music.apple.com/v1/catalog/cn/search`,
|
||||
{
|
||||
params: {
|
||||
term: keyword,
|
||||
l: 'zh-cn',
|
||||
platform: 'web',
|
||||
types: 'albums',
|
||||
limit: 1,
|
||||
},
|
||||
headers: {
|
||||
authorization: 'Bearer xxxxxx', // required token
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
return r.data?.results?.albums?.data?.[0]
|
||||
}
|
||||
|
||||
export const getCoverVideo = async ({
|
||||
name,
|
||||
artists,
|
||||
}: {
|
||||
name: string
|
||||
artists: string[]
|
||||
}): Promise<string | undefined> => {
|
||||
const keyword = `${artists.join(' ')} ${name}`
|
||||
logger.debug(`[appleMusic] getCoverVideo: ${keyword}`)
|
||||
const album = await searchAlbum(keyword).catch(e => {
|
||||
console.log(e)
|
||||
logger.debug('[appleMusic] Search album error', e)
|
||||
})
|
||||
|
||||
const url = album?.attributes.url
|
||||
|
||||
if (!url) {
|
||||
logger.info('[appleMusic] no url')
|
||||
return
|
||||
}
|
||||
|
||||
let { data: html } = await axios.get(url)
|
||||
if (!html) return
|
||||
|
||||
const regex =
|
||||
/<script type="fastboot\/shoebox" id="shoebox-media-api-cache-amp-music">(.*?)<\/script>/
|
||||
html = html
|
||||
.match(regex)[0]
|
||||
.replace(
|
||||
'<script type="fastboot/shoebox" id="shoebox-media-api-cache-amp-music">',
|
||||
''
|
||||
)
|
||||
.replace('</script>', '')
|
||||
html = JSON.parse(html)
|
||||
const data = JSON.parse(html[Object.keys(html)[1]])
|
||||
const m3u8 =
|
||||
data?.d?.[0]?.attributes?.editorialVideo?.motionSquareVideo1x1?.video
|
||||
|
||||
logger.debug(`[appleMusic] ${m3u8}`)
|
||||
|
||||
return m3u8
|
||||
}
|
||||
|
|
@ -31,8 +31,9 @@ class Cache {
|
|||
break
|
||||
}
|
||||
case APIs.Track: {
|
||||
if (!data.songs) return
|
||||
const tracks = (data as FetchTracksResponse).songs.map(t => ({
|
||||
const res = data as FetchTracksResponse
|
||||
if (!res.songs) return
|
||||
const tracks = res.songs.map(t => ({
|
||||
id: t.id,
|
||||
json: JSON.stringify(t),
|
||||
updatedAt: Date.now(),
|
||||
|
|
@ -106,6 +107,16 @@ class Cache {
|
|||
db.upsert(Tables.CoverColor, {
|
||||
id: data.id,
|
||||
color: data.color,
|
||||
queriedAt: Date.now(),
|
||||
})
|
||||
break
|
||||
}
|
||||
case APIs.VideoCover: {
|
||||
if (!data.id) return
|
||||
db.upsert(Tables.VideoCover, {
|
||||
id: data.id,
|
||||
url: data.url || 'no',
|
||||
queriedAt: Date.now(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -196,6 +207,10 @@ class Cache {
|
|||
if (isNaN(Number(params?.id))) return
|
||||
return db.find(Tables.CoverColor, params.id)?.color
|
||||
}
|
||||
case APIs.VideoCover: {
|
||||
if (isNaN(Number(params?.id))) return
|
||||
return db.find(Tables.VideoCover, params.id)?.url
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -278,7 +293,7 @@ class Cache {
|
|||
br,
|
||||
type: type as TablesStructures[Tables.Audio]['type'],
|
||||
source,
|
||||
updatedAt: Date.now(),
|
||||
queriedAt: Date.now(),
|
||||
})
|
||||
|
||||
log.info(`[cache] cacheAudio ${id}-${br}.${type}`)
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ export const enum Tables {
|
|||
AccountData = 'AccountData',
|
||||
CoverColor = 'CoverColor',
|
||||
AppData = 'AppData',
|
||||
VideoCover = 'VideoCover',
|
||||
}
|
||||
interface CommonTableStructure {
|
||||
id: number
|
||||
|
|
@ -50,16 +51,22 @@ export interface TablesStructures {
|
|||
| 'qq'
|
||||
| 'bilibili'
|
||||
| 'joox'
|
||||
updatedAt: number
|
||||
queriedAt: number
|
||||
}
|
||||
[Tables.CoverColor]: {
|
||||
id: number
|
||||
color: string
|
||||
queriedAt: number
|
||||
}
|
||||
[Tables.AppData]: {
|
||||
id: 'appVersion' | 'skippedVersion'
|
||||
value: string
|
||||
}
|
||||
[Tables.VideoCover]: {
|
||||
id: number
|
||||
url: string
|
||||
queriedAt: number
|
||||
}
|
||||
}
|
||||
|
||||
type TableNames = keyof TablesStructures
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { Thumbar } from './windowsTaskbar'
|
|||
import fastFolderSize from 'fast-folder-size'
|
||||
import path from 'path'
|
||||
import prettyBytes from 'pretty-bytes'
|
||||
import { getCoverVideo } from './appleMusic'
|
||||
|
||||
const on = <T extends keyof IpcChannelsParams>(
|
||||
channel: T,
|
||||
|
|
@ -20,6 +21,16 @@ const on = <T extends keyof IpcChannelsParams>(
|
|||
ipcMain.on(channel, listener)
|
||||
}
|
||||
|
||||
const handle = <T extends keyof IpcChannelsParams>(
|
||||
channel: T,
|
||||
listener: (
|
||||
event: Electron.IpcMainInvokeEvent,
|
||||
params: IpcChannelsParams[T]
|
||||
) => void
|
||||
) => {
|
||||
return ipcMain.handle(channel, listener)
|
||||
}
|
||||
|
||||
export function initIpcMain(
|
||||
win: BrowserWindow | null,
|
||||
tray: YPMTray | null,
|
||||
|
|
@ -143,6 +154,22 @@ function initOtherIpcMain() {
|
|||
)
|
||||
})
|
||||
|
||||
/**
|
||||
* 缓存动态专辑封面
|
||||
*/
|
||||
on(IpcChannels.SetVideoCover, (event, args) => {
|
||||
const { id, url } = args
|
||||
cache.set(APIs.VideoCover, { id, url })
|
||||
})
|
||||
|
||||
/**
|
||||
* 获取动态专辑封面
|
||||
*/
|
||||
on(IpcChannels.GetVideoCover, (event, args) => {
|
||||
const { id } = args
|
||||
event.returnValue = cache.get(APIs.VideoCover, { id })
|
||||
})
|
||||
|
||||
/**
|
||||
* 导出tables到json文件,方便查看table大小(dev环境)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ contextBridge.exposeInMainWorld('log', log)
|
|||
|
||||
contextBridge.exposeInMainWorld('ipcRenderer', {
|
||||
sendSync: ipcRenderer.sendSync,
|
||||
invoke: ipcRenderer.invoke,
|
||||
send: ipcRenderer.send,
|
||||
on: (
|
||||
channel: IpcChannels,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue