Skip to content

Commit 28605f4

Browse files
committed
add torrent manage
f f f
1 parent ed538ca commit 28605f4

21 files changed

Lines changed: 600 additions & 65 deletions

File tree

backend/src/module/api/__init__.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
from .program import router as program_router
99
from .rss import router as rss_router
1010
from .search import router as search_router
11+
from .torrent import router as torrent_router
1112

1213
__all__ = ["v1","lifespan"]
1314

@@ -20,3 +21,4 @@
2021
v1.include_router(config_router)
2122
v1.include_router(rss_router)
2223
v1.include_router(search_router)
24+
v1.include_router(torrent_router)

backend/src/module/api/bangumi.py

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
from module.database import Database, engine
88
from module.manager import BangumiManager
9-
from module.models import APIResponse, Bangumi, BangumiUpdate, ResponseModel
9+
from module.models import APIResponse, Bangumi, BangumiUpdate, ResponseModel,Torrent
1010
from module.security.api import get_current_user
1111

1212
from .response import u_response
@@ -217,12 +217,37 @@ async def refresh_single_poster(bangumi_id: int):
217217
async def reset_all():
218218
with Database(engine) as db:
219219
db.bangumi.delete_all()
220-
return JSONResponse(
221-
status_code=200,
222-
content={
223-
"msg_en": "Reset all rules successfully.",
224-
"msg_zh": "重置所有规则成功。",
225-
},
226-
)
220+
return JSONResponse(
221+
status_code=200,
222+
content={
223+
"msg_en": "Reset all rules successfully.",
224+
"msg_zh": "重置所有规则成功。",
225+
},
226+
)
227+
228+
229+
# @router.get("/get_torrent", response_model=list[Torrent], dependencies=[Depends(get_current_user)])
230+
# async def manage_bangumi(_id:int):
231+
# """
232+
# 管理对应 Bangumi 的规则
233+
# """
234+
# try:
235+
# resp = await BangumiManager().fetch_all_bangumi_torrents(_id)
236+
# return resp
237+
# except Exception as e:
238+
# logger.error(f"[Bangumi] Error managing bangumi: {e}")
239+
# return []
240+
#
241+
# @router.get("/download_torrent", response_model=APIResponse, dependencies=[Depends(get_current_user)])
242+
# async def download_bangumi(_id:int, torrent:Torrent):
243+
# """
244+
# 手动下载对应 Bangumi 的种子
245+
# """
246+
# try:
247+
# resp = BangumiManager().download_torrent(_id,torrent)
248+
# return resp
249+
# except Exception as e:
250+
# logger.error(f"[Bangumi] Error downloading bangumi: {e}")
251+
# return []
227252

228253

