Feat: Add ACGM API
随机动漫音乐曲库可根据 id 和番名添加(无鉴权),目录结构调整,前端部分内容更正
This commit is contained in:
parent
48d289b076
commit
0dbad9a6a6
|
|
@ -4,6 +4,13 @@ import { defineConfig } from '@midwayjs/hooks-kit';
|
||||||
import { resolve } from "path";
|
import { resolve } from "path";
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
source: "./src/server",
|
||||||
|
routes: [
|
||||||
|
{
|
||||||
|
baseDir: "api",
|
||||||
|
basePath: "/api"
|
||||||
|
}
|
||||||
|
],
|
||||||
vite: {
|
vite: {
|
||||||
plugins: [react()],
|
plugins: [react()],
|
||||||
resolve: {
|
resolve: {
|
||||||
|
|
|
||||||
|
|
@ -16,5 +16,6 @@ model ACGM {
|
||||||
bangumi String?
|
bangumi String?
|
||||||
music_id Int @unique
|
music_id Int @unique
|
||||||
created_at DateTime @default(now())
|
created_at DateTime @default(now())
|
||||||
|
enabled Boolean @default(true)
|
||||||
updated_at DateTime?
|
updated_at DateTime?
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ export const About = () => {
|
||||||
<>
|
<>
|
||||||
<h3>关于本项目</h3>
|
<h3>关于本项目</h3>
|
||||||
<p>保罗 API 基本上作为一只辅助角色,默默无闻的服务着其他主要项目,这便是它存在的意义。像「随机动漫壁纸」接口就是为 <a href="https://github.com/Dreamer-Paul/Single" target="_blank">Single</a> 主题量身定做的,既符合主题外观特性,又能满足其他人的快捷使用。它诞生于 2018 年 4 月,是保罗入门后端和 PHP 语言的主要项目之一。</p>
|
<p>保罗 API 基本上作为一只辅助角色,默默无闻的服务着其他主要项目,这便是它存在的意义。像「随机动漫壁纸」接口就是为 <a href="https://github.com/Dreamer-Paul/Single" target="_blank">Single</a> 主题量身定做的,既符合主题外观特性,又能满足其他人的快捷使用。它诞生于 2018 年 4 月,是保罗入门后端和 PHP 语言的主要项目之一。</p>
|
||||||
<p>项目后端采用原生 PHP 编写,前端是原生 CSS 和 JS,也就是非前后端分离项目,不需要额外的前端 SSR 服务。它没有任何框架加持(自己写的),所以执行速度和并发还是个谜。尽管如此,它也较为稳定的跑了这么久,不是吗?</p>
|
<p>项目后端采用 MidwayJS 重构,前端是 React,相较于原先的 PHP 版本,性能确实略快了一些,就是没有 SSR。</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li>前端:React (CSR)</li>
|
<li>前端:React (CSR)</li>
|
||||||
<li>后端:MidwayJS (NodeJS)</li>
|
<li>后端:MidwayJS (NodeJS)</li>
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ function FrontWrapper(props: FrontWrapperProps) {
|
||||||
else if (name) {
|
else if (name) {
|
||||||
document.title = String(name);
|
document.title = String(name);
|
||||||
}
|
}
|
||||||
}, []);
|
}, [location.pathname]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
window.scrollTo({ top: 0, left: 0 });
|
window.scrollTo({ top: 0, left: 0 });
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import React from "react";
|
||||||
|
|
||||||
import { useRequest } from "ahooks";
|
import { useRequest } from "ahooks";
|
||||||
|
|
||||||
import getStat from "../api/stat";
|
import getStat from "../server/api/stat";
|
||||||
|
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
import ArticleHead from "@/components/Layout/ArticleHead";
|
import ArticleHead from "@/components/Layout/ArticleHead";
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,7 @@ function Netease() {
|
||||||
|
|
||||||
<h3>示例:</h3>
|
<h3>示例:</h3>
|
||||||
<p>通过 ID 获得一首歌的信息</p>
|
<p>通过 ID 获得一首歌的信息</p>
|
||||||
<pre className="language-javascript"><code>{`https://api.paugram.com/netease/?id=448143347
|
<pre className="language-javascript"><code>{`https://api.paugram.com/api/netease/?id=448143347
|
||||||
|
|
||||||
// 返回的是:
|
// 返回的是:
|
||||||
|
|
||||||
|
|
@ -137,11 +137,11 @@ function Netease() {
|
||||||
}
|
}
|
||||||
`}</code></pre>
|
`}</code></pre>
|
||||||
<p>通过 ID 获得一首歌,并跳转到实际地址</p>
|
<p>通过 ID 获得一首歌,并跳转到实际地址</p>
|
||||||
<pre><code>https://api.paugram.com/netease/?id=517567145&play=true</code></pre>
|
<pre><code>https://api.paugram.com/api/netease/?id=517567145&play=true</code></pre>
|
||||||
<p>结合 Kico Style 和 Kico Player 使用本 API</p>
|
<p>结合 Kico Style 和 Kico Player 使用本 API</p>
|
||||||
<pre className="language-javascript"><code>{`ks.ajax({
|
<pre className="language-javascript"><code>{`ks.ajax({
|
||||||
method: "GET",
|
method: "GET",
|
||||||
url: \`https://api.paugram.com/netease/?id=\${id}\`,
|
url: \`https://api.paugram.com/api/netease/?id=\${id}\`,
|
||||||
success: (req) => {
|
success: (req) => {
|
||||||
const item = JSON.parse(req.response);
|
const item = JSON.parse(req.response);
|
||||||
声明的播放器.add([item]);
|
声明的播放器.add([item]);
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,115 @@
|
||||||
|
import { Api, Post, Query, useContext, useInject } from "@midwayjs/hooks";
|
||||||
|
import { RedisService } from "@midwayjs/redis";
|
||||||
|
import { prisma } from "../../utils/prisma";
|
||||||
|
|
||||||
|
import { getSong } from "../../utils/netease";
|
||||||
|
|
||||||
|
export default Api(
|
||||||
|
Post(),
|
||||||
|
Query<{ id: string, bangumi: string }>(),
|
||||||
|
async () => {
|
||||||
|
const ctx = useContext();
|
||||||
|
const client = await useInject(RedisService);
|
||||||
|
|
||||||
|
const { id, bangumi } = ctx.query;
|
||||||
|
|
||||||
|
if (!id || !bangumi) {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
msg: "Required id or bangumi"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 查重
|
||||||
|
const isExist = await prisma.aCGM.findUnique({
|
||||||
|
where: {
|
||||||
|
music_id: Number(id)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if (isExist) {
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
msg: "this song are existed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let result;
|
||||||
|
|
||||||
|
// 尝试使用缓存
|
||||||
|
const cached = await client.lrange(`api-next:163:${id}`, 0, 7);
|
||||||
|
|
||||||
|
if (cached.length) {
|
||||||
|
result = {
|
||||||
|
id: Number(id),
|
||||||
|
title: cached[0],
|
||||||
|
artist: cached[1],
|
||||||
|
album: cached[2],
|
||||||
|
alias: cached[3],
|
||||||
|
cover: cached[4],
|
||||||
|
lyric: cached[5],
|
||||||
|
sub_lyric: cached[6],
|
||||||
|
link: cached[7],
|
||||||
|
served: Boolean(cached[8]),
|
||||||
|
cached: true
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// 全新获取
|
||||||
|
const song = await getSong(id);
|
||||||
|
|
||||||
|
if (song) {
|
||||||
|
await client.rpush(`api-next:163:${id}`,
|
||||||
|
song.title,
|
||||||
|
song.artist,
|
||||||
|
song.album,
|
||||||
|
song.alias,
|
||||||
|
song.cover,
|
||||||
|
song.lyric,
|
||||||
|
song.sub_lyric,
|
||||||
|
song.link,
|
||||||
|
song.served,
|
||||||
|
err => {
|
||||||
|
err && console.log(err);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
await client.expire(`api-next:163:${id}`, 21600);
|
||||||
|
|
||||||
|
console.log(song);
|
||||||
|
|
||||||
|
result = {
|
||||||
|
...song,
|
||||||
|
cached: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(result);
|
||||||
|
|
||||||
|
// 有数据支撑
|
||||||
|
if (result) {
|
||||||
|
// 创建数据
|
||||||
|
await prisma.aCGM.create({
|
||||||
|
data: {
|
||||||
|
title: result.title,
|
||||||
|
artist: result.artist,
|
||||||
|
album: result.album,
|
||||||
|
alias: result.alias,
|
||||||
|
bangumi,
|
||||||
|
music_id: Number(id),
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 1,
|
||||||
|
msg: "Success",
|
||||||
|
data: result
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
code: 0,
|
||||||
|
msg: "Failed",
|
||||||
|
data: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
import { Api, Get, Query, useContext, useInject } from "@midwayjs/hooks";
|
import { Api, Get, Query, useContext, useInject } from "@midwayjs/hooks";
|
||||||
import { RedisService } from "@midwayjs/redis";
|
import { RedisService } from "@midwayjs/redis";
|
||||||
import { prisma } from "./utils/prisma";
|
import { prisma } from "../../utils/prisma";
|
||||||
|
|
||||||
import { getSong } from "./utils/netease";
|
import { getSong } from "../../utils/netease";
|
||||||
|
|
||||||
export default Api(
|
export default Api(
|
||||||
Get(),
|
Get(),
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Api, Get, Query, useContext, useInject } from "@midwayjs/hooks";
|
import { Api, Get, Query, useContext, useInject } from "@midwayjs/hooks";
|
||||||
import { RedisService } from "@midwayjs/redis";
|
import { RedisService } from "@midwayjs/redis";
|
||||||
|
|
||||||
import { getVideoInfo } from "./utils/bili";
|
import { getVideoInfo } from "../utils/bili";
|
||||||
|
|
||||||
const availableStyle = ["gray", "white", "black", "shadow"];
|
const availableStyle = ["gray", "white", "black", "shadow"];
|
||||||
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Api, Get, Query, useContext, useInject } from "@midwayjs/hooks";
|
import { Api, Get, Query, useContext, useInject } from "@midwayjs/hooks";
|
||||||
import { RedisService } from "@midwayjs/redis";
|
import { RedisService } from "@midwayjs/redis";
|
||||||
|
|
||||||
import { getSong } from "./utils/netease";
|
import { getSong } from "../utils/netease";
|
||||||
|
|
||||||
export default Api(
|
export default Api(
|
||||||
Get(),
|
Get(),
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
import { Api, Get, Query, useContext, useInject } from "@midwayjs/hooks";
|
import { Api, Get, Query, useContext, useInject } from "@midwayjs/hooks";
|
||||||
import { RedisService } from "@midwayjs/redis";
|
import { RedisService } from "@midwayjs/redis";
|
||||||
|
|
||||||
import { source } from "./data/wallpaper";
|
import { source } from "../data/wallpaper";
|
||||||
import { random } from "lodash";
|
import { random } from "lodash";
|
||||||
|
|
||||||
export default Api(
|
export default Api(
|
||||||
|
|
@ -12,6 +12,7 @@ export default createConfiguration({
|
||||||
imports: [Koa, redis, hooks()],
|
imports: [Koa, redis, hooks()],
|
||||||
importConfigs: [{
|
importConfigs: [{
|
||||||
default: {
|
default: {
|
||||||
|
keys: "session_keys",
|
||||||
redis: {
|
redis: {
|
||||||
client: {
|
client: {
|
||||||
port: Number(env.parsed ?. CACHE_PORT) || 6379,
|
port: Number(env.parsed ?. CACHE_PORT) || 6379,
|
||||||
|
|
@ -46,7 +46,7 @@ export const parseSongData = async (item: any) => {
|
||||||
id: item.id,
|
id: item.id,
|
||||||
title: item.name,
|
title: item.name,
|
||||||
artist: item.artists ?. [0].name || "",
|
artist: item.artists ?. [0].name || "",
|
||||||
alias: item.alias ?. [0] || "",
|
alias: item.transName || (Array.isArray(item.alias) ? (item.alias[0] || "") : ""),
|
||||||
album: item.album.name || "",
|
album: item.album.name || "",
|
||||||
cover: `${item.album.picUrl.replace("http://", "https://")}?param=250y250"`,
|
cover: `${item.album.picUrl.replace("http://", "https://")}?param=250y250"`,
|
||||||
lyric,
|
lyric,
|
||||||
Loading…
Reference in New Issue