Skip to content

Commit 6c7a144

Browse files
authored
Merge pull request #39 from nuthx/dev-0.0.11
Dev 0.0.11
2 parents df82175 + 9b22eb5 commit 6c7a144

File tree

38 files changed

+1864
-340
lines changed

38 files changed

+1864
-340
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ node_modules
44
.env
55
.env.local
66
.vscode
7+
.idea
78
.DS_Store
89
database
910
logs

.gitignore

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,15 +28,12 @@ yarn-debug.log*
2828
yarn-error.log*
2929
.pnpm-debug.log*
3030

31-
# env files (can opt-in for committing if needed)
31+
# env
3232
.env*
3333

3434
# vercel
3535
.vercel
3636

37-
# typescript
38-
*.tsbuildinfo
39-
next-env.d.ts
40-
41-
# VSCode
37+
# ide
4238
.vscode
39+
.idea

app/anime/[hash]/page.js

Lines changed: 351 additions & 0 deletions
Large diffs are not rendered by default.

app/anime/page.js

Lines changed: 147 additions & 132 deletions
Large diffs are not rendered by default.

app/api/anime/[hash]/desc/route.js

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { prisma } from "@/lib/db";
2+
import { dynamicImport } from "@/lib/core/dynamic";
3+
import { sendResponse } from "@/lib/http/response";
4+
5+
// Get anime description from source url
6+
// Params: hash, string, required
7+
export async function GET(request, { params }) {
8+
try {
9+
const hash = (await params).hash;
10+
11+
const anime = await prisma.anime.findUnique({
12+
where: {
13+
hash: hash,
14+
},
15+
include: {
16+
rss: { select: { name: true } },
17+
},
18+
});
19+
20+
if (!anime) {
21+
throw new Error("No anime found");
22+
}
23+
24+
// Dynamic import
25+
const { parserModule } = await dynamicImport(anime.source);
26+
27+
// Get source content from source url
28+
const res = await fetch(anime.sourceUrl);
29+
const html = await res.text();
30+
const desc = parserModule.extractDescription(html);
31+
32+
return sendResponse(request, {
33+
data: {
34+
type: anime.source,
35+
content: desc
36+
}
37+
});
38+
} catch (error) {
39+
return sendResponse(request, {
40+
code: 500,
41+
message: error.message
42+
});
43+
}
44+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { prisma } from "@/lib/db";
2+
import { getAnimeDetailFromAnilist } from "@/lib/api/anilist";
3+
import { getAnimeDetailFromBangumi } from "@/lib/api/bangumi";
4+
import { sendResponse } from "@/lib/http/response";
5+
6+
// Refresh anime info by manually input anilist or bangumi id
7+
// Body: {
8+
// anilist_id: string, optional
9+
// bangumi_id: string, optional
10+
// }
11+
export async function POST(request, { params }) {
12+
try {
13+
const data = await request.json();
14+
const hash = (await params).hash;
15+
let newAnilist = null;
16+
let newBangumi = null;
17+
18+
const anime = await prisma.anime.findUnique({
19+
where: { hash },
20+
});
21+
22+
if (!anime) {
23+
throw new Error("No anime found");
24+
}
25+
26+
if (
27+
(!data.anilist_id || data.anilist_id === anime.idAnilist) &&
28+
(!data.bangumi_id || data.bangumi_id === anime.idBangumi)
29+
) {
30+
throw new Error("No change");
31+
}
32+
33+
if (data.anilist_id) {
34+
newAnilist = await getAnimeDetailFromAnilist(data.anilist_id);
35+
}
36+
37+
if (data.bangumi_id) {
38+
newBangumi = await getAnimeDetailFromBangumi(data.bangumi_id);
39+
}
40+
41+
if (newAnilist) {
42+
await prisma.anime.update({
43+
where: { hash },
44+
data: {
45+
titleJp: newAnilist?.title?.native,
46+
titleEn: newAnilist?.title?.english,
47+
titleRomaji: newAnilist?.title?.romaji,
48+
coverAnilist: newAnilist?.coverImage?.extraLarge,
49+
idAnilist: data.anilist_id
50+
}
51+
});
52+
}
53+
54+
if (newBangumi) {
55+
await prisma.anime.update({
56+
where: { hash },
57+
data: {
58+
titleJp: newBangumi?.name, // Japanese title in bangumi will replace the title in anilist
59+
titleCn: newBangumi?.name_cn,
60+
coverBangumi: newBangumi?.images?.large,
61+
idBangumi: data.bangumi_id
62+
}
63+
});
64+
}
65+
66+
return sendResponse(request, {
67+
message: "Anime info updated successfully"
68+
});
69+
} catch (error) {
70+
if (error.message === "No change") {
71+
return sendResponse(request, {
72+
code: 240,
73+
message: error.message
74+
});
75+
}
76+
77+
return sendResponse(request, {
78+
code: 500,
79+
message: error.message
80+
});
81+
}
82+
}

app/api/anime/[hash]/route.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
import { prisma } from "@/lib/db";
2+
import { getTitleFirst } from "@/lib/title";
3+
import { sendResponse } from "@/lib/http/response";
4+
5+
// Get anime detail by hash
6+
// Params: hash, string, required
7+
export async function GET(request, { params }) {
8+
try {
9+
const hash = (await params).hash;
10+
11+
const anime = await prisma.anime.findUnique({
12+
where: {
13+
hash: hash,
14+
},
15+
include: {
16+
rss: { select: { name: true } },
17+
},
18+
});
19+
20+
if (!anime) {
21+
throw new Error("No anime found");
22+
}
23+
24+
return sendResponse(request, {
25+
data: {
26+
...anime,
27+
titleFirst: await getTitleFirst(anime)
28+
}
29+
});
30+
} catch (error) {
31+
return sendResponse(request, {
32+
code: 500,
33+
message: error.message
34+
});
35+
}
36+
}

app/api/anime/route.js

Lines changed: 9 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import { prisma, getConfig } from "@/lib/db";
1+
import { prisma } from "@/lib/db";
2+
import { getTitleFirst } from "@/lib/title";
23
import { sendResponse } from "@/lib/http/response";
34

45
// Get anime list with pagination
@@ -30,11 +31,7 @@ export async function GET(request) {
3031
pubDate: "desc"
3132
},
3233
include: {
33-
rss: {
34-
select: {
35-
name: true
36-
}
37-
}
34+
rss: { select: { name: true } }
3835
}
3936
}),
4037
// Get total count
@@ -67,26 +64,14 @@ export async function GET(request) {
6764
})
6865
]);
6966

