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
a1b0bcf4d3
commit
884f3df41a
198 changed files with 4572 additions and 5336 deletions
65
packages/server/.gitignore
vendored
Normal file
65
packages/server/.gitignore
vendored
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
# Logs
|
||||
logs
|
||||
*.log
|
||||
npm-debug.log*
|
||||
|
||||
# Runtime data
|
||||
pids
|
||||
*.pid
|
||||
*.seed
|
||||
|
||||
# Directory for instrumented libs generated by jscoverage/JSCover
|
||||
lib-cov
|
||||
|
||||
# Coverage directory used by tools like istanbul
|
||||
coverage
|
||||
|
||||
# nyc test coverage
|
||||
.nyc_output
|
||||
|
||||
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
|
||||
.grunt
|
||||
|
||||
# node-waf configuration
|
||||
.lock-wscript
|
||||
|
||||
# Compiled binary addons (http://nodejs.org/api/addons.html)
|
||||
build/Release
|
||||
|
||||
# Dependency directories
|
||||
node_modules
|
||||
jspm_packages
|
||||
|
||||
# Optional npm cache directory
|
||||
.npm
|
||||
|
||||
# Optional REPL history
|
||||
.node_repl_history
|
||||
|
||||
# 0x
|
||||
profile-*
|
||||
|
||||
# mac files
|
||||
.DS_Store
|
||||
|
||||
# vim swap files
|
||||
*.swp
|
||||
|
||||
# webstorm
|
||||
.idea
|
||||
|
||||
# vscode
|
||||
.vscode
|
||||
*code-workspace
|
||||
|
||||
# clinic
|
||||
profile*
|
||||
*clinic*
|
||||
*flamegraph*
|
||||
|
||||
# generated code
|
||||
examples/typescript-server.js
|
||||
test/types/index.js
|
||||
|
||||
# compiled app
|
||||
dist
|
||||
4
packages/server/.taprc
Normal file
4
packages/server/.taprc
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
test-env: [
|
||||
TS_NODE_FILES=true,
|
||||
TS_NODE_PROJECT=./test/tsconfig.json
|
||||
]
|
||||
23
packages/server/README.md
Normal file
23
packages/server/README.md
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
# Getting Started with [Fastify-CLI](https://www.npmjs.com/package/fastify-cli)
|
||||
This project was bootstrapped with Fastify-CLI.
|
||||
|
||||
## Available Scripts
|
||||
|
||||
In the project directory, you can run:
|
||||
|
||||
### `npm run dev`
|
||||
|
||||
To start the app in dev mode.\
|
||||
Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
|
||||
|
||||
### `npm start`
|
||||
|
||||
For production mode
|
||||
|
||||
### `npm run test`
|
||||
|
||||
Run the test cases.
|
||||
|
||||
## Learn More
|
||||
|
||||
To learn Fastify, check out the [Fastify documentation](https://www.fastify.io/docs/latest/).
|
||||
41
packages/server/fly.toml
Normal file
41
packages/server/fly.toml
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
# fly.toml file generated for ypm on 2022-09-06T00:57:21+08:00
|
||||
|
||||
app = "ypm"
|
||||
kill_signal = "SIGINT"
|
||||
kill_timeout = 5
|
||||
processes = ["npm run start"]
|
||||
|
||||
[build]
|
||||
builder = "heroku/buildpacks:20"
|
||||
|
||||
[env]
|
||||
PORT = "8080"
|
||||
|
||||
[experimental]
|
||||
allowed_public_ports = []
|
||||
auto_rollback = true
|
||||
|
||||
[[services]]
|
||||
http_checks = []
|
||||
internal_port = 35530
|
||||
processes = ["app"]
|
||||
protocol = "tcp"
|
||||
script_checks = []
|
||||
[services.concurrency]
|
||||
hard_limit = 25
|
||||
soft_limit = 20
|
||||
type = "connections"
|
||||
|
||||
[[services.ports]]
|
||||
handlers = ["http"]
|
||||
port = 80
|
||||
|
||||
[[services.ports]]
|
||||
handlers = ["tls", "http"]
|
||||
port = 443
|
||||
|
||||
[[services.tcp_checks]]
|
||||
grace_period = "1s"
|
||||
interval = "15s"
|
||||
restart_limit = 0
|
||||
timeout = "2s"
|
||||
37
packages/server/package.json
Normal file
37
packages/server/package.json
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"name": "server",
|
||||
"version": "1.0.0",
|
||||
"description": "This project was bootstrapped with Fastify-CLI.",
|
||||
"main": "app.ts",
|
||||
"directories": {
|
||||
"test": "test"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "npm run build:ts && tsc -p test/tsconfig.json && tap --ts \"test/**/*.test.ts\"",
|
||||
"start": "fastify start --port 35530 --address 0.0.0.0 -l info dist/app.js",
|
||||
"build:ts": "tsc",
|
||||
"watch:ts": "tsc -w",
|
||||
"dev": "npm run build:ts && concurrently -k -p \"[{name}]\" -n \"TypeScript,App\" -c \"yellow.bold,cyan.bold\" \"npm:watch:ts\" \"npm:dev:start\"",
|
||||
"dev:start": "fastify start --ignore-watch=.ts$ -w --port 35530 --address 0.0.0.0 -l info -P dist/app.js"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@fastify/autoload": "^5.0.0",
|
||||
"@fastify/sensible": "^4.1.0",
|
||||
"axios": "^0.27.2",
|
||||
"fastify": "^4.0.0",
|
||||
"fastify-cli": "^4.4.0",
|
||||
"fastify-plugin": "^3.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^18.0.0",
|
||||
"@types/tap": "^15.0.5",
|
||||
"concurrently": "^7.0.0",
|
||||
"fastify-tsconfig": "^1.0.1",
|
||||
"tap": "^16.1.0",
|
||||
"ts-node": "^10.4.0",
|
||||
"typescript": "^4.5.4"
|
||||
}
|
||||
}
|
||||
35
packages/server/src/app.ts
Normal file
35
packages/server/src/app.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
import { join } from 'path';
|
||||
import AutoLoad, {AutoloadPluginOptions} from '@fastify/autoload';
|
||||
import { FastifyPluginAsync } from 'fastify';
|
||||
|
||||
export type AppOptions = {
|
||||
// Place your custom options for app below here.
|
||||
} & Partial<AutoloadPluginOptions>;
|
||||
|
||||
const app: FastifyPluginAsync<AppOptions> = async (
|
||||
fastify,
|
||||
opts
|
||||
): Promise<void> => {
|
||||
// Place here your custom code!
|
||||
|
||||
// Do not touch the following lines
|
||||
|
||||
// This loads all plugins defined in plugins
|
||||
// those should be support plugins that are reused
|
||||
// through your application
|
||||
void fastify.register(AutoLoad, {
|
||||
dir: join(__dirname, 'plugins'),
|
||||
options: opts
|
||||
})
|
||||
|
||||
// This loads all plugins defined in routes
|
||||
// define your routes in one of these
|
||||
void fastify.register(AutoLoad, {
|
||||
dir: join(__dirname, 'routes'),
|
||||
options: opts
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
export default app;
|
||||
export { app }
|
||||
16
packages/server/src/plugins/README.md
Normal file
16
packages/server/src/plugins/README.md
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
# Plugins Folder
|
||||
|
||||
Plugins define behavior that is common to all the routes in your
|
||||
application. Authentication, caching, templates, and all the other cross
|
||||
cutting concerns should be handled by plugins placed in this folder.
|
||||
|
||||
Files in this folder are typically defined through the
|
||||
[`fastify-plugin`](https://github.com/fastify/fastify-plugin) module,
|
||||
making them non-encapsulated. They can define decorators and set hooks
|
||||
that will then be used in the rest of your application.
|
||||
|
||||
Check out:
|
||||
|
||||
* [The hitchhiker's guide to plugins](https://www.fastify.io/docs/latest/Guides/Plugins-Guide/)
|
||||
* [Fastify decorators](https://www.fastify.io/docs/latest/Reference/Decorators/).
|
||||
* [Fastify lifecycle](https://www.fastify.io/docs/latest/Reference/Lifecycle/).
|
||||
13
packages/server/src/plugins/sensible.ts
Normal file
13
packages/server/src/plugins/sensible.ts
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
import fp from 'fastify-plugin'
|
||||
import sensible, { SensibleOptions } from '@fastify/sensible'
|
||||
|
||||
/**
|
||||
* This plugins adds some utilities to handle http errors
|
||||
*
|
||||
* @see https://github.com/fastify/fastify-sensible
|
||||
*/
|
||||
export default fp<SensibleOptions>(async (fastify, opts) => {
|
||||
fastify.register(sensible, {
|
||||
errorHandler: false
|
||||
})
|
||||
})
|
||||
20
packages/server/src/plugins/support.ts
Normal file
20
packages/server/src/plugins/support.ts
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
import fp from 'fastify-plugin'
|
||||
|
||||
export interface SupportPluginOptions {
|
||||
// Specify Support plugin options here
|
||||
}
|
||||
|
||||
// The use of fastify-plugin is required to be able
|
||||
// to export the decorators to the outer scope
|
||||
export default fp<SupportPluginOptions>(async (fastify, opts) => {
|
||||
fastify.decorate('someSupport', function () {
|
||||
return 'hugs'
|
||||
})
|
||||
})
|
||||
|
||||
// When using .decorate you have to specify added properties for Typescript
|
||||
declare module 'fastify' {
|
||||
export interface FastifyInstance {
|
||||
someSupport(): string;
|
||||
}
|
||||
}
|
||||
38
packages/server/src/routes/apple-music/album.ts
Normal file
38
packages/server/src/routes/apple-music/album.ts
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
import { FastifyPluginAsync } from 'fastify'
|
||||
import appleMusicRequest from '../../utils/appleMusicRequest'
|
||||
|
||||
const example: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
||||
fastify.get<{
|
||||
Querystring: {
|
||||
name: string
|
||||
artist: string
|
||||
lang: 'zh-CN' | 'en-US'
|
||||
}
|
||||
}>('/album', async function (request, reply) {
|
||||
const { name, lang, artist } = request.query
|
||||
|
||||
const fromApple = await appleMusicRequest({
|
||||
method: 'GET',
|
||||
url: '/search',
|
||||
params: {
|
||||
term: name,
|
||||
types: 'albums',
|
||||
'fields[albums]': 'artistName,name,editorialVideo,editorialNotes',
|
||||
limit: '1',
|
||||
l: lang.toLowerCase(),
|
||||
},
|
||||
})
|
||||
|
||||
const albums = fromApple?.results?.album?.data
|
||||
const album =
|
||||
albums?.find(
|
||||
(a: any) =>
|
||||
a.attributes.name.toLowerCase() === name.toLowerCase() &&
|
||||
a.attributes.artistName.toLowerCase() === artist.toLowerCase()
|
||||
) || albums?.[0]
|
||||
|
||||
return album
|
||||
})
|
||||
}
|
||||
|
||||
export default example
|
||||
46
packages/server/src/routes/apple-music/artist.ts
Normal file
46
packages/server/src/routes/apple-music/artist.ts
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
import { FastifyPluginAsync } from 'fastify'
|
||||
import appleMusicRequest from '../../utils/appleMusicRequest'
|
||||
|
||||
const example: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
||||
fastify.get<{
|
||||
Querystring: {
|
||||
name: string
|
||||
lang: 'zh-CN' | 'en-US'
|
||||
}
|
||||
}>('/artist', async function (request, reply) {
|
||||
const { name, lang } = request.query
|
||||
|
||||
if (!name) {
|
||||
return {
|
||||
code: 400,
|
||||
message: 'params "name" is required',
|
||||
}
|
||||
}
|
||||
|
||||
const fromApple = await appleMusicRequest({
|
||||
method: 'GET',
|
||||
url: '/search',
|
||||
params: {
|
||||
term: name,
|
||||
types: 'artists',
|
||||
'fields[artists]': 'url,name,artwork,editorialVideo,artistBio',
|
||||
'omit[resource:artists]': 'relationships',
|
||||
platform: 'web',
|
||||
limit: '1',
|
||||
l: lang?.toLowerCase() || 'en-us',
|
||||
with: 'serverBubbles',
|
||||
},
|
||||
})
|
||||
|
||||
const artist = fromApple?.results?.artist?.data?.[0]
|
||||
|
||||
if (
|
||||
artist &&
|
||||
artist?.attributes?.name?.toLowerCase() === name.toLowerCase()
|
||||
) {
|
||||
return artist
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default example
|
||||
9
packages/server/src/routes/root.ts
Normal file
9
packages/server/src/routes/root.ts
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
import { FastifyPluginAsync } from 'fastify'
|
||||
|
||||
const root: FastifyPluginAsync = async (fastify, opts): Promise<void> => {
|
||||
fastify.get('/', async function (request, reply) {
|
||||
return { root: true }
|
||||
})
|
||||
}
|
||||
|
||||
export default root;
|
||||
57
packages/server/src/utils/appleMusicRequest.ts
Normal file
57
packages/server/src/utils/appleMusicRequest.ts
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
import axios, {
|
||||
AxiosError,
|
||||
AxiosInstance,
|
||||
AxiosRequestConfig,
|
||||
AxiosResponse,
|
||||
} from 'axios'
|
||||
|
||||
export const baseURL = 'https://amp-api.music.apple.com/v1/catalog/us'
|
||||
|
||||
export const headers = {
|
||||
Authority: 'amp-api.music.apple.com',
|
||||
Accept: '*/*',
|
||||
Authorization:
|
||||
'Bearer eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6IldlYlBsYXlLaWQifQ.eyJpc3MiOiJBTVBXZWJQbGF5IiwiaWF0IjoxNjYxNDQwNDMyLCJleHAiOjE2NzY5OTI0MzIsInJvb3RfaHR0cHNfb3JpZ2luIjpbImFwcGxlLmNvbSJdfQ.z4BMv9_O4MpMK2iFhYkDqPsx53soPSnlXXK3jm99pHqGOrZADvTgEUw2U7_B1W0MAtFiWBYhYcGvWrzaOig6Bw',
|
||||
Referer: 'https://music.apple.com/',
|
||||
'Sec-Fetch-Dest': 'empty',
|
||||
'Sec-Fetch-Mode': 'cors',
|
||||
'Sec-Fetch-Site': 'cross-site',
|
||||
'User-Agent':
|
||||
'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Cider/1.5.1 Chrome/100.0.4896.160 Electron/18.3.3 Safari/537.36',
|
||||
'Accept-Encoding': 'gzip',
|
||||
Origin: 'https://music.apple.com',
|
||||
}
|
||||
|
||||
export const params = {
|
||||
platform: 'web',
|
||||
with: 'serverBubbles',
|
||||
}
|
||||
|
||||
const service: AxiosInstance = axios.create({
|
||||
baseURL,
|
||||
withCredentials: true,
|
||||
timeout: 15000,
|
||||
})
|
||||
|
||||
service.interceptors.request.use((config: AxiosRequestConfig) => {
|
||||
config.headers = { ...headers, ...config.headers }
|
||||
config.params = { ...params, ...config.params }
|
||||
return config
|
||||
})
|
||||
|
||||
service.interceptors.response.use(
|
||||
(response: AxiosResponse) => {
|
||||
const res = response
|
||||
return res
|
||||
},
|
||||
(error: AxiosError) => {
|
||||
return Promise.reject(error)
|
||||
}
|
||||
)
|
||||
|
||||
const appleMusicRequest = async (config: AxiosRequestConfig) => {
|
||||
const { data } = await service.request(config)
|
||||
return data as any
|
||||
}
|
||||
|
||||
export default appleMusicRequest
|
||||
35
packages/server/test/helper.ts
Normal file
35
packages/server/test/helper.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
// This file contains code that we reuse between our tests.
|
||||
import Fastify from 'fastify'
|
||||
import fp from 'fastify-plugin'
|
||||
import App from '../src/app'
|
||||
import * as tap from 'tap';
|
||||
|
||||
export type Test = typeof tap['Test']['prototype'];
|
||||
|
||||
// Fill in this config with all the configurations
|
||||
// needed for testing the application
|
||||
async function config () {
|
||||
return {}
|
||||
}
|
||||
|
||||
// Automatically build and tear down our instance
|
||||
async function build (t: Test) {
|
||||
const app = Fastify()
|
||||
|
||||
// fastify-plugin ensures that all decorators
|
||||
// are exposed for testing purposes, this is
|
||||
// different from the production setup
|
||||
void app.register(fp(App), await config())
|
||||
|
||||
await app.ready();
|
||||
|
||||
// Tear down our app after we are done
|
||||
t.teardown(() => void app.close())
|
||||
|
||||
return app
|
||||
}
|
||||
|
||||
export {
|
||||
config,
|
||||
build
|
||||
}
|
||||
11
packages/server/test/plugins/support.test.ts
Normal file
11
packages/server/test/plugins/support.test.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { test } from 'tap'
|
||||
import Fastify from 'fastify'
|
||||
import Support from '../../src/plugins/support'
|
||||
|
||||
test('support works standalone', async (t) => {
|
||||
const fastify = Fastify()
|
||||
void fastify.register(Support)
|
||||
await fastify.ready()
|
||||
|
||||
t.equal(fastify.someSupport(), 'hugs')
|
||||
})
|
||||
12
packages/server/test/routes/example.test.ts
Normal file
12
packages/server/test/routes/example.test.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { test } from 'tap'
|
||||
import { build } from '../helper'
|
||||
|
||||
test('example is loaded', async (t) => {
|
||||
const app = await build(t)
|
||||
|
||||
const res = await app.inject({
|
||||
url: '/example'
|
||||
})
|
||||
|
||||
t.equal(res.payload, 'this is an example')
|
||||
})
|
||||
11
packages/server/test/routes/root.test.ts
Normal file
11
packages/server/test/routes/root.test.ts
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import { test } from 'tap'
|
||||
import { build } from '../helper'
|
||||
|
||||
test('default root route', async (t) => {
|
||||
const app = await build(t)
|
||||
|
||||
const res = await app.inject({
|
||||
url: '/'
|
||||
})
|
||||
t.same(JSON.parse(res.payload), { root: true })
|
||||
})
|
||||
8
packages/server/test/tsconfig.json
Normal file
8
packages/server/test/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"noEmit": true
|
||||
},
|
||||
"include": ["../src/**/*.ts", "**/*.ts"]
|
||||
}
|
||||
8
packages/server/tsconfig.json
Normal file
8
packages/server/tsconfig.json
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
{
|
||||
"extends": "fastify-tsconfig",
|
||||
"compilerOptions": {
|
||||
"outDir": "dist",
|
||||
"sourceMap": true
|
||||
},
|
||||
"include": ["src/**/*.ts"]
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue