Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auto make torrent and add it to qb #13

Merged
merged 2 commits into from
Dec 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -169,3 +169,5 @@ cython_debug/
/store.json
/conf/store.json
/tests/store.json

*.torrent
68 changes: 55 additions & 13 deletions animepipeline/bt/qb.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@

import qbittorrentapi
from loguru import logger
from torrentool.torrent import Torrent

from animepipeline.config import QBitTorrentConfig
from animepipeline.util import gen_magnet_link
from animepipeline.util import ANNOUNCE_URLS, gen_magnet_link


class QBittorrentManager:
Expand All @@ -27,25 +28,44 @@ def __init__(self, config: QBitTorrentConfig) -> None:

self.COMPLETE_STATES = ["uploading", "stalledUP", "pausedUP", "queuedUP"]

def add_torrent(self, torrent_hash: str, torrent_url: Optional[Union[str, Path]] = None) -> None:
def add_torrent(
self, torrent_hash: str, torrent_url: Optional[str] = None, torrent_file_path: Optional[Union[str, Path]] = None
) -> None:
"""
Add a torrent to download
Add a torrent to download, either from a magnet link or a torrent file

:param torrent_hash: Torrent hash
:param torrent_url: Torrent URL, defaults to None, in which case a magnet link will be
:param torrent_url: Torrent URL, defaults to None, in which case a magnet link will be generated
:param torrent_file_path: Torrent file path, defaults to None
"""
if torrent_url is None:
torrent_url = gen_magnet_link(torrent_hash)

if self.check_torrent_exist(torrent_hash):
logger.warning(f"Torrent {torrent_hash} already exists.")
return

try:
self.client.torrents.add(urls=torrent_url)
logger.info(f"Torrent {torrent_url} added for download.")
except Exception as e:
logger.error(f"Failed to add torrent: {e}")
if torrent_file_path is None:
# add fron torrent url
if torrent_url is None:
torrent_url = gen_magnet_link(torrent_hash)

try:
self.client.torrents.add(urls=torrent_url)
logger.info(f"Torrent {torrent_url} added for download.")
except Exception as e:
logger.error(f"Failed to add torrent: {e}")
else:
# add from torrent file path
if not Path(torrent_file_path).exists():
logger.error(f"Torrent file {torrent_file_path} does not exist.")
return

with open(torrent_file_path, "rb") as f:
torrent_file = f.read()

try:
self.client.torrents.add(torrent_files=torrent_file)
logger.info(f"Torrent {torrent_file_path} added for download.")
except Exception as e:
logger.error(f"Failed to add torrent: {e}")

def check_download_complete(self, torrent_hash: str) -> bool:
"""
Expand All @@ -56,7 +76,7 @@ def check_download_complete(self, torrent_hash: str) -> bool:

try:
torrent = self.client.torrents_info(torrent_hashes=torrent_hash)

# logger.debug(f"Torrent state: {torrent[0].state}")
if torrent[0].state in self.COMPLETE_STATES:
return True
else:
Expand Down Expand Up @@ -100,3 +120,25 @@ def check_torrent_exist(self, torrent_hash: str) -> bool:
except Exception as e:
logger.error(f"Error checking torrent existence: {e}")
return False

@staticmethod
def make_torrent_file(file_path: Union[str, Path], torrent_file_save_path: Union[str, Path]) -> str:
"""
Make a torrent file from a file, return the hash of the torrent

