1213 lines
58 KiB
Python
1213 lines
58 KiB
Python
from lib.sonarr import Sonarr_API
|
|
from lib.db import sqlite_db
|
|
from lib.db import Today_Queue_Status
|
|
from lib.discord_bot import ScheduleBot
|
|
from lib.logging_data import logger
|
|
from lib.check_track_detail import check_langs_with_langcodes,extract_file_path
|
|
from lib.torrent_creator import TorrentUpload
|
|
|
|
from dotenv import load_dotenv
|
|
import pytz
|
|
from datetime import datetime
|
|
import discord
|
|
import asyncio
|
|
import requests
|
|
import os
|
|
# from apscheduler.schedulers.background import BackgroundScheduler
|
|
from apscheduler.schedulers.asyncio import AsyncIOScheduler
|
|
|
|
from typing import Callable, Awaitable
|
|
|
|
|
|
class USK_Status:
|
|
def __init__(self):
|
|
self.title=""
|
|
self.check_status = False
|
|
self.check_found = False
|
|
self.check_lang_found = False
|
|
|
|
self.download_status = False
|
|
|
|
self.import_status = False
|
|
self.import_episode: requests.Response | None = None
|
|
|
|
self.torrent_status = False
|
|
|
|
self.message = ""
|
|
self.other_data=""
|
|
|
|
|
|
|
|
class USK(ScheduleBot):
|
|
CODEC_MAP = {
|
|
"265": 'h.265',
|
|
"264": 'h.264',
|
|
"AV1": 'av1'
|
|
}
|
|
QUALITY_MAP = {
|
|
1080: "1080p",
|
|
720: "720p",
|
|
480: "480p",
|
|
360: "360p",
|
|
240: "240p",
|
|
}
|
|
AUDIO_CHANNEL_MAP = {
|
|
'20': "2.0",
|
|
'51': "5.1"
|
|
}
|
|
|
|
def __init__(self,console:logger=None):
|
|
|
|
super().__init__(console=console)
|
|
# print(Path(__file__).resolve() / ".env")
|
|
load_dotenv(".env")
|
|
|
|
self.tz = pytz.timezone("Asia/Bangkok")
|
|
self.console = console
|
|
|
|
self.usk_path = os.getenv("usk_path")
|
|
# print(self.usk_path)
|
|
os.chdir(self.usk_path)
|
|
self.path = os.getenv("db_path")
|
|
self.sonarr_ip = os.getenv("sonarr_ip")
|
|
self.sonarr_key = os.getenv("sonarr_key")
|
|
self.download_path = os.getenv("download_path")
|
|
|
|
self.channel = None
|
|
|
|
self.scheduler = self.scheduler if isinstance( self.scheduler, AsyncIOScheduler) else AsyncIOScheduler()
|
|
self.sonarr = Sonarr_API(self.sonarr_ip, self.sonarr_key)
|
|
|
|
self.db = sqlite_db(self.path)
|
|
|
|
def download_command(self,entry,title_config,check=False):
|
|
cmd = [self.usk_path+".venv/bin/unshackle", 'dl',"--no-cache"]
|
|
|
|
if check:
|
|
# cmd += ['--skip-dl']
|
|
cmd += ['--list']
|
|
else:
|
|
if title_config.get("tmdb_id"):
|
|
cmd += ['--tmdb',title_config["tmdb_id"],"--enrich"]
|
|
|
|
if title_config['absolute']:
|
|
cmd += ['--episode-overwrite',str(int(title_config['absolute'])+int(entry['episode']))]
|
|
if title_config['absolute_season']:
|
|
cmd += ['--season-overwrite',str(int(title_config['absolute_season'])+int(title_config['season']))]
|
|
|
|
if title_config['Service'] in ['HMAX']:
|
|
cmd += ["--cdm-only"]
|
|
|
|
cmd += ['--quality', str(title_config['quality'])]
|
|
cmd += ['--range', title_config['range']]
|
|
cmd += ['--vcodec', self.CODEC_MAP[str(title_config['codec'])]]
|
|
|
|
if title_config['proxy']:
|
|
cmd += ['--proxy', title_config['proxy']]
|
|
else:
|
|
cmd += ['--no-proxy']
|
|
|
|
cmd += ['--v-lang',"all"]
|
|
cmd += ['--a-lang',
|
|
f"{title_config['audio_lang'] if title_config['Service'] not in ["TID","MMAX"] else 'all'}"]
|
|
cmd += ['--s-lang',
|
|
f"{title_config['sub_lang'] if title_config['Service'] not in ["TID","MMAX"] else 'all'}"]
|
|
|
|
if title_config['audio_channel']:
|
|
cmd += ['--channels', self.AUDIO_CHANNEL_MAP[title_config['audio_channel']]]
|
|
|
|
if bool(title_config['worst']):
|
|
cmd += ['--worst']
|
|
|
|
if title_config['video_bitrate']:
|
|
cmd += ['--vbitrate', int(title_config['video_bitrate'])]
|
|
|
|
if entry['season'] or entry['episode']:
|
|
cmd += ['--wanted']
|
|
if entry['season']:
|
|
wanted = f's{entry['season']:02}'
|
|
else:
|
|
wanted = "s01"
|
|
|
|
if entry['episode']:
|
|
if wanted:
|
|
wanted += f'e{entry['episode']:02}'
|
|
else:
|
|
wanted = f'e{entry['episode']:02}'
|
|
|
|
cmd += [wanted]
|
|
|
|
cmd += [title_config['Service']]
|
|
if title_config['Service'] in ['AMZN']:
|
|
cmd += ["https://www.primevideo.com/detail/"+title_config['url']]
|
|
else:
|
|
cmd += [title_config['url']]
|
|
if title_config['Service'] in ['TID']:
|
|
cmd += ['--drm','wv']
|
|
|
|
if title_config['Service'] in ['TID','BLBL']:
|
|
if title_config['season']:
|
|
cmd += ['--season', str(entry['season'])]
|
|
|
|
|
|
if title_config['Service'] in ['OND','LT','BLBL','TID']:
|
|
if title_config['title_lang']:
|
|
cmd += ['--title_lang', title_config['title_lang']]
|
|
|
|
if title_config['Service'] in ['BLBL']:
|
|
# if entry['season']:
|
|
# cmd += ['--season', str(entry['season'])]
|
|
# if title_config['title_lang']:
|
|
# cmd += ['--title_lang', str(title_config['title_lang'])]
|
|
if title_config['url_org']:
|
|
cmd += ['--original_url', title_config['url_org']]
|
|
if title_config['org_lang']:
|
|
cmd += ['--original_lang', str(title_config['org_lang'])]
|
|
return cmd
|
|
async def checking_process(self,entry,title_config,title_schedule,discord_notification=False) -> USK_Status:
|
|
cmd = self.download_command(entry, title_config,check=True)
|
|
self.console.log(" ".join(cmd))
|
|
|
|
status=USK_Status()
|
|
status.title=title_config['Title']
|
|
|
|
stdout, stderr = await self.run_cmd(cmd)
|
|
|
|
# Available Tracks
|
|
# if f"S{entry['season']:02}E{entry['episode']:02}" not in stdout:
|
|
if "Available Tracks" not in stdout:
|
|
# self.console.warn(f"Not found in the list: {title_config['Title']} Episode {entry['season']}x{entry['episode']}")
|
|
status.check_found=False
|
|
status.message=f"Failed to find: {title_config['Title']} Episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Failed to find {title_config['Title']} episode {entry['season']}x{entry['episode']} after multiple attempts.",
|
|
color=discord.Color.red()
|
|
)
|
|
self.console.error(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
else:
|
|
status.check_found=True
|
|
|
|
lang_result=check_langs_with_langcodes(stdout, title_config['audio_lang'].split(','), title_config['sub_lang'].split(','))
|
|
self.console.debug("lang_result :",lang_result)
|
|
if (
|
|
lang_result['audio']['exists_all'] or
|
|
title_config['Service'] in ["IQ"]
|
|
) \
|
|
and \
|
|
(lang_result['subtitle']['exists_all'] or
|
|
### Skip checking Thai subtitle that is Thai original
|
|
(title_config['audio_lang']=="th" and title_config['sub_lang']=="th")):
|
|
|
|
status.check_lang_found=True
|
|
# embed = discord.Embed(
|
|
# title=f"Found in the list: {title_config['Title']} Episode {entry['season']}x{entry['episode']}",
|
|
# description=f"Starting download for {title_config['Title']} - {entry['season']}x{entry['episode']}",
|
|
# color=discord.Color.green()
|
|
# )
|
|
# # embed.add_field(
|
|
# # name=f"Episode {entry['season']}x{entry['episode']} found in the list",
|
|
# # value=f"Starting download for {title_config['Title']} - {entry['season']}x{entry['episode']}",
|
|
# # inline=False
|
|
# # )
|
|
# # if self.channel:
|
|
# # await self.channel.send(embed=embed)
|
|
# status.message=f"{title_config['Title']} Episode {entry['season']}x{entry['episode']} found in the list"
|
|
# self.console.log(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
else:
|
|
status.message=f"Found but language requirements not met: {title_config['Title']} Episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Found episode but language requirements not met",
|
|
color=discord.Color.orange()
|
|
)
|
|
embed.add_field(
|
|
name="Audio Language Check",
|
|
value=f"Configured: {', '.join(lang_result['audio']['configured'])}\nFound: {', '.join(lang_result['audio']['found_langs'])}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Subtitle Language Check",
|
|
value=f"Configured: {', '.join(lang_result['subtitle']['configured'])}\nFound: {', '.join(lang_result['subtitle']['found_langs'])}",
|
|
inline=False
|
|
)
|
|
status.check_lang_found=False
|
|
|
|
self.console.error(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
status.check_status = True if status.check_found and status.check_lang_found else False
|
|
self.console.debug("Checking status:", status.__dict__)
|
|
return status
|
|
|
|
async def download_process(self,entry,waiting_minute:int=15,discord_notification:bool=True,retry_count=40) -> USK_Status:
|
|
|
|
title_config= self.db.find_title_config_db(entry['title'])
|
|
title_schedule=self.db.get_show_by_title(entry['title'])[0]
|
|
|
|
self.console.debug("Entry:", entry)
|
|
self.console.debug("Title Config:", title_config)
|
|
self.console.debug("Title Schedule:", title_schedule)
|
|
|
|
status=USK_Status()
|
|
|
|
today_queue_status = Today_Queue_Status()
|
|
|
|
status.message=f"Checking: {title_config['Title']} - {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.blue()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
embed.add_field(
|
|
name="Command",
|
|
value=" ".join(self.download_command(entry, title_config,check=True)),
|
|
inline=False
|
|
)
|
|
|
|
self.console.log(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
count=0
|
|
############ CHECKING ############
|
|
# self.console.debug("Checking status:", status.__dict__)
|
|
while not status.check_status :
|
|
|
|
status = await self.checking_process(entry,title_config,title_schedule,discord_notification)
|
|
|
|
if status.check_status or count>=retry_count:
|
|
break
|
|
|
|
status.message=f"Waiting {waiting_minute} minute before checking again for {entry['title']} episode {entry['season']}x{entry['episode']} to be available in the list"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.yellow()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
|
|
self.console.debug("Checking status:", status.__dict__)
|
|
self.console.warn(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
self.db.update_download_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.waiting)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.waiting)
|
|
count+=1
|
|
await asyncio.sleep(waiting_minute * 60)
|
|
|
|
|
|
|
|
if status.check_status:
|
|
status.message=f"Found in the list: {title_config['Title']} Episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Starting download for {title_config['Title']} - {entry['season']}x{entry['episode']}",
|
|
color=discord.Color.green()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
|
|
self.console.log(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
self.db.update_download_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.search_found)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.search_found)
|
|
# return status
|
|
|
|
elif not status.check_status:
|
|
status.message=f"Finish searching but not found: {title_config['Title']} Episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Starting download for {title_config['Title']} - {entry['season']}x{entry['episode']}",
|
|
color=discord.Color.red()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
|
|
self.console.log(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
self.db.update_download_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.failed_search)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.failed_search)
|
|
return status
|
|
|
|
self.console.debug("Checked results:", status.__dict__)
|
|
############ CHECKED ############
|
|
|
|
############ DOWNLOADING ############
|
|
# self.console.debug("Downloading status:", status.__dict__)
|
|
self.db.update_download_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.downloading)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.downloading)
|
|
cmd=self.download_command(entry, title_config)
|
|
|
|
status.message=f"Downloading: {title_config['Title']} - {entry['season']}x{entry['episode']}"
|
|
embed.clear_fields()
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.blue()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
embed.add_field(
|
|
name="Command",
|
|
value=" ".join(cmd),
|
|
inline=False
|
|
)
|
|
|
|
self.console.log( status.message, is_gotify=False , is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
self.console.debug("Download command:", " ".join(cmd))
|
|
|
|
stdout, stderr = await self.run_cmd(cmd)
|
|
|
|
final_file_path=extract_file_path(stdout)
|
|
|
|
if any(x in stdout for x in ['[E]']) or "Processed all titles" not in stdout or not final_file_path:
|
|
|
|
self.db.update_download_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.failed_download)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.failed_download)
|
|
|
|
status.message=f"Download failed: {title_config['Title']} - {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.red()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
# await self.channel.send(embed=embed)
|
|
status.download_status=False
|
|
status.message+=f"\n{stdout}"
|
|
self.console.error(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
return status
|
|
else:
|
|
self.db.update_schedule_episode(title_config['Title'], entry['episode'])
|
|
|
|
status.download_status=True
|
|
status.message=f"Download completed: {title_config['Title']} - {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.green()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
self.console.log(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {} )
|
|
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.downloaded)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.downloaded)
|
|
|
|
self.console.debug("Download status:", status.__dict__)
|
|
############ DOWNLOADED ############
|
|
|
|
############ IMPORTING ############
|
|
# self.console.debug(status.__dict__)
|
|
try:
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.importing)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.importing)
|
|
ep_info=self.sonarr.get_episodes(final_file_path)
|
|
ep_import = self.sonarr.import_episodes(entry,title_config,ep_info,mode="move")
|
|
self.console.debug("Import results:", ep_import)
|
|
if len(ep_import) == 0 :
|
|
status.import_status=False
|
|
status.message=f"Failed to import: {entry['title']} episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.red()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
self.console.error(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.failed_import)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.failed_import)
|
|
return status
|
|
for ep in ep_import:
|
|
if ep.status_code == 201:
|
|
status.import_status=True
|
|
status.message=f"Imported successfully: Episode {entry['title']} {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
color=discord.Color.green()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
self.console.log(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.imported)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.imported)
|
|
status.import_episode=ep
|
|
break
|
|
else:
|
|
status.import_status=False
|
|
status.message=f"Failed to import: {entry['title']} episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
color=discord.Color.red()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
self.console.error(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.failed_import)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.failed_import)
|
|
return status
|
|
|
|
except Exception as e:
|
|
status.import_status=False
|
|
status.message=f"Failed to import: {entry['title']} episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
color=discord.Color.red()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
status.message+=f"\n{e}"
|
|
self.console.error(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.failed_import)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.failed_import)
|
|
############ IMPORTED ############
|
|
|
|
############ CHECK IF LAST EPISODE ############
|
|
self.console.debug("Checking status:", status.__dict__)
|
|
self.console.debug("Show details:", self.db.get_show_by_title(title_config['Title']))
|
|
if int(entry['episode']) == int(self.db.get_show_by_title(title_config['Title'])[0]["end_ep"]):
|
|
status.message=f"Last EPISODE of SEASON: {title_config['Title']} - {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.pink()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
self.console.log(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {} )
|
|
############ CHECK IF LAST EPISODE ############
|
|
|
|
############ TORRENTING ############
|
|
# self.console.debug(status.__dict__)
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.downloaded)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.downloaded)
|
|
torrent_detail=self.db.get_torrent_detail(entry['title'])
|
|
if not torrent_detail or torrent_detail['enable']==0 or not status.import_episode :
|
|
### if not torrenting return to exit
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.completed)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.completed)
|
|
return status
|
|
|
|
status.message=f"Creating torrent: {entry['title']} episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.blue()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
self.console.log(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
await asyncio.sleep(5)
|
|
self.console.debug("Import results:", status.import_episode.json())
|
|
for imported_ep in status.import_episode.json()['body']['files']:
|
|
sonarr_import_count=0
|
|
sonarr_found=False
|
|
|
|
# sonarr_seriesId=imported_ep['seriesId']
|
|
sonarr_episodeIds=imported_ep['episodeIds'][0]
|
|
while not sonarr_found :
|
|
sonarr_import_count+=1
|
|
try:
|
|
sonarr_ep_detail=self.sonarr.get_episode_detail(sonarr_episodeIds)
|
|
self.console.debug("Sonarr episode details:", sonarr_ep_detail)
|
|
|
|
sonarr_ep_path=sonarr_ep_detail['episodeFile']['path']
|
|
sonarr_found=True
|
|
break
|
|
except KeyError as e:
|
|
|
|
if sonarr_import_count < 10:
|
|
self.console.warn("Sonarr not complete import yet. Wait for 10 seconds and try again.")
|
|
await asyncio.sleep(10)
|
|
else:
|
|
status.message=f"Failed to Create torrent: {entry['title']} episode {entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
# description=f"Air time: {title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
color=discord.Color.red()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
embed.add_field(
|
|
name="Sonarr error",
|
|
value="Sonarr not found file path. Try to inspect file in Sonarr and try again",
|
|
inline=False
|
|
)
|
|
status.message+=f"\n{e}"
|
|
self.console.error(status.message,is_gotify=False,is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
# if not sonarr_found and sonarr_import_count >= 10:
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.fail_upload)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.fail_upload)
|
|
return status
|
|
|
|
if int( torrent_detail['last_ep'] or 0)==int(sonarr_episodeIds) or torrent_detail['enable']==0:
|
|
continue
|
|
|
|
if len(status.import_episode.json()['body']['files'])>1:
|
|
status.message=f"Failed to Create torrent: {entry['title']} episode {entry['season']}x{entry['episode']} : Found more than 1 file for episode."
|
|
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
color=discord.Color.red()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.fail_upload)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.fail_upload)
|
|
self.console.error(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
return status
|
|
|
|
upload_entry={
|
|
'file_path':sonarr_ep_path,
|
|
'imdb_id':torrent_detail['imdb'],
|
|
'tmdb_id':torrent_detail['tmdb'],
|
|
'category':torrent_detail['category'],
|
|
'source_type':torrent_detail['source_type'],
|
|
'source':torrent_detail['source'],
|
|
'country':torrent_detail['country'],
|
|
'original_platform':torrent_detail['original_platform'],
|
|
'is_subdir':False,
|
|
'bearbit':True,
|
|
'torrentdd':True,
|
|
'is_movie':False,
|
|
'pack':False
|
|
}
|
|
try:
|
|
"""
|
|
Stop previous episode before adding a new one
|
|
|
|
Some releases are updated later (e.g., Thai dub added).
|
|
Example:
|
|
Old: S01E10 | Audio: JPN
|
|
New: S01E10 | Audio: JPN,THA
|
|
|
|
The new torrent replaces the old one.
|
|
To avoid qBittorrent file conflicts or missing file issues,
|
|
we must stop the existing torrent (same episode) before adding the new one.
|
|
|
|
Additionally, stop the previous episode (e.g., S01E09),
|
|
since seeding is only required for about one week.
|
|
"""
|
|
|
|
torrentupload=TorrentUpload(console=self.console)
|
|
await torrentupload.qbit.login()
|
|
stop_previous_episode=await torrentupload.qbit.stop_previous_episode_torrent(tmdb_id=torrent_detail['tmdb'],entry=entry,title_config=title_config,prv_count=1)
|
|
|
|
if not stop_previous_episode:
|
|
status.message= f"Some of Episode has problem when stopping torrent: {entry['title']} episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
color=discord.Color.orange()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
self.console.warn(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
|
|
# await torrentupload.qbit.stop_torrent(search_string=torrent_detail["qbit_name"])
|
|
################################################
|
|
|
|
upload_status: dict[str,list] = await torrentupload.upload_torrent(upload_entry,qbit_category="SeFree-Automate",super_seed=False,seedingTimeLimit=10080)
|
|
self.console.debug("Upload status:", upload_status)
|
|
if not (any(item['status'] is False for item in upload_status['bearbit']) or any(item['status'] is False for item in upload_status['torrentdd'])) and \
|
|
len(upload_status['bearbit'] ) > 0 and len(upload_status['torrentdd']) >0:
|
|
status.message=f"Torrent Upload Completed: {entry['title']} episode {entry['season']}x{entry['episode']}"
|
|
|
|
embed = discord.Embed(
|
|
title="Torrent Upload Completed",
|
|
description="All torrents have been created and uploaded successfully.",
|
|
color=discord.Color.green()
|
|
)
|
|
bb_text=""
|
|
for staBB in upload_status['bearbit']:
|
|
bb_text+=f"{"Uploaded" if staBB["status"] else "Fail Upload"} : [{staBB["name"]}]({staBB["url"]})"
|
|
bb_text+="\n"
|
|
# bb_text+=staBB["url"]
|
|
# bb_text+="\n"
|
|
embed.add_field(name="BearBit", value=bb_text, inline=False)
|
|
|
|
dd_text=""
|
|
for staDD in upload_status['torrentdd']:
|
|
dd_text+=f"{"Uploaded" if staDD["status"] else "Fail Upload"} : [{staDD["name"]}]({staDD["url"]})"
|
|
dd_text+="\n"
|
|
# dd_text+=staDD["url"]
|
|
# dd_text+="\n"
|
|
embed.add_field(name="TorrentDD", value=dd_text, inline=False)
|
|
embed.set_footer(text="Thank you for visiting!")
|
|
# self.console.debug("Upload status:", upload_status)
|
|
self.console.log(status.message,is_discord={"channel": self.channel,"embed": embed,"web_hook_urls":os.getenv('torrent_update_webhook').split(",")})
|
|
|
|
qbit_name=next(
|
|
(item["name"]
|
|
for items in upload_status.values()
|
|
for item in items
|
|
if item.get("name")),
|
|
None
|
|
)
|
|
|
|
self.db.update_torrent_detail(entry['title'],qbit_name,sonarr_episodeIds)
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.uploaded)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.uploaded)
|
|
|
|
# return status
|
|
else:
|
|
raise Exception("Error during create torrent")
|
|
except Exception as e:
|
|
status.message=f"Fail to Create torrent: {entry['title']} episode {entry['season']}x{entry['episode']}"
|
|
embed = discord.Embed(
|
|
title=status.message,
|
|
color=discord.Color.red()
|
|
)
|
|
embed.add_field(
|
|
name="Air time:",
|
|
value=f"{title_schedule["day_of_week"]} {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
embed.add_field(
|
|
name="Timestamp",
|
|
value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
inline=True
|
|
)
|
|
status.message+=f"\n{e}"
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.fail_upload)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.fail_upload)
|
|
self.console.error(status.message, is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if discord_notification else {})
|
|
return status
|
|
|
|
self.db.update_download_status(title_config['Title'],entry['season'], entry['episode'], today_queue_status.completed)
|
|
self.db.update_download_history_status(title_config['Title'], entry['season'], entry['episode'], today_queue_status.completed)
|
|
return status
|
|
|
|
|
|
@staticmethod
|
|
async def run_cmd(cmd):
|
|
process = await asyncio.create_subprocess_exec(
|
|
*cmd,
|
|
stdout=asyncio.subprocess.PIPE,
|
|
stderr=asyncio.subprocess.PIPE
|
|
)
|
|
stdout, stderr = await process.communicate()
|
|
return stdout.decode(errors='replace') if stdout else None , stderr.decode(errors='replace') if stderr else None
|
|
|
|
# @staticmethod
|
|
# async def already_in_queue(entrys:list[dict],func: Callable[..., Any]) :
|
|
# # with open('entrys.json','w') as f:
|
|
# # json.dump(entrys,f,indent=4)
|
|
# # exit()
|
|
# for entry in entrys:
|
|
|
|
# await func(entry,discord_notification=True)
|
|
# # await VT.download_process(entry,discord_notification=True)
|
|
@staticmethod
|
|
async def already_in_queue(
|
|
entries: list[dict],
|
|
func: Callable[..., Awaitable[bool]],
|
|
*,
|
|
retry_delay: float = 15*60, #900
|
|
max_retry: int | None = 40
|
|
):
|
|
pending = entries.copy()
|
|
attempt = 0
|
|
|
|
while pending:
|
|
attempt += 1
|
|
# print(f"Attempt {attempt}, pending = {len(pending)}")
|
|
|
|
next_round = []
|
|
|
|
for entry in pending:
|
|
ok = False
|
|
# try:
|
|
status:USK_Status = await func(entry,waiting_minute=0,retry_count=0, discord_notification=True)
|
|
# print(status.check_status)
|
|
ok = status.check_status and status.download_status
|
|
# if not ok:
|
|
# ok=False
|
|
# else:
|
|
# ok=True
|
|
# except Exception as e:
|
|
# print("Exception:", e)
|
|
# ok = False
|
|
|
|
if not ok:
|
|
next_round.append(entry)
|
|
|
|
if not next_round:
|
|
# print("All entries succeeded")
|
|
return True
|
|
|
|
if max_retry and attempt >= max_retry:
|
|
# print("Retry limit reached")
|
|
return False
|
|
|
|
pending = next_round
|
|
await asyncio.sleep(retry_delay)
|
|
|
|
|
|
def add_shows_jobs(self) -> None:
|
|
|
|
entrys=[]
|
|
today_queue_status=Today_Queue_Status()
|
|
for i,entry in enumerate(self.db.get_today_queue()):
|
|
|
|
if entry['status'] in [today_queue_status.downloaded,
|
|
# today_queue_status.failed_download,
|
|
today_queue_status.importing,
|
|
today_queue_status.failed_import,
|
|
today_queue_status.imported,
|
|
today_queue_status.completed,
|
|
today_queue_status.uploading,
|
|
today_queue_status.uploaded,
|
|
today_queue_status.fail_upload
|
|
]:
|
|
continue
|
|
|
|
timestamp = entry['start_timestamp'] #+(60*5)
|
|
|
|
if datetime.now(self.tz).timestamp() > entry['start_timestamp']:
|
|
timestamp = datetime.now(self.tz).timestamp() + (60*i)
|
|
entrys.append(entry)
|
|
continue
|
|
|
|
self.console.log(f"Scheduling download for {entry['title']} - {entry['season']}x{entry['episode']} at {datetime.fromtimestamp(timestamp)}", is_gotify=False)
|
|
|
|
# embed = discord.Embed(
|
|
# title=f"Scheduling download for {entry['title']} - {entry['season']}x{entry['episode']}",
|
|
# description=f"Start Time: {datetime.fromtimestamp(timestamp, self.tz).strftime('%Y-%m-%d %H:%M:%S')}",
|
|
# color=discord.Color.blue()
|
|
# )
|
|
# if self.channel:
|
|
# self.channel.send(embed=embed)
|
|
|
|
self.scheduler.add_job(
|
|
self.download_process,
|
|
|
|
# args=(entry,waiting_minute,discord_notification,retry_count),
|
|
kwargs={
|
|
"entry":entry,
|
|
"discord_notification":True,
|
|
"retry_count":20
|
|
},
|
|
trigger='date',
|
|
run_date=datetime.fromtimestamp(timestamp),
|
|
id=f"{entry['title']}_{entry['season']}_{entry['episode']}",
|
|
replace_existing=True
|
|
)
|
|
if len(entrys)<1:
|
|
return
|
|
|
|
self.scheduler.add_job(
|
|
self.already_in_queue,
|
|
# args=(entry,self.download_process),
|
|
kwargs={
|
|
"entries":entrys,
|
|
"func":self.download_process,
|
|
# "retry_delay":15*60 if entry['status'] is not today_queue_status.failed_download else 0,
|
|
"max_retry":20 #if entry['status'] is not today_queue_status.failed_download else 0
|
|
},
|
|
trigger='date',
|
|
run_date=datetime.fromtimestamp(datetime.now(self.tz).timestamp()+60),
|
|
id="Already Aired",
|
|
replace_existing=True
|
|
)
|
|
|
|
|
|
async def daily_job(self,is_clear_queue:bool=False,overwrite:bool=True) -> discord.Embed:
|
|
|
|
self.db.add_today_queue([],True) if is_clear_queue else None
|
|
|
|
# self.scheduler.shutdown(wait=False)
|
|
# self.scheduler.remove_all_jobs()
|
|
|
|
embed = discord.Embed(
|
|
title="Daily Job",
|
|
description="Starting daily job to fetch today's schedule and add it to the queue.",
|
|
color=discord.Color.blue()
|
|
)
|
|
|
|
today_schedule = self.db.get_today_schedule()
|
|
|
|
today_queue_db=self.db.get_today_queue()
|
|
|
|
for entry in today_schedule:
|
|
if not (any(entry['title'] == x['title'] for x in today_queue_db) and
|
|
any(entry['episode'] == x['episode'] for x in today_queue_db) and
|
|
any(entry['season'] == x['season'] for x in today_queue_db)):
|
|
|
|
self.db.add_today_queue([entry],False)
|
|
self.db.add_download_history([entry],False)
|
|
|
|
self.console.log(f"Adding season {entry['season']} episode {entry['episode']} of {entry['title']} to queue", is_gotify=False)
|
|
|
|
embed.add_field(
|
|
name=f"Adding season {entry['season']} episode {entry['episode']} of {entry['title']} to queue",
|
|
value=f"Air time: {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%Y-%m-%d %H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
# embed.add_field(
|
|
# name="Timestamp",
|
|
# value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
# inline=False
|
|
# )
|
|
|
|
else:
|
|
|
|
# if self.get_download_status(entry['title'], entry['season']) == 'completed':
|
|
|
|
# if any(x["status"] =='completed' or 'import' in x["status"] for x in self.get_download_status(entry['title'], entry['season'])):
|
|
if self.db.get_download_status(entry['title'], entry['season'], entry['episode']) in ['completed','uploaded']:
|
|
self.console.log(f"Episode {entry['episode']} season {entry['season']} of {entry['title']} already completed, skipping", is_gotify=False)
|
|
|
|
embed.add_field(
|
|
name=f"Episode {entry['episode']} season {entry['season']} of {entry['title']} already completed, skipping",
|
|
value=f"Air time: {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%Y-%m-%d %H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
# embed.add_field(
|
|
# name="Timestamp",
|
|
# value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
# inline=False
|
|
# )
|
|
|
|
else:
|
|
self.console.warn(f"Already in queue but not complete. Adding season {entry['season']} episode {entry['episode']} of {entry['title']} to queue", is_gotify=False)
|
|
|
|
embed.add_field(
|
|
name=f"Already in queue but not complete. Adding season {entry['season']} episode {entry['episode']} of {entry['title']} to queue",
|
|
value=f"Air time: {datetime.fromtimestamp(entry['start_timestamp'], self.tz).strftime('%Y-%m-%d %H:%M:%S')}",
|
|
inline=False
|
|
)
|
|
# embed.add_field(
|
|
# name="Timestamp",
|
|
# value=datetime.now(self.tz).strftime('%Y-%m-%d %H:%M:%S'),
|
|
# inline=False
|
|
# )
|
|
self.db.add_today_queue([entry],False,True)
|
|
self.db.add_download_history([entry],False)
|
|
|
|
# if self.channel:
|
|
# await self.channel.send(embed=embed)
|
|
|
|
self.add_shows_jobs()
|
|
if self.scheduler.state != 1: # If the scheduler is not running
|
|
self.scheduler.start()
|
|
|
|
self.console.log("Daily job completed", is_gotify=False, is_discord={"channel": self.channel,"embed": embed} if self.channel else {})
|
|
|
|
return embed
|
|
|
|
async def recheck_day(self,weekday:int,interaction: discord.Interaction) -> None:
|
|
weekday_map = {
|
|
'Monday': 1,
|
|
'Tuesday': 2,
|
|
'Wednesday': 3,
|
|
'Thursday': 4,
|
|
'Friday': 5,
|
|
'Saturday': 6,
|
|
'Sunday': 7,
|
|
'All':8
|
|
}
|
|
self.channel = self.get_channel(interaction.channel_id)
|
|
|
|
# watchlist=self.db.get_watchlist()
|
|
recheck_list=[]
|
|
|
|
if weekday != 8:
|
|
for entry in self.db.get_show_by_date(weekday):
|
|
result = self.db.find_title_config_db(entry['title'])
|
|
if entry['last_ep'] >= entry['end_ep']:
|
|
continue
|
|
for dow in entry['day_of_week'].split(','):
|
|
if weekday != weekday_map[dow.strip()]:
|
|
continue
|
|
|
|
timestamp = int(datetime.now().replace(hour=int(entry['air_time'][:2]), minute=int(entry['air_time'][2:]), second=0, microsecond=0).timestamp())
|
|
|
|
for i in range(entry['multi_release']):
|
|
|
|
detail ={
|
|
"title": result['Title'],
|
|
"season": int(result['season']) if isinstance(result['season'], int) else 1,
|
|
"episode": ((int(entry['last_ep'])) if entry['last_ep'] is not None else 0) +i+1,
|
|
"sonarr_id": result['ID'],
|
|
"air_time": entry['air_time'],
|
|
"day_of_week": entry['day_of_week'],
|
|
"offset": entry['offset'],
|
|
"start_timestamp":timestamp + (60*(i*5))
|
|
}
|
|
|
|
# print(detail)
|
|
recheck_list.append(detail)
|
|
else:
|
|
for k,v in weekday_map.items():
|
|
if k == "All":
|
|
continue
|
|
for entry in self.db.get_show_by_date(v):
|
|
result = self.db.find_title_config_db(entry['title'])
|
|
if entry['last_ep'] >= entry['end_ep']:
|
|
continue
|
|
for dow in entry['day_of_week'].split(','):
|
|
if v != weekday_map[dow.strip()]:
|
|
continue
|
|
|
|
timestamp = int(datetime.now().replace(hour=int(entry['air_time'][:2]), minute=int(entry['air_time'][2:]), second=0, microsecond=0).timestamp())
|
|
|
|
for i in range(entry['multi_release']):
|
|
|
|
detail ={
|
|
"title": result['Title'],
|
|
"season": int(result['season']) if isinstance(result['season'], int) else 1,
|
|
"episode": ((int(entry['last_ep'])) if entry['last_ep'] is not None else 0) +i+1,
|
|
"sonarr_id": result['ID'],
|
|
"air_time": entry['air_time'],
|
|
"day_of_week": entry['day_of_week'],
|
|
"offset": entry['offset'],
|
|
"start_timestamp":timestamp + (60*(i*5))
|
|
}
|
|
|
|
# print(detail)
|
|
recheck_list.append(detail)
|
|
|
|
if len(recheck_list)<1:
|
|
return
|
|
|
|
async def recheck_queue(entrys:list[dict]) :
|
|
for entry in entrys:
|
|
await self.download_process(entry,0,discord_notification=True,retry_count=0)
|
|
# self.scheduler.add_job(
|
|
# recheck_queue,
|
|
# args=(recheck_list,),
|
|
# trigger='date',
|
|
# run_date=datetime.fromtimestamp(datetime.now(self.tz).timestamp()+60),
|
|
# id=f"Recheck_{weekday_map[weekday]}",
|
|
# replace_existing=True
|
|
# )
|
|
# if self.scheduler.state != 1: # If the scheduler is not running
|
|
# self.scheduler.start()
|
|
await recheck_queue(recheck_list)
|
|
|
|
async def recheck_Title(self,title:str,interaction: discord.Interaction,season=None,episode=None) -> None:
|
|
|
|
self.channel = self.get_channel(interaction.channel_id)
|
|
|
|
# watchlist=self.db.get_watchlist()
|
|
recheck_list=[]
|
|
for entry in self.db.get_show_by_title(title):
|
|
|
|
result = self.db.find_title_config_db(entry['title'])
|
|
|
|
if entry['last_ep'] > entry['end_ep']:
|
|
continue
|
|
|
|
|
|
timestamp = int(datetime.now().replace(hour=int(entry['air_time'][:2]), minute=int(entry['air_time'][2:]), second=0, microsecond=0).timestamp())
|
|
|
|
for i in range(entry['multi_release']):
|
|
|
|
detail ={
|
|
"title": result['Title'],
|
|
"season": season or int(result['season']) if isinstance(result['season'], int) else 1,
|
|
"episode": (episode or 0)+i or (((int(entry['last_ep'])) if entry['last_ep'] is not None else 0) +i+1),
|
|
"sonarr_id": result['ID'],
|
|
"air_time": entry['air_time'],
|
|
"day_of_week": entry['day_of_week'],
|
|
"offset": entry['offset'],
|
|
"start_timestamp":timestamp + (60*(i*5))
|
|
}
|
|
|
|
recheck_list.append(detail)
|
|
if len(recheck_list)<1:
|
|
return
|
|
async def recheck_queue(entrys:list[dict]) :
|
|
for entry in entrys:
|
|
await self.download_process(entry,0,discord_notification=True,retry_count=0)
|
|
|
|
|
|
# self.scheduler.add_job(
|
|
# recheck_queue,
|
|
# args=(recheck_list,),
|
|
# trigger='date',
|
|
# run_date=datetime.fromtimestamp(datetime.now(self.tz).timestamp()+60),
|
|
# id=f"Recheck_{weekday_map[weekday]}",
|
|
# replace_existing=True
|
|
# )
|
|
# if self.scheduler.state != 1: # If the scheduler is not running
|
|
# self.scheduler.start()
|
|
await recheck_queue(recheck_list)
|
|
|
|
async def set_today_schedule(self,interaction: discord.Interaction) -> None:
|
|
# tomorrow = datetime.now(self.tz) + timedelta(days=1)
|
|
# tomorrow = tomorrow.strftime('%Y_%m_%d')
|
|
# hour_now = int(datetime.now(self.tz).strftime('%H'))
|
|
minute_now = int(datetime.now(self.tz).strftime('%M'))
|
|
self.channel = self.get_channel(interaction.channel_id)
|
|
await self.daily_job(False)
|
|
# if self.channel:
|
|
# await self.channel.send(embed=embed)
|
|
|
|
self.scheduler.add_job( self.daily_job,args=(True,),trigger='cron', hour=0, minute=0 if not minute_now > 59 else 0, id="daily_midnight_job", replace_existing=True)
|
|
|
|
# embed = discord.Embed(
|
|
# title="Today's Schedule",
|
|
# description="Today's schedule has been set and the download jobs have been added.",
|
|
# color=discord.Color.green()
|
|
# )
|
|
# for job in self.scheduler.get_jobs():
|
|
# if job.id == 'today_queue':
|
|
# continue
|
|
# embed.add_field(name=job.id, value=f"Scheduled for {job.next_run_time.astimezone(self.tz).strftime('%Y-%m-%d %H:%M:%S')}", inline=False)
|
|
# channel = bot.get_channel(interaction.channel_id)
|
|
# await channel.send(embed=embed)
|
|
|
|
|
|
if __name__ == "__main__":#
|
|
# import time
|
|
import logging
|
|
|
|
# current_epoch_time = int(time.time())
|
|
|
|
console = logger(app_name="scheduler",log_dir="./log",discord_config=os.getenv('DISCORD_CHANNEL_ID'),level=logging.DEBUG)
|
|
# console.log("Starting VT Schedule Bot...")
|
|
|
|
usk_scheduler = USK(console)
|
|
console.client=usk_scheduler
|
|
|
|
async def main():
|
|
Entry= {'title': 'Fire Force', 'season': 3, 'episode': 25, 'sonarr_id': 1326, 'air_time': '1235', 'day_of_week': 'Saturday', 'offset': 0, 'start_timestamp': 1774762500}
|
|
# Entry= {'title': 'Fate/strange Fake', 'season': 1, 'episode': 14, 'sonarr_id': 1107, 'air_time': '2330', 'day_of_week': 'Saturday', 'offset': 0, 'start_timestamp': 1774801800}
|
|
# Entry={'title': 'Dead Account', 'season': 1, 'episode': 13, 'sonarr_id': 1078, 'air_time': '2200', 'day_of_week': 'Saturday', 'offset': 0, 'start_timestamp': 1774796400}
|
|
await usk_scheduler.download_process(Entry,discord_notification=True)
|
|
|
|
asyncio.run(main()) |