diff --git a/Dockerfile b/Dockerfile index f31684d..8f43c2b 100644 --- a/Dockerfile +++ b/Dockerfile @@ -48,7 +48,7 @@ ENV PIP_ROOT_USER_ACTION ignore # USER dockeruser ENV USER_NAME dockeruser -ENV VERSION "1.8.3" +ENV VERSION "1.8.4" EXPOSE 5000 diff --git a/config/job.py b/config/job.py index 59ab4e5..2be5a21 100644 --- a/config/job.py +++ b/config/job.py @@ -1,3 +1,4 @@ +import threading import time import requests @@ -52,12 +53,19 @@ def job(): logger.warning(txt.EPISODE_DOWNLOAD_LOG.format(season=episode["season"], episode=episode["num"]) + '\n') title = f'{anime["title"]} - S{episode["season"]}E{episode["num"]}' + + # thread args + opt = [] + thargs = {"active": True, "epId": episode["ID"]} + + threading.Thread(target=fun.downloadControl, args=(thargs, opt)).start() + file = ep.download(title, DOWNLOAD_FOLDER, hook=fun.downloadProgress, opt=opt) + + thargs['active'] = False - file = ep.download(title, DOWNLOAD_FOLDER, fun.downloadProgress) if file: logger.info(txt.DOWNLOAD_COMPLETED_LOG + '\n') - if Settings.data["MoveEp"]: logger.info(txt.EPISODE_SHIFT_LOG.format(season=episode["season"], episode=episode["num"], folder=anime["path"]) + '\n') if fun.movefile(os.path.join(DOWNLOAD_FOLDER,file), anime["path"]): @@ -83,7 +91,9 @@ def job(): logger.info(txt.SEND_CONNECTION_MESSAGE_LOG + '\n') message.warning(txt.CONNECTION_MESSAGE.format(title=anime["title"], season=episode["season"], episode=episode["num"], episodeTitle=episode["title"])) - + else: + if 'abort' in opt: # Se il download è stato abortito + logger.info(txt.EPISODE_ALREADY_IN_DOWNLOADING_LOG + '\n') break else: logger.info(txt.EPISODE_UNAVAILABLE_LOG + '\n') diff --git a/config/other/exceptions.py b/config/other/exceptions.py index eb412e5..44946d7 100644 --- a/config/other/exceptions.py +++ b/config/other/exceptions.py @@ -6,5 +6,6 @@ def __init__(self): super().__init__(self.message) class UnauthorizedSonarr(Exception): + """Errore accesso a Sonarr.""" def __init__(self, message): super().__init__(message) \ No newline at end of file diff --git a/config/other/texts.py b/config/other/texts.py index 6b3d0ab..55b348d 100644 --- a/config/other/texts.py +++ b/config/other/texts.py @@ -64,6 +64,7 @@ EPISODE_RENAME_ERROR_LOG = "⚠️ NON è stato possibile rinominare l'episodio." SEND_CONNECTION_MESSAGE_LOG = "✉️ Inviando il messaggio tramite 𝗰𝗼𝗻𝗻𝗲𝗰𝘁𝗶𝗼𝗻𝘀." NO_EPISODES = "Non c'è nessun episodio da cercare." +EPISODE_ALREADY_IN_DOWNLOADING_LOG = "🔒 L'episodio è già in download su Sonarr." AUTOMATIC_LINK_SEARCH_LOG = "⚠️ Ricerca automatica link di AnimeWorld per la 𝘴𝘵𝘢𝘨𝘪𝘰𝘯𝘦 {season} della 𝘴𝘦𝘳𝘪𝘦 '{anime}'." ABSOLUTE_AUTOMATIC_LINK_SEARCH_ERROR_LOG = "⛔ La ricerca automatica link di AnimeWorld è incompatibile con le serie ad ordinamento assoluto." diff --git a/config/utility/functions.py b/config/utility/functions.py index efd7ca1..d8be0c6 100644 --- a/config/utility/functions.py +++ b/config/utility/functions.py @@ -7,6 +7,7 @@ import shutil from datetime import datetime from typing import Dict, List +import time from app import socketio @@ -14,6 +15,7 @@ from .table import Table from .logger import logger, message from .settings import Settings +from . import sonarr import other.texts as txt from other.exceptions import TableFormattingError @@ -278,4 +280,20 @@ def downloadProgress(d): socketio.emit("download_info", d, broadcast=True) downloadProgress.step = datetime.timestamp(datetime.now()) -downloadProgress.step = datetime.timestamp(datetime.now()) \ No newline at end of file +downloadProgress.step = datetime.timestamp(datetime.now()) + +def downloadControl(args: Dict[str,str], opt: List[str]): + """ + Controlla il download del file. + `opt`: opzioni da modificare. + `args`: { + active: bool + epId: int + } + """ + + while args["active"]: + if sonarr.inQueue(args["epId"]): + opt.append('abort') + return + time.sleep(60) diff --git a/config/utility/sonarr.py b/config/utility/sonarr.py index e7900dc..c76af73 100644 --- a/config/utility/sonarr.py +++ b/config/utility/sonarr.py @@ -7,6 +7,9 @@ import other.texts as txt from other.exceptions import UnauthorizedSonarr +# https://sonarr.tv/docs/api/ +# https://github.com/Sonarr/Sonarr/wiki/API (Legacy) + def getMissingEpisodes() -> List[Dict]: """ Ottiene tutte le informazioni riguardante gli episodi mancanti da Sonarr. @@ -151,7 +154,7 @@ def renameEpisode(seriesId:int, epFileId:int): } requests.post(url, json=data) -def getEpisodeFileID(epId): # Converte l'epId in epFileId +def getEpisodeFileID(epId:int) -> int: # Converte l'epId in epFileId """ Trova l'ID del file (`epFileId`) partendo dall'ID dell'episodio (`epId`). @@ -160,4 +163,12 @@ def getEpisodeFileID(epId): # Converte l'epId in epFileId ``` """ data = getEpisode(epId) - return data["episodeFile"]["id"] \ No newline at end of file + return data["episodeFile"]["id"] + +def inQueue(epId:int) -> bool: + """ + Controlla se l'episodio è in download da Sonarr. + """ + endpoint = "queue" + url = "{}/api/{}?apikey={}".format(SONARR_URL, endpoint, API_KEY) + return epId in [x["episode"]["id"] for x in requests.get(url).json()] \ No newline at end of file diff --git a/documentation/examples/json/table.json b/documentation/examples/json/table.json index 1c916ad..428072c 100644 --- a/documentation/examples/json/table.json +++ b/documentation/examples/json/table.json @@ -435,6 +435,15 @@ }, "title": "Redo of Healer" }, + { + "title": "Reincarnated as a Sword", + "seasons": { + "1": [ + "https://www.animeworld.tv/play/tensei-shitara-ken-deshita.ABj8v" + ] + }, + "absolute": false + }, { "absolute": false, "seasons": { diff --git a/requirements.txt b/requirements.txt index 1b763b0..6e0d878 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -animeworld>=1.4.18 +animeworld>=1.4.20 schedule>=0.6.0 flask flask_socketio