:param file_path: File path
:param torrent_file_save_path: Torrent file save path
"""
if not Path(file_path).exists():
logger.error(f"File {file_path} does not exist.")
raise FileNotFoundError(f"File {file_path} does not exist.")

new_torrent = Torrent.create_from(file_path)
logger.info(f"Editing torrent file: {file_path} ...")
new_torrent.private = False
new_torrent.announce_urls = ANNOUNCE_URLS
new_torrent.comment = "Created by TensoRaws/AnimePipeline"
new_torrent.created_by = "TensoRaws"
new_torrent.to_file(torrent_file_save_path)

return new_torrent.info_hash
36 changes: 25 additions & 11 deletions animepipeline/loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -243,25 +243,39 @@ async def pipeline_finalrip(self, task_info: TaskInfo) -> None:
async def pipeline_post(self, task_info: TaskInfo) -> None:
task_status = await self.json_store.get_task(task_info.hash)

if self.tg_channel_sender is None:
logger.info("Telegram Channel Sender is not enabled. Skip upload.")
return

# check tg
if task_status.tg_posted:
# check posted
if task_status.posted:
return

if task_status.finalrip_downloaded_path is None:
logger.error("FinalRip download path is None! finalrip download task not finished?")
raise ValueError("FinalRip download path is None! finalrip download task not finished?")

logger.info(f'Post to Telegram Channel for "{task_info.name}" EP {task_info.episode}')
finalrip_downloaded_path = Path(task_info.download_path) / task_status.finalrip_downloaded_path
torrent_file_save_path = Path(task_info.download_path) / (str(finalrip_downloaded_path.name) + ".torrent")

try:
torrent_file_hash = QBittorrentManager.make_torrent_file(
file_path=finalrip_downloaded_path,
torrent_file_save_path=torrent_file_save_path,
)
logger.info(f"Torrent file created: {torrent_file_save_path}, hash: {torrent_file_hash}")
except Exception as e:
logger.error(f"Failed to create torrent file: {e}")
raise e

self.qbittorrent_manager.add_torrent(torrent_hash=torrent_file_hash, torrent_file_path=torrent_file_save_path)

logger.info(f"Post to Telegram Channel for {task_info.name} EP {task_info.episode}")

finalrip_downloaded_path = Path(task_info.download_path) / task_status.finalrip_downloaded_path

await self.tg_channel_sender.send_text(
text=f"{task_info.translation} | EP {task_info.episode} | {finalrip_downloaded_path.name}",
)
if self.tg_channel_sender is None:
logger.info("Telegram Channel Sender is not enabled. Skip upload.")
else:
await self.tg_channel_sender.send_text(
text=f"{task_info.translation} | EP {task_info.episode} | {finalrip_downloaded_path.name} | hash: {torrent_file_hash}"
)

task_status.tg_posted = True
task_status.posted = True
await self.json_store.update_task(task_info.hash, task_status)
2 changes: 1 addition & 1 deletion animepipeline/post/tg.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ def __init__(self, config: TelegramConfig) -> None:
self.bot = Bot(token=config.bot_token)
self.channel_id = config.channel_id

@retry(wait=wait_random(min=3, max=5), stop=stop_after_attempt(5))
@retry(wait=wait_random(min=3, max=15), stop=stop_after_attempt(5))
async def send_text(self, text: str) -> None:
"""
Send text to the channel.
Expand Down
2 changes: 1 addition & 1 deletion animepipeline/store/task.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ class TaskStatus(BaseModel):
done: bool = False
bt_downloaded_path: Optional[str] = None
finalrip_downloaded_path: Optional[str] = None
tg_posted: bool = False
posted: bool = False
ex_status_dict: Optional[Dict[str, Any]] = None


Expand Down
2 changes: 1 addition & 1 deletion animepipeline/util/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
from animepipeline.util.bt import gen_magnet_link # noqa
from animepipeline.util.bt import gen_magnet_link, ANNOUNCE_URLS # noqa
58 changes: 58 additions & 0 deletions animepipeline/util/bt.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,61 @@ def gen_magnet_link(torrent_hash: str) -> str:
:param torrent_hash: The torrent hash.
"""
return f"magnet:?xt=urn:btih:{torrent_hash}"


# bt tracker urls
ANNOUNCE_URLS = [
"http://nyaa.tracker.wf:7777/announce",
"http://open.acgtracker.com:1096/announce",
"http://t.nyaatracker.com:80/announce",
"http://tracker4.itzmx.com:2710/announce",
"https://tracker.nanoha.org/announce",
"http://t.acg.rip:6699/announce",
"https://tr.bangumi.moe:9696/announce",
"http://tr.bangumi.moe:6969/announce",
"udp://tr.bangumi.moe:6969/announce",
"http://open.acgnxtracker.com/announce",
"https://open.acgnxtracker.com/announce",
"udp://open.stealth.si:80/announce",
"udp://tracker.opentrackr.org:1337/announce",
"udp://exodus.desync.com:6969/announce",
"udp://tracker.torrent.eu.org:451/announce",
"udp://tracker.openbittorrent.com:80/announce",
"udp://tracker.publicbt.com:80/announce",
"udp://tracker.prq.to:80/announce",
"udp://104.238.198.186:8000/announce",
"http://104.238.198.186:8000/announce",
"http://94.228.192.98/announce",
"http://share.dmhy.org/annonuce",
"http://tracker.btcake.com/announce",
"http://tracker.ktxp.com:6868/announce",
"http://tracker.ktxp.com:7070/announce",
"http://bt.sc-ol.com:2710/announce",
"http://btfile.sdo.com:6961/announce",
"https://t-115.rhcloud.com/only_for_ylbud",
"http://exodus.desync.com:6969/announce",
"udp://coppersurfer.tk:6969/announce",
"http://tracker3.torrentino.com/announce",
"http://tracker2.torrentino.com/announce",
"udp://open.demonii.com:1337/announce",
"udp://tracker.ex.ua:80/announce",
"http://pubt.net:2710/announce",
"http://tracker.tfile.me/announce",
"http://bigfoot1942.sektori.org:6969/announce",
"udp://bt.sc-ol.com:2710/announce",
"http://1337.abcvg.info:80/announce",
"http://bt.okmp3.ru:2710/announce",
"http://ipv6.rer.lol:6969/announce",
"https://tr.burnabyhighstar.com:443/announce",
"https://tracker.gbitt.info:443/announce",
"https://tracker.gcrenwp.top:443/announce",
"https://tracker.kuroy.me:443/announce",
"https://tracker.lilithraws.org:443/announce",
"https://tracker.loligirl.cn:443/announce",
"https://tracker1.520.jp:443/announce",
"udp://amigacity.xyz:6969/announce",
"udp://bt1.archive.org:6969/announce",
"udp://bt2.archive.org:6969/announce",
"udp://epider.me:6969/announce",
"wss://tracker.openwebtorrent.com:443/announce",
]
Loading