70-
// Add titleFirst to each anime item
71-
const config = await getConfig();
72-
const priorities = config.animeTitlePriority.split(",");
73-
const animeWithTitleFirst = anime.map(item => ({
74-
...item,
75-
titleFirst: priorities.reduce((title, p) => {
76-
if (title) return title;
77-
const titleMap = {
78-
jp: item.titleJp,
79-
romaji: item.titleRomaji,
80-
cn: item.titleCn,
81-
en: item.titleEn
82-
};
83-
return titleMap[p];
84-
}, "") || item.titleParsed || item.titleRaw
85-
}));
86-
8767
return sendResponse(request, {
8868
data: {
89-
anime: animeWithTitleFirst,
69+
anime: await Promise.all(
70+
anime.map(async (item) => ({
71+
...item,
72+
titleFirst: await getTitleFirst(item)
73+
}))
74+
),
9075
rss: {
9176
current: rss || "",
9277
list: rssList.map(r => r.name)

app/api/torrents/route.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { prisma } from "@/lib/db";
2-
import { formatBytes } from "@/lib/bytes";
2+
import { formatBytes, formatEta } from "@/lib/format";
33
import { sendResponse } from "@/lib/http/response";
4-
import { getQbittorrentVersion, getQbittorrentTorrents, manageQbittorrentTorrent } from "@/lib/api/qbittorrent";
4+
import { QB_STATE, getQbittorrentVersion, getQbittorrentTorrents, manageQbittorrentTorrent } from "@/lib/api/qbittorrent";
55

66
// Get torrent list
77

@@ -27,10 +27,12 @@ export async function GET(request) {
2727
name: torrent.name,
2828
hash: torrent.hash,
2929
state: torrent.state,
30+
state_class: Object.keys(QB_STATE).find(key => QB_STATE[key].includes(torrent.state)) || "stalled",
3031
progress: torrent.progress,
3132
eta: torrent.eta,
32-
dlspeed: formatBytes(torrent.dlspeed),
33-
upspeed: formatBytes(torrent.upspeed),
33+
eta_dict: formatEta(torrent.eta),
34+
dl_speed: formatBytes(torrent.dl_speed),
35+
up_speed: formatBytes(torrent.up_speed),
3436
completed: formatBytes(torrent.completed),
3537
size: formatBytes(torrent.size),
3638
added_on: torrent.added_on,

app/downloads/page.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import { Pause, RefreshCcw, Trash2 } from "lucide-react";
2929
export default function Home() {
3030
const { t } = useTranslation();
3131

32-
const { data: torrentsData, error: torrentsError, isLoading: torrentsLoading, mutate: mutateTorrents } = useData(API.TORRENTS, null, { refreshInterval: 1000 });
32+
const { data: torrentsData, error: torrentsError, isLoading: torrentsLoading, mutate: torrentsMutate } = useData(API.TORRENTS, null, { refreshInterval: 1000 });
3333

3434
// Set page title
3535
useEffect(() => {
@@ -39,7 +39,7 @@ export default function Home() {
3939
const handleManage = async (action, downloader, hash) => {
4040
const result = await handleRequest("POST", API.TORRENTS, { action, downloader, hash }, t(`toast.failed.${action}`));
4141
if (result) {
42-
mutateTorrents();
42+
torrentsMutate();
4343
}
4444
};
4545

@@ -74,8 +74,8 @@ export default function Home() {
7474
</div>
7575
<a className="font-medium">{item.name}</a>
7676
<div className="flex items-center gap-2">
77-
<a className="w-1/6 text-sm text-muted-foreground">{t("downloads.d_speed")}: {item.dlspeed}/s</a>
78-
<a className="w-1/6 text-sm text-muted-foreground">{t("downloads.u_speed")}: {item.upspeed}/s</a>
77+
<a className="w-1/6 text-sm text-muted-foreground">{t("downloads.d_speed")}: {item.dl_speed}/s</a>
78+
<a className="w-1/6 text-sm text-muted-foreground">{t("downloads.u_speed")}: {item.up_speed}/s</a>
7979
{item.eta !== 8640000 && <a className="w-2/6 text-sm text-muted-foreground">
8080
{t("downloads.eta")}: {Math.floor(item.eta/86400) > 0 && `${Math.floor(item.eta/86400)} ${t("downloads.d")} `}
8181
{Math.floor((item.eta%86400)/3600) > 0 && `${Math.floor((item.eta%86400)/3600)} ${t("downloads.h")} `}

0 commit comments

Comments
 (0)