Skip to content

Commit

Permalink
feat: web方式支持下载到服务器中
Browse files Browse the repository at this point in the history
  • Loading branch information
zonemeen committed Jan 3, 2024
1 parent e90ef60 commit 7791937
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 34 deletions.
4 changes: 2 additions & 2 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@ import type { SongInfo } from './types'

!(async () => {
const {
options: { qrcode, port, open },
options: { qrcode, port, open, path },
} = command
if (qrcode) {
return await qrcodeGenerator({ port, open })
return await qrcodeGenerator({ port, open, path })
}
const result = await searchMusic(<SongInfo>command)
const { songs = [] } = await choose(<SongInfo>result)
Expand Down
97 changes: 73 additions & 24 deletions src/qrcode/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { fileURLToPath } from 'node:url'
import { resolve, dirname } from 'node:path'
import { resolve, dirname, join } from 'node:path'
import { pipeline } from 'node:stream/promises'
import { existsSync, mkdirSync, createWriteStream } from 'node:fs'
import got from 'got'
import portfinder from 'portfinder'
import qrcode from 'qrcode-terminal'
Expand All @@ -8,7 +10,19 @@ import express, { NextFunction, Request, Response } from 'express'
import search from '../services/search'
import lyric from '../services/lyric'
import { getNetworkAddress } from '../utils'
import type { ServiceType, SearchProps, SearchSongInfo } from '../types'
import type { ServiceType } from '../types'

interface DownloadRequestType {
url: string
songName: string
}

interface SearchRequestType {
service: ServiceType
text: string
pageNum: string
pageSize: string
}

const __dirname = dirname(fileURLToPath(import.meta.url))

Expand All @@ -22,7 +36,15 @@ const config = {
},
}

export default async ({ port, open: isOpen }: { port: string; open: boolean }) => {
export default async ({
port,
open: isOpen,
path,
}: {
port: string
open: boolean
path: string
}) => {
const app = express()

app.use(
Expand All @@ -42,28 +64,55 @@ export default async ({ port, open: isOpen }: { port: string; open: boolean }) =
isOpen && open(address)
}

app.get('/search', async (req: Request, res: Response) => {
const { service, text, pageNum, pageSize = 20 } = req.query
const { searchSongs, totalSongCount } = await search[service as ServiceType]({
text,
pageNum,
pageSize,
} as SearchProps)
const lyricList = (await Promise.allSettled(
searchSongs.map(({ lyricUrl }: SearchSongInfo) =>
lyric[service as ServiceType](null, lyricUrl!)
)
)) as { value: string | undefined }[]
searchSongs.forEach((song: SearchSongInfo, index: number) => {
song.lrc = lyricList[index].value ?? '[00:00.00]无歌词'
})
res.send({ searchSongs, totalSongCount })
})
app.get(
'/search',
async (
req: Request<
Record<string, unknown>,
Record<string, unknown>,
Record<string, unknown>,
SearchRequestType
>,
res: Response
) => {
const { service, text, pageNum, pageSize = '20' } = req.query
const { searchSongs, totalSongCount } = await search[service]({
text,
pageNum,
pageSize,
})
const lyricList = (await Promise.allSettled(
searchSongs.map(({ lyricUrl }) => lyric[service](null, lyricUrl!))

Check warning on line 85 in src/qrcode/index.ts

View workflow job for this annotation

GitHub Actions / lint

Forbidden non-null assertion
)) as { value: string | undefined }[]
searchSongs.forEach((song, index) => {
song.lrc = lyricList[index].value ?? '[00:00.00]无歌词'
})
res.send({ searchSongs, totalSongCount })
}
)

app.get('/download', (req: Request, res: Response) => {
const { url } = req.query
got.stream(url as string).pipe(res)
})
app.get(
'/download',
async (
req: Request<
Record<string, unknown>,
Record<string, unknown>,
Record<string, unknown>,
DownloadRequestType
>,
res: Response
) => {
const { url, songName } = req.query
if (path) {
if (!existsSync(path)) mkdirSync(path)
const songPath = join(path, songName)
await pipeline(got.stream(url), createWriteStream(songPath))
res.send({ download: 'success' })
} else {
got.stream(url).pipe(res)
}
}
)

app.use((err: Error, req: Request, res: Response, next: NextFunction) => {

Check warning on line 117 in src/qrcode/index.ts

View workflow job for this annotation

GitHub Actions / lint

'next' is defined but never used
res.status(res.statusCode || 500)
Expand Down
18 changes: 10 additions & 8 deletions template/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width,initial-scale=1.0" />
<title>Music Player</title>
<link rel="icon" type="image/svg+xml" href="/music.svg">
<link rel="icon" type="image/png" href="/music.png">
<link rel="icon" type="image/svg+xml" href="/music.svg" />
<link rel="icon" type="image/png" href="/music.png" />
<link
href="https://cdn.bootcdn.net/ajax/libs/ant-design-vue/1.7.7/antd.min.css"
rel="stylesheet"
Expand Down Expand Up @@ -174,16 +174,18 @@
async onDownload({ id, url, songName }) {
try {
this.downloadLoadingList.push(id)
const response = await fetch(`/download?url=${url}`, {
const response = await fetch(`/download?url=${url}&songName=${songName}`, {
method: 'GET',
signal: this.controller.signal,
})
const blob = await response.blob()
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = songName
link.click()
URL.revokeObjectURL(link.href)
if (blob.type !== 'application/json') {
const link = document.createElement('a')
link.href = URL.createObjectURL(blob)
link.download = songName
link.click()
URL.revokeObjectURL(link.href)
}
} catch (error) {
console.error('下载音乐文件时出错:', error)
} finally {
Expand Down

0 comments on commit 7791937

Please sign in to comment.