async def _process_candidate(self, candidate, res): log.info( "Searching episode '%s' from series '%s'. Filename: %s", candidate.get("episode_title"), candidate.get("series_title"), candidate.get("scenename"), ) candidate_files = self._search_candidate_files(candidate, res) if not candidate_files: return self._refresh_db_media(candidate, candidate_files[0]) videos = self.filter_video_files(candidate_files, res) if not videos: return subtitles_info = await self.download_sub(videos, res) res.subtitles = subtitles_info if subtitles_info: res.successful("download successful") DopplerrDb().insert_event("subtitles", "subtitles fetched: {}".format(", ".join([ "{} (lang: {}, source: {})".format( s.get("filename"), s.get("language"), s.get("provider"), ) for s in subtitles_info ]))) else: DopplerrDb().insert_event("subtitles", "no subtitle found for: {}".format( ", ".join([Path(f).name for f in candidate_files]))) res.failed("no subtitle found")
async def _refresh_video(self, filepath): if DopplerrDb().media_exists(filepath): log.info("Already existing video file found: %s", filepath) return log.info("Unknown Video file found: %s", filepath) refined_lst = await RefineVideoFileTask().refine_file(filepath) if not refined_lst: log.error("Cannot refine file: %s", filepath) return if not isinstance(refined_lst, list): refined_lst = [refined_lst] for refined in refined_lst: if isinstance(refined, SeriesEpisodeInfo): DopplerrDb().update_series_media( series_title=refined.series_title, tv_db_id=refined.series_episode_uid.tv_db_id, season_number=refined.series_episode_uid.season_number, episode_number=refined.series_episode_uid.episode_number, episode_title=refined.episode_title, quality=refined.quality, video_languages=refined.video_languages, media_filename=refined.media_filename, dirty=refined.dirty, ) DopplerrDb().insert_event("media update", "Available TV episode: {} - {}x{} - {}.".format( refined.series_title, refined.series_episode_uid.season_number, refined.series_episode_uid.episode_number, refined.episode_title, )) else: log.error("Unsupported refined video type: %r", refined) return
async def run(self, task) -> dict: content = task log.debug("Sonarr notification received: %r", content) res = await SonarrFilter().filter(content) if res.is_unhandled: # event has been filtered out return res.to_dict() if res.candidates: for candidate in res.candidates: DopplerrDb().insert_event( "media update", "Available TV episode: {} - {}x{} - {} [{}].".format( candidate.get("series_title"), candidate.get("season_number"), candidate.get("episode_number"), candidate.get("episode_title"), candidate.get("quality"), )) log.debug("Sonarr notification ok, posting background task") # processing ok, let's post our background task to the task queue self.post_task(self.task_sonarr_on_download_background(res)) # asyncio.ensure_future(self.task_sonarr_on_download_background(res)) res.successful("Request successfully posted") return res.to_dict()
def _search_candidate_files(self, candidate, res): candidate_files = self.search_file(candidate['root_dir'], candidate['scenename']) log.debug("All found files: %r", candidate_files) if not candidate_files: res.failed("candidates defined in request but no video file found on disk") DopplerrDb().insert_event("subtitles", "No video file found on disk " "after sonarr notification") return [] return candidate_files
def _refresh_db_media(candidate, media_filename): DopplerrDb().update_series_media( series_title=candidate.get("series_title"), tv_db_id=candidate.get("tv_db_id"), season_number=candidate.get("season_number"), episode_number=candidate.get("episode_number"), episode_title=candidate.get("episode_title"), quality=candidate.get("quality"), video_languages=None, media_filename=media_filename, dirty=True)
async def _run(self, task): log.debug("Starting Download subtitle for task") res = task if not res.candidates: DopplerrDb().insert_event("error", "event handled but no candidate found") log.debug("event handled but no candidate found") res.failed("event handled but no candidate found") return res for candidate in res.candidates: await self._process_candidate(candidate, res) return res
async def task_sonarr_on_download_background(self, res): log.debug("Starting task_sonarr_on_download_background") downloader = DownloadSubtitleTask() res = await downloader.run_and_wait(res) if not res.is_successful: log.debug("not successful, leaving background task") return res for episode_info in res.sonarr_episode_infos: await emit_notifications( SubtitleFetchedNotification(series_episode_info=episode_info)) DopplerrDb().update_fetched_series_subtitles( series_episode_uid=SeriesEpisodeUid( episode_info['tv_db_id'], episode_info['season_number'], episode_info['episode_number'], ), subtitles_languages=episode_info['subtitles_languages'], dirty=False) log.debug("Background task finished with result: %s", res.to_json()) return res
async def get_series(seriesid) -> Series: return DopplerrDb().get_series(seriesid)
async def list_series() -> SeriesList: return DopplerrDb().list_series()
async def medias_series() -> Medias: res = {"medias": DopplerrDb().get_medias_series()} return res
async def recent_fetched_series_num(num: int = 10) -> RecentSeries: num = int(num) if num > 100: num = 100 res = {"events": DopplerrDb().get_last_fetched_series(num)} return res
async def recent_events_10() -> Events: res = {"events": DopplerrDb().get_recent_events(10)} return res
async def recent_events_num(num: int = 10) -> Events: num = int(num) if num > 100: num = 100 res = {"events": DopplerrDb().get_recent_events(num)} return res
def main(): outputtype = OutputType.PLAIN if "--debug-config" in sys.argv: default_level = logging.DEBUG else: default_level = logging.ERROR for i in range(len(sys.argv)): if sys.argv[i] == "--output-type": if i < len(sys.argv) and sys.argv[i + 1] == "dev": outputtype = OutputType.DEV break debug = default_level is logging.DEBUG setup_logging(debug=debug, outputtype=outputtype) log.debug("Initializing Dopplerr version %s...", DOPPLERR_VERSION) DopplerrConfig().find_configuration_values() log.debug("Current configuration: %s", DopplerrConfig().json(safe=True)) debug = DopplerrConfig().get_cfg_value("general.verbose") output_type = DopplerrConfig().get_cfg_value("general.output_type") if output_type == 'dev': outputtype = OutputType.DEV elif output_type == 'plain': outputtype = OutputType.PLAIN else: raise NotImplementedError( "Invalid output type: {!r}".format(output_type)) log.debug("Applying configuration") custom_log_levels = [ ("peewee", logging.DEBUG if debug else logging.ERROR), ("sanic", logging.INFO), ("cfgtree", logging.DEBUG if debug else logging.ERROR), ("apscheduler", logging.INFO), # Subliminal loggers ("chardet", logging.ERROR), ("dogpile", logging.ERROR), ("enzyme", logging.ERROR), ("rebulk.processors", logging.INFO), ("rebulk", logging.ERROR), ("subliminal.providers", logging.ERROR), ("subliminal.score", logging.ERROR), ("subliminal.subtitle", logging.ERROR), ("subliminal", logging.INFO), ("urllib3", logging.ERROR), ] setup_logging(outputtype=outputtype, debug=debug, logfile=DopplerrConfig().get_cfg_value("general.logfile"), custom_log_levels=custom_log_levels) log.info( "Logging is set to %s", "verbose" if DopplerrConfig().get_cfg_value("general.verbose") else "not verbose") DopplerrStatus().refresh_from_cfg() # Backup configuration, now refresh_from_cfg has updated the version DopplerrConfig().save_configuration() log.info("Initializing Subtitle DopplerrDownloader Service") SubliminalSubDownloader.initialize_db() DopplerrStatus().sqlite_db_path = ( Path(DopplerrConfig().get_cfg_value("general.configdir")) / "sqlite.db") reset_db = False if DopplerrStatus().has_minor_version_changed: log.warning("Major version change, dropping all databases") reset_db = True else: log.info("Previous version was %s, now: %s", DopplerrStatus().previous_version, DopplerrConfig().get_cfg_value("general.version")) log.debug("SQLite DB: %s", DopplerrStatus().sqlite_db_path.as_posix()) DopplerrDb().init(DopplerrStatus().sqlite_db_path, reset_db=reset_db) DopplerrDb().create_tables() if reset_db: DopplerrDb().insert_event( "db reset", "Doppler major or minor version upgrade caused a DB reset ") # change current work dir for subliminal work files os.chdir(DopplerrConfig().get_cfg_value("general.configdir")) DopplerrDb().insert_event("start", "dopplerr started") # main event loop (Asyncio behind) listen() logging.info("Clean stopping") DopplerrDb().insert_event("stop", "dopplerr stopped") return 0