backend/src/module/api/torrent.py

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
import logging
2+
3+
from fastapi import APIRouter, Depends, HTTPException
4+
from fastapi.responses import JSONResponse
5+
from sqlalchemy.util.concurrency import asyncio
6+
7+
from module.database import Database, engine
8+
from module.manager import BangumiManager, TorrentManager
9+
from module.models import APIResponse, Bangumi, BangumiUpdate, ResponseModel, Torrent
10+
from module.security.api import get_current_user
11+
12+
from .response import u_response
13+
14+
router = APIRouter(prefix="/torrent", tags=["torrent"])
15+
logger = logging.getLogger(__name__)
16+
17+
18+
@router.get(
19+
"/get_all",
20+
response_model=list[Torrent],
21+
dependencies=[Depends(get_current_user)],
22+
)
23+
async def manage_bangumi(_id: int):
24+
"""
25+
管理对应 Bangumi 的规则
26+
"""
27+
try:
28+
resp = await TorrentManager().fetch_all_bangumi_torrents(_id)
29+
return resp
30+
except Exception as e:
31+
logger.error(f"[Bangumi] Error managing bangumi: {e}")
32+
return []
33+
34+
35+
@router.post(
36+
"/delete",
37+
response_model=APIResponse,
38+
dependencies=[Depends(get_current_user)],
39+
)
40+
async def delete_torrent(url: str):
41+
"""
42+
删除对应的种子
43+
"""
44+
try:
45+
resp = await TorrentManager().delete_torrent(url)
46+
if resp:
47+
resp = ResponseModel(
48+
status_code=200,
49+
status=True,
50+
msg_en=f"Delete torrent for {url}",
51+
msg_zh=f"删除 {url} 的种子",
52+
)
53+
else:
54+
resp = ResponseModel(
55+
status_code=406,
56+
status=False,
57+
msg_en=f"Can't find torrent with url {url}",
58+
msg_zh=f"无法找到 url 为 {url} 的种子",
59+
)
60+
return resp
61+
except Exception as e:
62+
logger.error(f"[Bangumi] Error deleting torrent: {e}")
63+
return ResponseModel(
64+
status_code=500,
65+
status=False,
66+
msg_en="Internal server error",
67+
msg_zh="服务器内部错误",
68+
)
69+
70+
71+
@router.post(
72+
"/download",
73+
response_model=APIResponse,
74+
dependencies=[Depends(get_current_user)],
75+
)
76+
async def download_bangumi(_id: int, torrent: Torrent):
77+
"""
78+
手动下载对应 Bangumi 的种子
79+
"""
80+
try:
81+
resp = TorrentManager().download_torrent(_id, torrent)
82+
if resp:
83+
resp = ResponseModel(
84+
status_code=200,
85+
status=True,
86+
msg_en=f"Download torrent for {_id}",
87+
msg_zh=f"下载 {_id} 的种子",
88+
)
89+
else:
90+
resp = ResponseModel(
91+
status_code=406,
92+
status=False,
93+
msg_en=f"Can't find id {_id}",
94+
msg_zh=f"无法找到 id {_id}",
95+
)
96+
return resp
97+
except Exception as e:
98+
logger.error(f"[Bangumi] Error downloading bangumi: {e}")
99+
return ResponseModel(
100+
status_code=500,
101+
status=False,
102+
msg_en="Internal server error",
103+
msg_zh="服务器内部错误",
104+
)

backend/src/module/database/combine.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import logging
22

3-
from sqlmodel import Session, SQLModel, and_, delete, false, or_, select, text
3+
from sqlmodel import Session, SQLModel, and_, false, select, text
44

55
from module.models import Bangumi, RSSItem, Torrent, User
66

backend/src/module/database/torrent.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,7 @@ def delete_by_url(self, url: str) -> bool:
119119
)
120120
self.session.commit()
121121
return True
122+
return False
122123

123124
def delete_by_duid(self, duid: str) -> bool:
124125
stmt = select(Torrent).where(Torrent.download_uid == duid)

backend/src/module/downloader/download_client.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,6 @@ async def move_torrent(self, hashes: list[str] | str, location: str) -> bool:
249249
if not await self.wait_for_login():
250250
return False # 登录失败时返回False
251251
try:
252-
#TODO: 好像是用 | 连起来就行,但现在好像用不上了
253252
result = await self.downloader.move(hashes=hashes, new_location=location)
254253
if result:
255254
logger.info(f"[Downloader] Move torrents {hashes} to {location}")

backend/src/module/manager/bangumi.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,10 @@
44
from module.conf import settings
55
from module.database import Database, engine
66
from module.downloader import Client as DownlondClient
7+
from module.downloader import download_queue
78
from module.manager.torrent import TorrentManager
89
from module.models import Bangumi, BangumiUpdate, Torrent
10+
from module.network import RequestContent
911
from module.parser import MikanParser, TmdbParser
1012
from module.utils import gen_save_path
1113
from module.utils.events import Event, EventType, event_bus
@@ -158,6 +160,10 @@ def search_one(self, _id: int | str):
158160
return data
159161

160162

163+
164+
165+
161166
if __name__ == "__main__":
162167
manager = TorrentManager()
163-
asyncio.run(manager.refresh_poster())
168+
manager = BangumiManager()
169+
asyncio.run(manager.fetch_all_bangumi_torrents(1))

backend/src/module/manager/renamer.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ async def rename_torrent(self, torrent: Torrent, bangumi: Bangumi | None = None)
248248
return
249249
if bangumi is None:
250250
with Database() as db:
251+
#NOTE: 这里会更新一下 season 和 official_title
252+
# 可能是因为更新了番剧信息导致的
251253
bangumi = db.torrent_to_bangumi(torrent)
252254
if not bangumi:
253255
bangumi = Bangumi(

backend/src/module/manager/torrent.py

Lines changed: 56 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@
22

33
from module.database import Database, engine
44
from module.downloader import Client as DownlondClient
5-
from module.models import Bangumi
5+
from module.downloader import download_queue
6+
from module.models import Bangumi, Torrent
7+
from module.network import RequestContent
68

79
logger = logging.getLogger(__name__)
810

@@ -36,3 +38,56 @@ async def delete_torrents(self, data: Bangumi) -> bool:
3638
logger.info(f"Delete rule and torrents for {data.official_title}")
3739
return True
3840
return False
41+
42+
async def delete_torrent(self,url:str)->bool:
43+
with Database(engine) as db:
44+
torrent = db.torrent.search_by_url(url)
45+
if torrent and torrent.download_uid:
46+
res = await DownlondClient.delete_torrent(torrent.download_uid)
47+
res = db.torrent.delete_by_url(url)
48+
return res
49+
50+
def download_torrent(self, _id:int,torrent: Torrent) -> bool:
51+
"""下载种子
52+
Args:
53+
bangumi: 番剧信息
54+
"""
55+
with Database() as db:
56+
bangumi = db.bangumi.search_id(int(_id))
57+
if not bangumi:
58+
logger.error(f"[Manager] Can't find data with {_id}")
59+
return False
60+
61+
# 构造一个 torrent
62+
torrent.bangumi_official_title = bangumi.official_title
63+
torrent.bangumi_season = bangumi.season
64+
torrent.rss_link = bangumi.rss_link
65+
66+
download_queue.add(torrent, bangumi)
67+
return True
68+
69+
async def fetch_all_bangumi_torrents(self,_id:int)->list[Torrent]:
70+
# 先拉一下 rss
71+
# 然后从数据库找
72+
# 最后返回一个 torrent list
73+
with Database() as db:
74+
bangumi = db.bangumi.search_id(int(_id))
75+
if not bangumi:
76+
logger.error(f"[Manager] Can't find data with {_id}")
77+
return []
78+
exist_torrents: list[Torrent] = db.find_torrent_by_bangumi(bangumi)
79+
url = bangumi.rss_link
80+
existing_urls = {torrent.url for torrent in exist_torrents}
81+
async with RequestContent() as req:
82+
torrents = await req.get_torrents(url)
83+
title_raws = bangumi.title_raw.split(",")
84+
for torrent in torrents:
85+
if torrent.url in existing_urls:
86+
continue
87+
for title in title_raws:
88+
if title in torrent.name:
89+
exist_torrents.append(torrent)
90+
existing_urls.add(torrent.url)
91+
break
92+
exist_torrents.sort(key=lambda x: x.name, reverse=True)
93+
return exist_torrents

backend/src/module/models/torrent.py

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from datetime import datetime
1+
from datetime import datetime, timezone
22

33
from pydantic import BaseModel
44
from sqlmodel import Field, SQLModel
@@ -9,14 +9,13 @@
99
class Torrent(SQLModel, table=True):
1010
url: str = Field(primary_key=True, alias="url")
1111
name: str = Field(default="", alias="name")
12-
created_at: datetime = Field(default_factory=datetime.utcnow, index=True)
12+
created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc), index=True)
1313
downloaded: bool = Field(default=False, alias="downloaded")
1414
renamed: bool = Field(default=False, alias="renamed")
1515
download_uid: str | None = Field(default=None, alias="duid", index=True)
1616
bangumi_official_title: str = Field(default="", index=True, alias="bangumi_title")
1717
bangumi_season: int = Field(default=1, index=True, alias="bangumi_season")
1818
rss_link: str = Field(default="", alias="ruid", index=True)
19-
# TODO: 添加外键字段 rss_id 和 bangumi_id 替代当前的字符串引用
2019
homepage: str | None = Field(default=None, alias="homepage")
2120

2221

0 commit comments

Comments
 (0)