Example #1
0
    def get(self):
        episodes_conditions = [
            (TableEpisodes.missing_subtitles.is_null(False)),
            (TableEpisodes.missing_subtitles != '[]')
        ]
        episodes_conditions += get_exclusion_clause('series')
        missing_episodes = TableEpisodes.select(TableShows.tags,
                                                TableShows.seriesType,
                                                TableEpisodes.monitored)\
            .join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId))\
            .where(reduce(operator.and_, episodes_conditions))\
            .count()

        movies_conditions = [(TableMovies.missing_subtitles.is_null(False)),
                             (TableMovies.missing_subtitles != '[]')]
        movies_conditions += get_exclusion_clause('movie')
        missing_movies = TableMovies.select(TableMovies.tags,
                                            TableMovies.monitored)\
            .where(reduce(operator.and_, movies_conditions))\
            .count()

        throttled_providers = len(get_throttled_providers())

        health_issues = len(get_health_issues())

        result = {
            "episodes": missing_episodes,
            "movies": missing_movies,
            "providers": throttled_providers,
            "status": health_issues
        }
        return jsonify(result)
Example #2
0
    def get(self):
        query = request.args.get('query')
        search_list = []

        if query:
            if settings.general.getboolean('use_sonarr'):
                # Get matching series
                series = TableShows.select(TableShows.title,
                                           TableShows.sonarrSeriesId,
                                           TableShows.year)\
                    .where(TableShows.title.contains(query))\
                    .order_by(TableShows.title)\
                    .dicts()
                series = list(series)
                search_list += series

            if settings.general.getboolean('use_radarr'):
                # Get matching movies
                movies = TableMovies.select(TableMovies.title,
                                            TableMovies.radarrId,
                                            TableMovies.year) \
                    .where(TableMovies.title.contains(query)) \
                    .order_by(TableMovies.title) \
                    .dicts()
                movies = list(movies)
                search_list += movies


        return jsonify(search_list)
Example #3
0
    def post(self):
        radarr_id = int(request.args.get('radarrid'))
        provider = request.form.get('provider')
        subs_id = request.form.get('subs_id')
        language = request.form.get('language')
        # TODO
        forced = False
        hi = False

        data = TableMovies.select(TableMovies.path).where(TableMovies.radarrId == radarr_id).dicts().get()

        media_path = data['path']
        subtitles_path = request.form.get('subtitles_path')

        blacklist_log_movie(radarr_id=radarr_id,
                            provider=provider,
                            subs_id=subs_id,
                            language=language)
        delete_subtitles(media_type='movie',
                         language=language,
                         forced=forced,
                         hi=hi,
                         media_path=path_mappings.path_replace_movie(media_path),
                         subtitles_path=subtitles_path,
                         radarr_id=radarr_id)
        movies_download_subtitles(radarr_id)
        event_stream(type='movie-history')
        return '', 200
Example #4
0
    def get(self):
        # Manual Search
        radarrId = request.args.get('radarrid')
        movieInfo = TableMovies.select(TableMovies.title,
                                       TableMovies.path,
                                       TableMovies.sceneName,
                                       TableMovies.profileId) \
            .where(TableMovies.radarrId == radarrId) \
            .dicts() \
            .get_or_none()

        if not movieInfo:
            return 'Movie not found', 500

        title = movieInfo['title']
        moviePath = path_mappings.path_replace_movie(movieInfo['path'])
        sceneName = movieInfo['sceneName'] or "None"
        profileId = movieInfo['profileId']

        providers_list = get_providers()

        data = manual_search(moviePath, profileId, providers_list, sceneName, title, 'movie')
        if not data:
            data = []
        return jsonify(data=data)
Example #5
0
def wanted_search_missing_subtitles_movies():
    conditions = [(TableMovies.missing_subtitles != '[]')]
    conditions += get_exclusion_clause('movie')
    movies = TableMovies.select(TableMovies.radarrId,
                                TableMovies.tags,
                                TableMovies.monitored,
                                TableMovies.title) \
        .where(reduce(operator.and_, conditions)) \
        .dicts()
    movies = list(movies)

    count_movies = len(movies)
    for i, movie in enumerate(movies):
        show_progress(id='wanted_movies_progress',
                      header='Searching subtitles...',
                      name=movie['title'],
                      value=i,
                      count=count_movies)

        providers = get_providers()
        if providers:
            wanted_download_subtitles_movie(movie['radarrId'])
        else:
            logging.info("BAZARR All providers are throttled")
            break

    hide_progress(id='wanted_movies_progress')

    logging.info('BAZARR Finished searching for missing Movies Subtitles. Check History for more information.')
Example #6
0
    def delete(self):
        # Delete
        radarrId = request.args.get('radarrid')
        movieInfo = TableMovies.select(TableMovies.path) \
            .where(TableMovies.radarrId == radarrId) \
            .dicts() \
            .get_or_none()

        if not movieInfo:
            return 'Movie not found', 500

        moviePath = path_mappings.path_replace_movie(movieInfo['path'])

        language = request.form.get('language')
        forced = request.form.get('forced')
        hi = request.form.get('hi')
        subtitlesPath = request.form.get('path')

        subtitlesPath = path_mappings.path_replace_reverse_movie(subtitlesPath)

        result = delete_subtitles(media_type='movie',
                                  language=language,
                                  forced=forced,
                                  hi=hi,
                                  media_path=moviePath,
                                  subtitles_path=subtitlesPath,
                                  radarr_id=radarrId)
        if result:
            return '', 202
        else:
            return '', 204
Example #7
0
def get_movie(radarr_id):
    data = TableMovies.select(TableMovies.title, TableMovies.year)\
        .where(TableMovies.radarrId == radarr_id)\
        .dicts()\
        .get()

    return {'title': data['title'], 'year': data['year']}
Example #8
0
    def get(self):
        radarrid = request.args.getlist("radarrid[]")

        wanted_conditions = [(TableMovies.missing_subtitles != '[]')]
        if len(radarrid) > 0:
            wanted_conditions.append((TableMovies.radarrId.in_(radarrid)))
        wanted_conditions += get_exclusion_clause('movie')
        wanted_condition = reduce(operator.and_, wanted_conditions)

        if len(radarrid) > 0:
            result = TableMovies.select(TableMovies.title,
                                        TableMovies.missing_subtitles,
                                        TableMovies.radarrId,
                                        TableMovies.sceneName,
                                        TableMovies.failedAttempts,
                                        TableMovies.tags,
                                        TableMovies.monitored)\
                .where(wanted_condition)\
                .dicts()
        else:
            start = request.args.get('start') or 0
            length = request.args.get('length') or -1
            result = TableMovies.select(TableMovies.title,
                                        TableMovies.missing_subtitles,
                                        TableMovies.radarrId,
                                        TableMovies.sceneName,
                                        TableMovies.failedAttempts,
                                        TableMovies.tags,
                                        TableMovies.monitored)\
                .where(wanted_condition)\
                .order_by(TableMovies.rowid.desc())\
                .limit(length)\
                .offset(start)\
                .dicts()
        result = list(result)

        for item in result:
            postprocessMovie(item)

        count_conditions = [(TableMovies.missing_subtitles != '[]')]
        count_conditions += get_exclusion_clause('movie')
        count = TableMovies.select(TableMovies.monitored,
                                   TableMovies.tags)\
            .where(reduce(operator.and_, count_conditions))\
            .count()

        return jsonify(data=result, total=count)
Example #9
0
def movies_scan_subtitles(no):
    movies = TableMovies.select(
        TableMovies.path).where(TableMovies.radarr_id == no)

    for movie in movies:
        store_subtitles_movie(path_replace_movie(movie.path))

    list_missing_subtitles_movies(no)
Example #10
0
def movies_scan_subtitles(no):
    movies = TableMovies.select(TableMovies.path)\
        .where(TableMovies.radarrId == no)\
        .order_by(TableMovies.radarrId)\
        .dicts()

    for movie in movies:
        store_subtitles_movie(movie['path'], path_mappings.path_replace_movie(movie['path']), use_cache=False)
Example #11
0
def list_missing_subtitles_movies(no=None):
    movies_subtitles_clause = {TableMovies.radarr_id.is_null(False)}
    if no is not None:
        movies_subtitles_clause = {TableMovies.radarr_id**no}

    movies_subtitles = TableMovies.select(
        TableMovies.radarr_id, TableMovies.subtitles, TableMovies.languages,
        TableMovies.forced).where(movies_subtitles_clause)

    missing_subtitles_global = []
    use_embedded_subs = settings.general.getboolean('use_embedded_subs')
    for movie_subtitles in movies_subtitles:
        actual_subtitles_temp = []
        desired_subtitles_temp = []
        actual_subtitles = []
        desired_subtitles = []
        missing_subtitles = []
        if movie_subtitles.subtitles is not None:
            if use_embedded_subs:
                actual_subtitles = ast.literal_eval(movie_subtitles.subtitles)
            else:
                actual_subtitles_temp = ast.literal_eval(
                    movie_subtitles.subtitles)
                for subtitle in actual_subtitles_temp:
                    if subtitle[1] is not None:
                        actual_subtitles.append(subtitle)
        if movie_subtitles.languages is not None:
            desired_subtitles = ast.literal_eval(movie_subtitles.languages)
            if movie_subtitles.forced == "True" and desired_subtitles is not None:
                for i, desired_subtitle in enumerate(desired_subtitles):
                    desired_subtitles[i] = desired_subtitle + ":forced"
            elif movie_subtitles.forced == "Both" and desired_subtitles is not None:
                for desired_subtitle in desired_subtitles:
                    desired_subtitles_temp.append(desired_subtitle)
                    desired_subtitles_temp.append(desired_subtitle + ":forced")
                desired_subtitles = desired_subtitles_temp
        actual_subtitles_list = []
        if desired_subtitles is None:
            missing_subtitles_global.append(
                tuple(['[]', movie_subtitles.radarr_id]))
        else:
            for item in actual_subtitles:
                if item[0] == "pt-BR":
                    actual_subtitles_list.append("pb")
                elif item[0] == "pt-BR:forced":
                    actual_subtitles_list.append("pb:forced")
                else:
                    actual_subtitles_list.append(item[0])
            missing_subtitles = list(
                set(desired_subtitles) - set(actual_subtitles_list))
            missing_subtitles_global.append(
                tuple([str(missing_subtitles), movie_subtitles.radarr_id]))

    for missing_subtitles_item in missing_subtitles_global:
        TableMovies.update({
            TableMovies.missing_subtitles:
            missing_subtitles_item[0]
        }).where(TableMovies.radarr_id == missing_subtitles_item[1]).execute()
Example #12
0
def refine_from_ffprobe(path, video):
    if isinstance(video, Movie):
        file_id = TableMovies.select(TableMovies.movie_file_id, TableMovies.file_size)\
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path))\
            .dicts()\
            .get_or_none()
    else:
        file_id = TableEpisodes.select(TableEpisodes.episode_file_id, TableEpisodes.file_size)\
            .where(TableEpisodes.path == path_mappings.path_replace_reverse(path))\
            .dicts()\
            .get_or_none()

    if not file_id:
        return video

    if isinstance(video, Movie):
        data = parse_video_metadata(file=path, file_size=file_id['file_size'],
                                    movie_file_id=file_id['movie_file_id'])
    else:
        data = parse_video_metadata(file=path, file_size=file_id['file_size'],
                                    episode_file_id=file_id['episode_file_id'])

    if not data['ffprobe']:
        logging.debug("No FFprobe available in cache for this file: {}".format(path))
        return video

    logging.debug('FFprobe found: %s', data['ffprobe'])

    if 'video' not in data['ffprobe']:
        logging.debug('BAZARR FFprobe was unable to find video tracks in the file!')
    else:
        if 'resolution' in data['ffprobe']['video'][0]:
            if not video.resolution:
                video.resolution = data['ffprobe']['video'][0]['resolution']
        if 'codec' in data['ffprobe']['video'][0]:
            if not video.video_codec:
                video.video_codec = data['ffprobe']['video'][0]['codec']
        if 'frame_rate' in data['ffprobe']['video'][0]:
            if not video.fps:
                if isinstance(data['ffprobe']['video'][0]['frame_rate'], float):
                    video.fps = data['ffprobe']['video'][0]['frame_rate']
                else:
                    try:
                        video.fps = data['ffprobe']['video'][0]['frame_rate'].magnitude
                    except AttributeError:
                        video.fps = data['ffprobe']['video'][0]['frame_rate']

    if 'audio' not in data['ffprobe']:
        logging.debug('BAZARR FFprobe was unable to find audio tracks in the file!')
    else:
        if 'codec' in data['ffprobe']['audio'][0]:
            if not video.audio_codec:
                video.audio_codec = data['ffprobe']['audio'][0]['codec']
        for track in data['ffprobe']['audio']:
            if 'language' in track:
                video.audio_languages.add(track['language'].alpha3)

    return video
Example #13
0
    def post(self):
        # Manual Download
        radarrId = request.args.get('radarrid')
        movieInfo = TableMovies.select(TableMovies.title,
                                       TableMovies.path,
                                       TableMovies.sceneName,
                                       TableMovies.audio_language) \
            .where(TableMovies.radarrId == radarrId) \
            .dicts() \
            .get()

        title = movieInfo['title']
        moviePath = path_mappings.path_replace_movie(movieInfo['path'])
        sceneName = movieInfo['sceneName']
        if sceneName is None: sceneName = "None"
        audio_language = movieInfo['audio_language']

        language = request.form.get('language')
        hi = request.form.get('hi').capitalize()
        forced = request.form.get('forced').capitalize()
        selected_provider = request.form.get('provider')
        subtitle = request.form.get('subtitle')

        providers_auth = get_providers_auth()

        audio_language_list = get_audio_profile_languages(movie_id=radarrId)
        if len(audio_language_list) > 0:
            audio_language = audio_language_list[0]['name']
        else:
            audio_language = 'None'

        try:
            result = manual_download_subtitle(moviePath, language, audio_language, hi, forced, subtitle,
                                              selected_provider, providers_auth, sceneName, title, 'movie',
                                              profile_id=get_profile_id(movie_id=radarrId))
            if result is not None:
                message = result[0]
                path = result[1]
                forced = result[5]
                if result[8]:
                    language_code = result[2] + ":hi"
                elif forced:
                    language_code = result[2] + ":forced"
                else:
                    language_code = result[2]
                provider = result[3]
                score = result[4]
                subs_id = result[6]
                subs_path = result[7]
                history_log_movie(2, radarrId, message, path, language_code, provider, score, subs_id, subs_path)
                if not settings.general.getboolean('dont_notify_manual_actions'):
                    send_notifications_movie(radarrId, message)
                store_subtitles_movie(path, moviePath)
        except OSError:
            pass

        return '', 204
Example #14
0
    def get(self):
        start = request.args.get('start') or 0
        length = request.args.get('length') or -1
        radarrId = request.args.getlist('radarrid[]')

        count = TableMovies.select().count()

        if len(radarrId) != 0:
            result = TableMovies.select()\
                .where(TableMovies.radarrId.in_(radarrId))\
                .order_by(TableMovies.sortTitle)\
                .dicts()
        else:
            result = TableMovies.select().order_by(
                TableMovies.sortTitle).limit(length).offset(start).dicts()
        result = list(result)
        for item in result:
            postprocessMovie(item)

        return jsonify(data=result, total=count)
Example #15
0
def movies_full_scan_subtitles():
    movies = TableMovies.select(TableMovies.path)
    count_movies = movies.count()

    for i, movie in enumerate(movies, 1):
        notifications.write(msg='Updating all movies subtitles from disk...',
                            queue='list_subtitles_movies',
                            item=i,
                            length=count_movies)
        store_subtitles_movie(path_replace_movie(movie.path))

    gc.collect()
Example #16
0
def movies_full_scan_subtitles():
    use_ffprobe_cache = settings.radarr.getboolean('use_ffprobe_cache')

    movies = TableMovies.select(TableMovies.path).dicts()

    count_movies = len(movies)
    for i, movie in enumerate(movies):
        show_progress(id='movies_disk_scan',
                      header='Full disk scan...',
                      name='Movies subtitles',
                      value=i,
                      count=count_movies)
        store_subtitles_movie(movie['path'], path_mappings.path_replace_movie(movie['path']),
                              use_cache=use_ffprobe_cache)

    hide_progress(id='movies_disk_scan')

    gc.collect()
Example #17
0
def get_radarr_rootfolder():
    apikey_radarr = settings.radarr.apikey
    radarr_rootfolder = []

    # Get root folder data from Radarr
    if get_radarr_info.is_legacy():
        url_radarr_api_rootfolder = url_radarr() + "/api/rootfolder?apikey=" + apikey_radarr
    else:
        url_radarr_api_rootfolder = url_radarr() + "/api/v3/rootfolder?apikey=" + apikey_radarr

    try:
        rootfolder = requests.get(url_radarr_api_rootfolder, timeout=60, verify=False, headers=headers)
    except requests.exceptions.ConnectionError:
        logging.exception("BAZARR Error trying to get rootfolder from Radarr. Connection Error.")
        return []
    except requests.exceptions.Timeout:
        logging.exception("BAZARR Error trying to get rootfolder from Radarr. Timeout Error.")
        return []
    except requests.exceptions.RequestException:
        logging.exception("BAZARR Error trying to get rootfolder from Radarr.")
        return []
    else:
        radarr_movies_paths = list(TableMovies.select(TableMovies.path).dicts())
        for folder in rootfolder.json():
            if any(item['path'].startswith(folder['path']) for item in radarr_movies_paths):
                radarr_rootfolder.append({'id': folder['id'], 'path': folder['path']})
        db_rootfolder = TableMoviesRootfolder.select(TableMoviesRootfolder.id, TableMoviesRootfolder.path).dicts()
        rootfolder_to_remove = [x for x in db_rootfolder if not
                                next((item for item in radarr_rootfolder if item['id'] == x['id']), False)]
        rootfolder_to_update = [x for x in radarr_rootfolder if
                                next((item for item in db_rootfolder if item['id'] == x['id']), False)]
        rootfolder_to_insert = [x for x in radarr_rootfolder if not
                                next((item for item in db_rootfolder if item['id'] == x['id']), False)]

        for item in rootfolder_to_remove:
            TableMoviesRootfolder.delete().where(TableMoviesRootfolder.id == item['id']).execute()
        for item in rootfolder_to_update:
            TableMoviesRootfolder.update({TableMoviesRootfolder.path: item['path']})\
                .where(TableMoviesRootfolder.id == item['id']).execute()
        for item in rootfolder_to_insert:
            TableMoviesRootfolder.insert({TableMoviesRootfolder.id: item['id'],
                                          TableMoviesRootfolder.path: item['path']}).execute()
Example #18
0
def wanted_download_subtitles_movie(radarr_id):
    movies_details = TableMovies.select(TableMovies.path,
                                        TableMovies.missing_subtitles,
                                        TableMovies.radarrId,
                                        TableMovies.audio_language,
                                        TableMovies.sceneName,
                                        TableMovies.failedAttempts,
                                        TableMovies.title)\
        .where((TableMovies.radarrId == radarr_id))\
        .dicts()
    movies_details = list(movies_details)

    for movie in movies_details:
        providers_list = get_providers()

        if providers_list:
            _wanted_movie(movie)
        else:
            logging.info("BAZARR All providers are throttled")
            break
Example #19
0
def manual_upload_subtitle(path, language, forced, hi, title, scene_name, media_type, subtitle, audio_language):
    logging.debug('BAZARR Manually uploading subtitles for this file: ' + path)

    single = settings.general.getboolean('single_language')

    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
        'win') and settings.general.getboolean('chmod_enabled') else None

    language = alpha3_from_alpha2(language)

    custom = CustomLanguage.from_value(language, "alpha3")
    if custom is None:
        lang_obj = Language(language)
    else:
        lang_obj = custom.subzero_language()

    if forced:
        lang_obj = Language.rebuild(lang_obj, forced=True)

    sub = Subtitle(
        lang_obj,
        mods=get_array_from(settings.general.subzero_mods)
    )

    sub.content = subtitle.read()
    if not sub.is_valid():
        logging.exception('BAZARR Invalid subtitle file: ' + subtitle.filename)
        sub.mods = None

    if settings.general.getboolean('utf8_encode'):
        sub.set_encoding("utf-8")

    saved_subtitles = []
    try:
        saved_subtitles = save_subtitles(path,
                                         [sub],
                                         single=single,
                                         tags=None,  # fixme
                                         directory=get_target_folder(path),
                                         chmod=chmod,
                                         # formats=("srt", "vtt")
                                         path_decoder=force_unicode)
    except Exception:
        logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path)
        return

    if len(saved_subtitles) < 1:
        logging.exception('BAZARR Error saving Subtitles file to disk for this file:' + path)
        return

    subtitle_path = saved_subtitles[0].storage_path

    if hi:
        modifier_string = " HI"
    elif forced:
        modifier_string = " forced"
    else:
        modifier_string = ""
    message = language_from_alpha3(language) + modifier_string + " Subtitles manually uploaded."

    if hi:
        modifier_code = ":hi"
    elif forced:
        modifier_code = ":forced"
    else:
        modifier_code = ""
    uploaded_language_code3 = language + modifier_code
    uploaded_language = language_from_alpha3(language) + modifier_string
    uploaded_language_code2 = alpha2_from_alpha3(language) + modifier_code
    audio_language_code2 = alpha2_from_language(audio_language)
    audio_language_code3 = alpha3_from_language(audio_language)

    if media_type == 'series':
        episode_metadata = TableEpisodes.select(TableEpisodes.sonarrSeriesId, TableEpisodes.sonarrEpisodeId) \
            .where(TableEpisodes.path == path_mappings.path_replace_reverse(path)) \
            .dicts() \
            .get_or_none()
        if not episode_metadata:
            return
        series_id = episode_metadata['sonarrSeriesId']
        episode_id = episode_metadata['sonarrEpisodeId']
        sync_subtitles(video_path=path, srt_path=subtitle_path, srt_lang=uploaded_language_code2, media_type=media_type,
                       percent_score=100, sonarr_series_id=episode_metadata['sonarrSeriesId'], forced=forced,
                       sonarr_episode_id=episode_metadata['sonarrEpisodeId'])
    else:
        movie_metadata = TableMovies.select(TableMovies.radarrId) \
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path)) \
            .dicts() \
            .get_or_none()
        if not movie_metadata:
            return
        series_id = ""
        episode_id = movie_metadata['radarrId']
        sync_subtitles(video_path=path, srt_path=subtitle_path, srt_lang=uploaded_language_code2, media_type=media_type,
                       percent_score=100, radarr_id=movie_metadata['radarrId'], forced=forced)

    if use_postprocessing:
        command = pp_replace(postprocessing_cmd, path, subtitle_path, uploaded_language,
                             uploaded_language_code2, uploaded_language_code3, audio_language,
                             audio_language_code2, audio_language_code3, forced, 100, "1", "manual", series_id,
                             episode_id, hi=hi)
        postprocessing(command, path)

    if media_type == 'series':
        reversed_path = path_mappings.path_replace_reverse(path)
        reversed_subtitles_path = path_mappings.path_replace_reverse(subtitle_path)
        notify_sonarr(episode_metadata['sonarrSeriesId'])
        event_stream(type='series', action='update', payload=episode_metadata['sonarrSeriesId'])
        event_stream(type='episode-wanted', action='delete', payload=episode_metadata['sonarrEpisodeId'])
    else:
        reversed_path = path_mappings.path_replace_reverse_movie(path)
        reversed_subtitles_path = path_mappings.path_replace_reverse_movie(subtitle_path)
        notify_radarr(movie_metadata['radarrId'])
        event_stream(type='movie', action='update', payload=movie_metadata['radarrId'])
        event_stream(type='movie-wanted', action='delete', payload=movie_metadata['radarrId'])

    return message, reversed_path, reversed_subtitles_path
Example #20
0
    def post(self):
        # Upload
        # TODO: Support Multiply Upload
        radarrId = request.args.get('radarrid')
        movieInfo = TableMovies.select(TableMovies.title,
                                       TableMovies.path,
                                       TableMovies.sceneName,
                                       TableMovies.audio_language) \
            .where(TableMovies.radarrId == radarrId) \
            .dicts() \
            .get_or_none()

        if not movieInfo:
            return 'Movie not found', 500

        moviePath = path_mappings.path_replace_movie(movieInfo['path'])
        sceneName = movieInfo['sceneName'] or 'None'

        title = movieInfo['title']
        audioLanguage = movieInfo['audio_language']

        language = request.form.get('language')
        forced = True if request.form.get('forced') == 'true' else False
        hi = True if request.form.get('hi') == 'true' else False
        subFile = request.files.get('file')

        _, ext = os.path.splitext(subFile.filename)

        if ext not in SUBTITLE_EXTENSIONS:
            raise ValueError('A subtitle of an invalid format was uploaded.')

        try:
            result = manual_upload_subtitle(path=moviePath,
                                            language=language,
                                            forced=forced,
                                            hi=hi,
                                            title=title,
                                            scene_name=sceneName,
                                            media_type='movie',
                                            subtitle=subFile,
                                            audio_language=audioLanguage)

            if not result:
                logging.debug(
                    f"BAZARR unable to process subtitles for this movie: {moviePath}"
                )
            else:
                message = result[0]
                path = result[1]
                subs_path = result[2]
                if hi:
                    language_code = language + ":hi"
                elif forced:
                    language_code = language + ":forced"
                else:
                    language_code = language
                provider = "manual"
                score = 120
                history_log_movie(4,
                                  radarrId,
                                  message,
                                  path,
                                  language_code,
                                  provider,
                                  score,
                                  subtitles_path=subs_path)
                if not settings.general.getboolean(
                        'dont_notify_manual_actions'):
                    send_notifications_movie(radarrId, message)
                store_subtitles_movie(path, moviePath)
        except OSError:
            pass

        return '', 204
Example #21
0
    def patch(self):
        # Download
        radarrId = request.args.get('radarrid')

        movieInfo = TableMovies.select(TableMovies.title,
                                       TableMovies.path,
                                       TableMovies.sceneName,
                                       TableMovies.audio_language)\
            .where(TableMovies.radarrId == radarrId)\
            .dicts()\
            .get_or_none()

        if not movieInfo:
            return 'Movie not found', 500

        moviePath = path_mappings.path_replace_movie(movieInfo['path'])
        sceneName = movieInfo['sceneName'] or 'None'

        title = movieInfo['title']
        audio_language = movieInfo['audio_language']

        language = request.form.get('language')
        hi = request.form.get('hi').capitalize()
        forced = request.form.get('forced').capitalize()

        audio_language_list = get_audio_profile_languages(movie_id=radarrId)
        if len(audio_language_list) > 0:
            audio_language = audio_language_list[0]['name']
        else:
            audio_language = None

        try:
            result = list(
                generate_subtitles(
                    moviePath, [(language, hi, forced)],
                    audio_language,
                    sceneName,
                    title,
                    'movie',
                    profile_id=get_profile_id(movie_id=radarrId)))
            if result:
                result = result[0]
                message = result[0]
                path = result[1]
                forced = result[5]
                if result[8]:
                    language_code = result[2] + ":hi"
                elif forced:
                    language_code = result[2] + ":forced"
                else:
                    language_code = result[2]
                provider = result[3]
                score = result[4]
                subs_id = result[6]
                subs_path = result[7]
                history_log_movie(1, radarrId, message, path, language_code,
                                  provider, score, subs_id, subs_path)
                send_notifications_movie(radarrId, message)
                store_subtitles_movie(path, moviePath)
            else:
                event_stream(type='movie', payload=radarrId)
        except OSError:
            pass

        return '', 204
Example #22
0
def _wanted_movie(movie):
    audio_language_list = get_audio_profile_languages(movie_id=movie['radarrId'])
    if len(audio_language_list) > 0:
        audio_language = audio_language_list[0]['name']
    else:
        audio_language = 'None'

    languages = []

    for language in ast.literal_eval(movie['missing_subtitles']):
        # confirm if language is still missing or if cutoff have been reached
        confirmed_missing_subs = TableMovies.select(TableMovies.missing_subtitles) \
            .where(TableMovies.radarrId == movie['radarrId']) \
            .dicts() \
            .get_or_none()
        if not confirmed_missing_subs:
            continue

        if language not in ast.literal_eval(confirmed_missing_subs['missing_subtitles']):
            continue

        if is_search_active(desired_language=language, attempt_string=movie['failedAttempts']):
            TableMovies.update({TableMovies.failedAttempts:
                                updateFailedAttempts(desired_language=language,
                                                     attempt_string=movie['failedAttempts'])}) \
                .where(TableMovies.radarrId == movie['radarrId']) \
                .execute()

            hi_ = "True" if language.endswith(':hi') else "False"
            forced_ = "True" if language.endswith(':forced') else "False"
            languages.append((language.split(":")[0], hi_, forced_))

        else:
            logging.info(f"BAZARR Search is throttled by adaptive search for this movie {movie['path']} and "
                         f"language: {language}")

    for result in generate_subtitles(path_mappings.path_replace_movie(movie['path']),
                                     languages,
                                     audio_language,
                                     str(movie['sceneName']),
                                     movie['title'], 'movie'):

        if result:
            message = result[0]
            path = result[1]
            forced = result[5]
            if result[8]:
                language_code = result[2] + ":hi"
            elif forced:
                language_code = result[2] + ":forced"
            else:
                language_code = result[2]
            provider = result[3]
            score = result[4]
            subs_id = result[6]
            subs_path = result[7]
            store_subtitles_movie(movie['path'], path_mappings.path_replace_movie(movie['path']))
            history_log_movie(1, movie['radarrId'], message, path, language_code, provider, score,
                              subs_id, subs_path)
            event_stream(type='movie-wanted', action='delete', payload=movie['radarrId'])
            send_notifications_movie(movie['radarrId'], message)
Example #23
0
def parse_video_metadata(file,
                         file_size,
                         episode_file_id=None,
                         movie_file_id=None,
                         use_cache=True):
    # Define default data keys value
    data = {
        "ffprobe": {},
        "enzyme": {},
        "file_id": episode_file_id or movie_file_id,
        "file_size": file_size,
    }

    if use_cache:
        # Get the actual cache value form database
        if episode_file_id:
            cache_key = TableEpisodes.select(TableEpisodes.ffprobe_cache)\
                .where(TableEpisodes.path == path_mappings.path_replace_reverse(file))\
                .dicts()\
                .get()
        elif movie_file_id:
            cache_key = TableMovies.select(TableMovies.ffprobe_cache)\
                .where(TableMovies.path == path_mappings.path_replace_reverse_movie(file))\
                .dicts()\
                .get()
        else:
            cache_key = None

        # check if we have a value for that cache key
        try:
            # Unpickle ffprobe cache
            cached_value = pickle.loads(cache_key['ffprobe_cache'])
        except:
            pass
        else:
            # Check if file size and file id matches and if so, we return the cached value
            if cached_value['file_size'] == file_size and cached_value[
                    'file_id'] in [episode_file_id, movie_file_id]:
                return cached_value

    # if not, we retrieve the metadata from the file
    from utils import get_binary

    ffprobe_path = get_binary("ffprobe")

    # if we have ffprobe available
    if ffprobe_path:
        api.initialize({"provider": "ffmpeg", "ffmpeg": ffprobe_path})
        data["ffprobe"] = api.know(file)
    # if not, we use enzyme for mkv files
    else:
        if os.path.splitext(file)[1] == ".mkv":
            with open(file, "rb") as f:
                try:
                    mkv = enzyme.MKV(f)
                except MalformedMKVError:
                    logger.error(
                        "BAZARR cannot analyze this MKV with our built-in MKV parser, you should install "
                        "ffmpeg/ffprobe: " + file)
                else:
                    data["enzyme"] = mkv

    # we write to db the result and return the newly cached ffprobe dict
    if episode_file_id:
        TableEpisodes.update({TableEpisodes.ffprobe_cache: pickle.dumps(data, pickle.HIGHEST_PROTOCOL)})\
            .where(TableEpisodes.path == path_mappings.path_replace_reverse(file))\
            .execute()
    elif movie_file_id:
        TableMovies.update({TableEpisodes.ffprobe_cache: pickle.dumps(data, pickle.HIGHEST_PROTOCOL)})\
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(file))\
            .execute()
    return data
Example #24
0
    def patch(self):
        action = request.args.get('action')

        language = request.form.get('language')
        subtitles_path = request.form.get('path')
        media_type = request.form.get('type')
        id = request.form.get('id')

        if media_type == 'episode':
            subtitles_path = path_mappings.path_replace(subtitles_path)
            metadata = TableEpisodes.select(TableEpisodes.path, TableEpisodes.sonarrSeriesId)\
                .where(TableEpisodes.sonarrEpisodeId == id)\
                .dicts()\
                .get_or_none()

            if not metadata:
                return 'Episode not found', 500

            video_path = path_mappings.path_replace(metadata['path'])
        else:
            subtitles_path = path_mappings.path_replace_movie(subtitles_path)
            metadata = TableMovies.select(TableMovies.path).where(
                TableMovies.radarrId == id).dicts().get_or_none()

            if not metadata:
                return 'Movie not found', 500

            video_path = path_mappings.path_replace_movie(metadata['path'])

        if action == 'sync':
            subsync = SubSyncer()
            if media_type == 'episode':
                subsync.sync(video_path=video_path,
                             srt_path=subtitles_path,
                             srt_lang=language,
                             media_type='series',
                             sonarr_series_id=metadata['sonarrSeriesId'],
                             sonarr_episode_id=int(id))
            else:
                subsync.sync(video_path=video_path,
                             srt_path=subtitles_path,
                             srt_lang=language,
                             media_type='movies',
                             radarr_id=id)
            del subsync
            gc.collect()
        elif action == 'translate':
            dest_language = language
            forced = True if request.form.get('forced') == 'true' else False
            hi = True if request.form.get('hi') == 'true' else False
            result = translate_subtitles_file(video_path=video_path,
                                              source_srt_file=subtitles_path,
                                              to_lang=dest_language,
                                              forced=forced,
                                              hi=hi)
            if result:
                if media_type == 'episode':
                    store_subtitles(
                        path_mappings.path_replace_reverse(video_path),
                        video_path)
                else:
                    store_subtitles_movie(
                        path_mappings.path_replace_reverse_movie(video_path),
                        video_path)
                return '', 200
            else:
                return '', 404
        else:
            subtitles_apply_mods(language, subtitles_path, [action])

        # apply chmod if required
        chmod = int(settings.general.chmod, 8) if not sys.platform.startswith(
            'win') and settings.general.getboolean('chmod_enabled') else None
        if chmod:
            os.chmod(subtitles_path, chmod)

        return '', 204
Example #25
0
def movies_download_subtitles(no):
    conditions = [(TableMovies.radarrId == no)]
    conditions += get_exclusion_clause('movie')
    movies = TableMovies.select(TableMovies.path,
                                TableMovies.missing_subtitles,
                                TableMovies.audio_language,
                                TableMovies.radarrId,
                                TableMovies.sceneName,
                                TableMovies.title,
                                TableMovies.tags,
                                TableMovies.monitored)\
        .where(reduce(operator.and_, conditions))\
        .dicts()
    if not len(movies):
        logging.debug(
            "BAZARR no movie with that radarrId can be found in database:",
            str(no))
        return
    else:
        movie = movies[0]

    if ast.literal_eval(movie['missing_subtitles']):
        count_movie = len(ast.literal_eval(movie['missing_subtitles']))
    else:
        count_movie = 0

    audio_language_list = get_audio_profile_languages(
        movie_id=movie['radarrId'])
    if len(audio_language_list) > 0:
        audio_language = audio_language_list[0]['name']
    else:
        audio_language = 'None'

    languages = []
    providers_list = None

    for i, language in enumerate(ast.literal_eval(movie['missing_subtitles'])):
        providers_list = get_providers()

        if language is not None:
            hi_ = "True" if language.endswith(':hi') else "False"
            forced_ = "True" if language.endswith(':forced') else "False"
            languages.append((language.split(":")[0], hi_, forced_))

        if providers_list:
            # confirm if language is still missing or if cutoff have been reached
            confirmed_missing_subs = TableMovies.select(TableMovies.missing_subtitles) \
                .where(TableMovies.radarrId == movie['radarrId']) \
                .dicts() \
                .get_or_none()
            if not confirmed_missing_subs:
                continue

            if language not in ast.literal_eval(
                    confirmed_missing_subs['missing_subtitles']):
                continue

            show_progress(id='movie_search_progress_{}'.format(no),
                          header='Searching missing subtitles...',
                          name=movie['title'],
                          value=i,
                          count=count_movie)

    if providers_list:
        for result in generate_subtitles(
                path_mappings.path_replace_movie(movie['path']), languages,
                audio_language, str(movie['sceneName']), movie['title'],
                'movie'):

            if result:
                message = result[0]
                path = result[1]
                forced = result[5]
                if result[8]:
                    language_code = result[2] + ":hi"
                elif forced:
                    language_code = result[2] + ":forced"
                else:
                    language_code = result[2]
                provider = result[3]
                score = result[4]
                subs_id = result[6]
                subs_path = result[7]
                store_subtitles_movie(
                    movie['path'],
                    path_mappings.path_replace_movie(movie['path']))
                history_log_movie(1, no, message, path, language_code,
                                  provider, score, subs_id, subs_path)
                send_notifications_movie(no, message)
    else:
        logging.info("BAZARR All providers are throttled")

    hide_progress(id='movie_search_progress_{}'.format(no))
Example #26
0
def update_movies():
    logging.debug('BAZARR Starting movie sync from Radarr.')
    apikey_radarr = settings.radarr.apikey
    movie_default_enabled = settings.general.getboolean(
        'movie_default_enabled')
    movie_default_language = settings.general.movie_default_language
    movie_default_hi = settings.general.movie_default_hi
    movie_default_forced = settings.general.movie_default_forced

    if apikey_radarr is None:
        pass
    else:
        audio_profiles = get_profile_list()

        # Get movies data from radarr
        url_radarr_api_movies = url_radarr + "/api/movie?apikey=" + apikey_radarr
        try:
            r = requests.get(url_radarr_api_movies, timeout=60, verify=False)
            r.raise_for_status()
        except requests.exceptions.HTTPError as errh:
            logging.exception(
                "BAZARR Error trying to get movies from Radarr. Http error.")
            return
        except requests.exceptions.ConnectionError as errc:
            logging.exception(
                "BAZARR Error trying to get movies from Radarr. Connection Error."
            )
            return
        except requests.exceptions.Timeout as errt:
            logging.exception(
                "BAZARR Error trying to get movies from Radarr. Timeout Error."
            )
            return
        except requests.exceptions.RequestException as err:
            logging.exception("BAZARR Error trying to get movies from Radarr.")
            return
        else:
            # Get current movies in DB
            current_movies_db = TableMovies.select(TableMovies.tmdb_id,
                                                   TableMovies.path,
                                                   TableMovies.radarr_id)

            current_movies_db_list = [x.tmdb_id for x in current_movies_db]

            current_movies_radarr = []
            movies_to_update = []
            movies_to_add = []
            altered_movies = []

            moviesIdListLength = len(r.json())
            for i, movie in enumerate(r.json(), 1):
                notifications.write(msg="Getting movies data from Radarr...",
                                    queue='get_movies',
                                    item=i,
                                    length=moviesIdListLength)
                if movie['hasFile'] is True:
                    if 'movieFile' in movie:
                        # Detect file separator
                        if movie['path'][0] == "/":
                            separator = "/"
                        else:
                            separator = "\\"

                        if movie["path"] != None and movie['movieFile'][
                                'relativePath'] != None:
                            try:
                                overview = unicode(movie['overview'])
                            except:
                                overview = ""
                            try:
                                poster_big = movie['images'][0]['url']
                                poster = os.path.splitext(
                                    poster_big)[0] + '-500' + os.path.splitext(
                                        poster_big)[1]
                            except:
                                poster = ""
                            try:
                                fanart = movie['images'][1]['url']
                            except:
                                fanart = ""

                            if 'sceneName' in movie['movieFile']:
                                sceneName = movie['movieFile']['sceneName']
                            else:
                                sceneName = None

                            if 'alternativeTitles' in movie:
                                alternativeTitles = str([
                                    item['title']
                                    for item in movie['alternativeTitles']
                                ])
                            else:
                                alternativeTitles = None

                            if 'imdbId' in movie: imdbId = movie['imdbId']
                            else: imdbId = None

                            try:
                                format, resolution = movie['movieFile'][
                                    'quality']['quality']['name'].split('-')
                            except:
                                format = movie['movieFile']['quality'][
                                    'quality']['name']
                            try:
                                resolution = movie['movieFile']['quality'][
                                    'quality']['resolution'].lstrip(
                                        'r').lower()
                            except:
                                resolution = None

                            if 'mediaInfo' in movie['movieFile']:
                                videoFormat = videoCodecID = videoProfile = videoCodecLibrary = None
                                if 'videoFormat' in movie['movieFile'][
                                        'mediaInfo']:
                                    videoFormat = movie['movieFile'][
                                        'mediaInfo']['videoFormat']
                                if 'videoCodecID' in movie['movieFile'][
                                        'mediaInfo']:
                                    videoCodecID = movie['movieFile'][
                                        'mediaInfo']['videoCodecID']
                                if 'videoProfile' in movie['movieFile'][
                                        'mediaInfo']:
                                    videoProfile = movie['movieFile'][
                                        'mediaInfo']['videoProfile']
                                if 'videoCodecLibrary' in movie['movieFile'][
                                        'mediaInfo']:
                                    videoCodecLibrary = movie['movieFile'][
                                        'mediaInfo']['videoCodecLibrary']
                                videoCodec = RadarrFormatVideoCodec(
                                    videoFormat, videoCodecID, videoProfile,
                                    videoCodecLibrary)

                                audioFormat = audioCodecID = audioProfile = audioAdditionalFeatures = None
                                if 'audioFormat' in movie['movieFile'][
                                        'mediaInfo']:
                                    audioFormat = movie['movieFile'][
                                        'mediaInfo']['audioFormat']
                                if 'audioCodecID' in movie['movieFile'][
                                        'mediaInfo']:
                                    audioCodecID = movie['movieFile'][
                                        'mediaInfo']['audioCodecID']
                                if 'audioProfile' in movie['movieFile'][
                                        'mediaInfo']:
                                    audioProfile = movie['movieFile'][
                                        'mediaInfo']['audioProfile']
                                if 'audioAdditionalFeatures' in movie[
                                        'movieFile']['mediaInfo']:
                                    audioAdditionalFeatures = movie[
                                        'movieFile']['mediaInfo'][
                                            'audioAdditionalFeatures']
                                audioCodec = RadarrFormatAudioCodec(
                                    audioFormat, audioCodecID, audioProfile,
                                    audioAdditionalFeatures)
                            else:
                                videoCodec = None
                                audioCodec = None

                            # Add movies in radarr to current movies list
                            current_movies_radarr.append(
                                unicode(movie['tmdbId']))

                            if unicode(
                                    movie['tmdbId']) in current_movies_db_list:
                                movies_to_update.append({
                                    'radarr_id':
                                    movie["id"],
                                    'title':
                                    unicode(movie["title"]),
                                    'path':
                                    unicode(
                                        movie["path"] + separator +
                                        movie['movieFile']['relativePath']),
                                    'tmdb_id':
                                    unicode(movie["tmdbId"]),
                                    'poster':
                                    unicode(poster),
                                    'fanart':
                                    unicode(fanart),
                                    'audio_language':
                                    unicode(
                                        profile_id_to_language(
                                            movie['qualityProfileId'],
                                            audio_profiles)),
                                    'scene_name':
                                    sceneName,
                                    'monitored':
                                    unicode(bool(movie['monitored'])),
                                    'year':
                                    unicode(movie['year']),
                                    'sort_title':
                                    unicode(movie['sortTitle']),
                                    'alternative_titles':
                                    unicode(alternativeTitles),
                                    'format':
                                    unicode(format),
                                    'resolution':
                                    unicode(resolution),
                                    'video_codec':
                                    unicode(videoCodec),
                                    'audio_codec':
                                    unicode(audioCodec),
                                    'overview':
                                    unicode(overview),
                                    'imdb_id':
                                    unicode(imdbId),
                                    'movie_file_id':
                                    movie['movieFile']['id']
                                })
                            else:
                                if movie_default_enabled is True:
                                    movies_to_add.append({
                                        'radarr_id':
                                        movie["id"],
                                        'title':
                                        movie["title"],
                                        'path':
                                        movie["path"] + separator +
                                        movie['movieFile']['relativePath'],
                                        'tmdb_id':
                                        movie["tmdbId"],
                                        'languages':
                                        movie_default_language,
                                        'subtitles':
                                        '[]',
                                        'hearing_impaired':
                                        movie_default_hi,
                                        'overview':
                                        overview,
                                        'poster':
                                        poster,
                                        'fanart':
                                        fanart,
                                        'audio_language':
                                        profile_id_to_language(
                                            movie['qualityProfileId'],
                                            audio_profiles),
                                        'scene_name':
                                        sceneName,
                                        'monitored':
                                        unicode(bool(movie['monitored'])),
                                        'sort_title':
                                        movie['sortTitle'],
                                        'year':
                                        movie['year'],
                                        'alternative_titles':
                                        alternativeTitles,
                                        'format':
                                        format,
                                        'resolution':
                                        resolution,
                                        'video_codec':
                                        videoCodec,
                                        'audio_codec':
                                        audioCodec,
                                        'imdb_id':
                                        imdbId,
                                        'forced':
                                        movie_default_forced,
                                        'movie_file_id':
                                        movie['movieFile']['id']
                                    })
                                else:
                                    movies_to_add.append({
                                        'radarr_id':
                                        movie["id"],
                                        'title':
                                        movie["title"],
                                        'path':
                                        movie["path"] + separator +
                                        movie['movieFile']['relativePath'],
                                        'tmdb_id':
                                        movie["tmdbId"],
                                        'overview':
                                        overview,
                                        'poster':
                                        poster,
                                        'fanart':
                                        fanart,
                                        'audio_language':
                                        profile_id_to_language(
                                            movie['qualityProfileId'],
                                            audio_profiles),
                                        'scene_name':
                                        sceneName,
                                        'monitored':
                                        unicode(bool(movie['monitored'])),
                                        'sort_title':
                                        movie['sortTitle'],
                                        'year':
                                        movie['year'],
                                        'alternative_titles':
                                        alternativeTitles,
                                        'format':
                                        format,
                                        'resolution':
                                        resolution,
                                        'video_codec':
                                        videoCodec,
                                        'audio_codec':
                                        audioCodec,
                                        'imdb_id':
                                        imdbId,
                                        'movie_file_id':
                                        movie['movieFile']['id']
                                    })
                        else:
                            logging.error(
                                'BAZARR Radarr returned a movie without a file path: '
                                + movie["path"] + separator +
                                movie['movieFile']['relativePath'])

            # Update or insert movies in DB
            movies_in_db_list = []
            movies_in_db = TableMovies.select(
                TableMovies.radarr_id, TableMovies.title, TableMovies.path,
                TableMovies.tmdb_id, TableMovies.overview, TableMovies.poster,
                TableMovies.fanart, TableMovies.audio_language,
                TableMovies.scene_name, TableMovies.monitored,
                TableMovies.sort_title, TableMovies.year,
                TableMovies.alternative_titles, TableMovies.format,
                TableMovies.resolution, TableMovies.video_codec,
                TableMovies.audio_codec, TableMovies.imdb_id,
                TableMovies.movie_file_id).dicts()

            for item in movies_in_db:
                movies_in_db_list.append(item)

            movies_to_update_list = [
                i for i in movies_to_update if i not in movies_in_db_list
            ]

            for updated_movie in movies_to_update_list:
                TableMovies.update(updated_movie).where(
                    TableMovies.radarr_id ==
                    updated_movie['radarr_id']).execute()
                altered_movies.append([
                    updated_movie['tmdb_id'], updated_movie['path'],
                    updated_movie['radarr_id']
                ])

            # Insert new movies in DB
            for added_movie in movies_to_add:
                TableMovies.insert(added_movie).on_conflict_ignore().execute()
                altered_movies.append([
                    added_movie['tmdb_id'], added_movie['path'],
                    added_movie['radarr_id']
                ])

            # Remove old movies from DB
            removed_movies = list(
                set(current_movies_db_list) - set(current_movies_radarr))

            for removed_movie in removed_movies:
                TableMovies.delete().where(
                    TableMovies.tmdb_id == removed_movie).execute()

            # Store subtitles for added or modified movies
            for i, altered_movie in enumerate(altered_movies, 1):
                notifications.write(
                    msg='Indexing movies embedded subtitles...',
                    queue='get_movies',
                    item=i,
                    length=len(altered_movies))
                store_subtitles_movie(path_replace_movie(altered_movie[1]))
                list_missing_subtitles_movies(altered_movie[2])

            logging.debug(
                'BAZARR All movies synced from Radarr into database.')

            # Search for desired subtitles if no more than 5 movies have been added.
            if len(altered_movies) <= 5:
                logging.debug(
                    "BAZARR No more than 5 movies were added during this sync then we'll search for subtitles."
                )
                for altered_movie in altered_movies:
                    movies_download_subtitles(altered_movie[2])
            else:
                logging.debug(
                    "BAZARR More than 5 movies were added during this sync then we wont search for subtitles."
                )
Example #27
0
def process_subtitle(subtitle,
                     media_type,
                     audio_language,
                     path,
                     max_score,
                     is_upgrade=False,
                     is_manual=False):
    use_postprocessing = settings.general.getboolean('use_postprocessing')
    postprocessing_cmd = settings.general.postprocessing_cmd

    downloaded_provider = subtitle.provider_name
    downloaded_language_code3 = _get_download_code3(subtitle)

    downloaded_language = language_from_alpha3(downloaded_language_code3)
    downloaded_language_code2 = alpha2_from_alpha3(downloaded_language_code3)
    audio_language_code2 = alpha2_from_language(audio_language)
    audio_language_code3 = alpha3_from_language(audio_language)
    downloaded_path = subtitle.storage_path
    subtitle_id = subtitle.id
    if subtitle.language.hi:
        modifier_string = " HI"
    elif subtitle.language.forced:
        modifier_string = " forced"
    else:
        modifier_string = ""
    logging.debug('BAZARR Subtitles file saved to disk: ' + downloaded_path)
    if is_upgrade:
        action = "upgraded"
    elif is_manual:
        action = "manually downloaded"
    else:
        action = "downloaded"

    percent_score = round(subtitle.score * 100 / max_score, 2)
    message = downloaded_language + modifier_string + " subtitles " + action + " from " + \
        downloaded_provider + " with a score of " + str(percent_score) + "%."

    if media_type == 'series':
        episode_metadata = TableEpisodes.select(TableEpisodes.sonarrSeriesId,
                                                TableEpisodes.sonarrEpisodeId) \
            .where(TableEpisodes.path == path_mappings.path_replace_reverse(path)) \
            .dicts() \
            .get_or_none()
        if not episode_metadata:
            return
        series_id = episode_metadata['sonarrSeriesId']
        episode_id = episode_metadata['sonarrEpisodeId']
        sync_subtitles(video_path=path,
                       srt_path=downloaded_path,
                       forced=subtitle.language.forced,
                       srt_lang=downloaded_language_code2,
                       media_type=media_type,
                       percent_score=percent_score,
                       sonarr_series_id=episode_metadata['sonarrSeriesId'],
                       sonarr_episode_id=episode_metadata['sonarrEpisodeId'])
    else:
        movie_metadata = TableMovies.select(TableMovies.radarrId) \
            .where(TableMovies.path == path_mappings.path_replace_reverse_movie(path)) \
            .dicts() \
            .get_or_none()
        if not movie_metadata:
            return
        series_id = ""
        episode_id = movie_metadata['radarrId']
        sync_subtitles(video_path=path,
                       srt_path=downloaded_path,
                       forced=subtitle.language.forced,
                       srt_lang=downloaded_language_code2,
                       media_type=media_type,
                       percent_score=percent_score,
                       radarr_id=movie_metadata['radarrId'])

    if use_postprocessing is True:
        command = pp_replace(postprocessing_cmd, path, downloaded_path,
                             downloaded_language, downloaded_language_code2,
                             downloaded_language_code3, audio_language,
                             audio_language_code2, audio_language_code3,
                             subtitle.language.forced, percent_score,
                             subtitle_id, downloaded_provider, series_id,
                             episode_id, subtitle.language.hi)

        if media_type == 'series':
            use_pp_threshold = settings.general.getboolean(
                'use_postprocessing_threshold')
            pp_threshold = int(settings.general.postprocessing_threshold)
        else:
            use_pp_threshold = settings.general.getboolean(
                'use_postprocessing_threshold_movie')
            pp_threshold = int(settings.general.postprocessing_threshold_movie)

        if not use_pp_threshold or (use_pp_threshold
                                    and percent_score < pp_threshold):
            logging.debug(
                "BAZARR Using post-processing command: {}".format(command))
            postprocessing(command, path)
        else:
            logging.debug(
                "BAZARR post-processing skipped because subtitles score isn't below this "
                "threshold value: " + str(pp_threshold) + "%")

    if media_type == 'series':
        reversed_path = path_mappings.path_replace_reverse(path)
        reversed_subtitles_path = path_mappings.path_replace_reverse(
            downloaded_path)
        notify_sonarr(episode_metadata['sonarrSeriesId'])
        event_stream(type='series',
                     action='update',
                     payload=episode_metadata['sonarrSeriesId'])
        event_stream(type='episode-wanted',
                     action='delete',
                     payload=episode_metadata['sonarrEpisodeId'])

    else:
        reversed_path = path_mappings.path_replace_reverse_movie(path)
        reversed_subtitles_path = path_mappings.path_replace_reverse_movie(
            downloaded_path)
        notify_radarr(movie_metadata['radarrId'])
        event_stream(type='movie-wanted',
                     action='delete',
                     payload=movie_metadata['radarrId'])

    track_event(category=downloaded_provider,
                action=action,
                label=downloaded_language)

    return message, reversed_path, downloaded_language_code2, downloaded_provider, subtitle.score, \
        subtitle.language.forced, subtitle.id, reversed_subtitles_path, subtitle.language.hi
Example #28
0
def update_movies(send_event=True):
    check_radarr_rootfolder()
    logging.debug('BAZARR Starting movie sync from Radarr.')
    apikey_radarr = settings.radarr.apikey

    movie_default_enabled = settings.general.getboolean(
        'movie_default_enabled')

    if movie_default_enabled is True:
        movie_default_profile = settings.general.movie_default_profile
        if movie_default_profile == '':
            movie_default_profile = None
    else:
        movie_default_profile = None

    if apikey_radarr is None:
        pass
    else:
        audio_profiles = get_profile_list()
        tagsDict = get_tags()

        # Get movies data from radarr
        movies = get_movies_from_radarr_api(url=url_radarr(),
                                            apikey_radarr=apikey_radarr)
        if not movies:
            return
        else:
            # Get current movies in DB
            current_movies_db = TableMovies.select(
                TableMovies.tmdbId, TableMovies.path,
                TableMovies.radarrId).dicts()

            current_movies_db_list = [x['tmdbId'] for x in current_movies_db]

            current_movies_radarr = []
            movies_to_update = []
            movies_to_add = []
            altered_movies = []

            # Build new and updated movies
            movies_count = len(movies)
            for i, movie in enumerate(movies):
                if send_event:
                    show_progress(id='movies_progress',
                                  header='Syncing movies...',
                                  name=movie['title'],
                                  value=i,
                                  count=movies_count)

                if movie['hasFile'] is True:
                    if 'movieFile' in movie:
                        if movie['movieFile']['size'] > 20480:
                            # Add movies in radarr to current movies list
                            current_movies_radarr.append(str(movie['tmdbId']))

                            if str(movie['tmdbId']) in current_movies_db_list:
                                movies_to_update.append(
                                    movieParser(movie,
                                                action='update',
                                                tags_dict=tagsDict,
                                                movie_default_profile=
                                                movie_default_profile,
                                                audio_profiles=audio_profiles))
                            else:
                                movies_to_add.append(
                                    movieParser(movie,
                                                action='insert',
                                                tags_dict=tagsDict,
                                                movie_default_profile=
                                                movie_default_profile,
                                                audio_profiles=audio_profiles))

            if send_event:
                hide_progress(id='movies_progress')

            # Remove old movies from DB
            removed_movies = list(
                set(current_movies_db_list) - set(current_movies_radarr))

            for removed_movie in removed_movies:
                try:
                    TableMovies.delete().where(
                        TableMovies.tmdbId == removed_movie).execute()
                except Exception as e:
                    logging.error(
                        f"BAZARR cannot remove movie tmdbId {removed_movie} because of {e}"
                    )
                    continue

            # Update movies in DB
            movies_in_db_list = []
            movies_in_db = TableMovies.select(
                TableMovies.radarrId, TableMovies.title, TableMovies.path,
                TableMovies.tmdbId, TableMovies.overview, TableMovies.poster,
                TableMovies.fanart, TableMovies.audio_language,
                TableMovies.sceneName, TableMovies.monitored,
                TableMovies.sortTitle, TableMovies.year,
                TableMovies.alternativeTitles, TableMovies.format,
                TableMovies.resolution, TableMovies.video_codec,
                TableMovies.audio_codec, TableMovies.imdbId,
                TableMovies.movie_file_id, TableMovies.tags,
                TableMovies.file_size).dicts()

            for item in movies_in_db:
                movies_in_db_list.append(item)

            movies_to_update_list = [
                i for i in movies_to_update if i not in movies_in_db_list
            ]

            for updated_movie in movies_to_update_list:
                try:
                    TableMovies.update(updated_movie).where(
                        TableMovies.tmdbId ==
                        updated_movie['tmdbId']).execute()
                except IntegrityError as e:
                    logging.error(
                        f"BAZARR cannot update movie {updated_movie['path']} because of {e}"
                    )
                    continue
                else:
                    altered_movies.append([
                        updated_movie['tmdbId'], updated_movie['path'],
                        updated_movie['radarrId'], updated_movie['monitored']
                    ])

            # Insert new movies in DB
            for added_movie in movies_to_add:
                try:
                    result = TableMovies.insert(added_movie).on_conflict(
                        action='IGNORE').execute()
                except IntegrityError as e:
                    logging.error(
                        f"BAZARR cannot insert movie {added_movie['path']} because of {e}"
                    )
                    continue
                else:
                    if result > 0:
                        altered_movies.append([
                            added_movie['tmdbId'], added_movie['path'],
                            added_movie['radarrId'], added_movie['monitored']
                        ])
                        if send_event:
                            event_stream(type='movie',
                                         action='update',
                                         payload=int(added_movie['radarrId']))
                    else:
                        logging.debug(
                            'BAZARR unable to insert this movie into the database:',
                            path_mappings.path_replace_movie(
                                added_movie['path']))

            # Store subtitles for added or modified movies
            for i, altered_movie in enumerate(altered_movies, 1):
                store_subtitles_movie(
                    altered_movie[1],
                    path_mappings.path_replace_movie(altered_movie[1]))

            logging.debug(
                'BAZARR All movies synced from Radarr into database.')
Example #29
0
    def post(self):
        json_webhook = request.form.get('payload')
        parsed_json_webhook = json.loads(json_webhook)

        event = parsed_json_webhook['event']
        if event not in ['media.play']:
            return '', 204

        media_type = parsed_json_webhook['Metadata']['type']

        if media_type == 'episode':
            season = parsed_json_webhook['Metadata']['parentIndex']
            episode = parsed_json_webhook['Metadata']['index']
        else:
            season = episode = None

        ids = []
        for item in parsed_json_webhook['Metadata']['Guid']:
            splitted_id = item['id'].split('://')
            if len(splitted_id) == 2:
                ids.append({splitted_id[0]: splitted_id[1]})
        if not ids:
            return '', 404

        if media_type == 'episode':
            try:
                episode_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0]
                r = requests.get(
                    'https://imdb.com/title/{}'.format(episode_imdb_id),
                    headers={"User-Agent": os.environ["SZ_USER_AGENT"]})
                soup = bso(r.content, "html.parser")
                series_imdb_id = soup.find(
                    'a',
                    {'class': re.compile(r'SeriesParentLink__ParentTextLink')
                     })['href'].split('/')[2]
            except:
                return '', 404
            else:
                sonarrEpisodeId = TableEpisodes.select(TableEpisodes.sonarrEpisodeId) \
                    .join(TableShows, on=(TableEpisodes.sonarrSeriesId == TableShows.sonarrSeriesId)) \
                    .where(TableShows.imdbId == series_imdb_id,
                           TableEpisodes.season == season,
                           TableEpisodes.episode == episode) \
                    .dicts() \
                    .get()

                if sonarrEpisodeId:
                    episode_download_subtitles(
                        no=sonarrEpisodeId['sonarrEpisodeId'],
                        send_progress=True)
        else:
            try:
                movie_imdb_id = [x['imdb'] for x in ids if 'imdb' in x][0]
            except:
                return '', 404
            else:
                radarrId = TableMovies.select(TableMovies.radarrId)\
                    .where(TableMovies.imdbId == movie_imdb_id)\
                    .dicts()\
                    .get()
                if radarrId:
                    movies_download_subtitles(no=radarrId['radarrId'])

        return '', 200
Example #30
0
def update_one_movie(movie_id, action):
    logging.debug(
        'BAZARR syncing this specific movie from Radarr: {}'.format(movie_id))

    # Check if there's a row in database for this movie ID
    existing_movie = TableMovies.select(TableMovies.path)\
        .where(TableMovies.radarrId == movie_id)\
        .dicts()\
        .get_or_none()

    # Remove movie from DB
    if action == 'deleted':
        if existing_movie:
            try:
                TableMovies.delete().where(
                    TableMovies.radarrId == movie_id).execute()
            except Exception as e:
                logging.error(
                    f"BAZARR cannot delete movie {existing_movie['path']} because of {e}"
                )
            else:
                event_stream(type='movie',
                             action='delete',
                             payload=int(movie_id))
                logging.debug(
                    'BAZARR deleted this movie from the database:{}'.format(
                        path_mappings.path_replace_movie(
                            existing_movie['path'])))
        return

    movie_default_enabled = settings.general.getboolean(
        'movie_default_enabled')

    if movie_default_enabled is True:
        movie_default_profile = settings.general.movie_default_profile
        if movie_default_profile == '':
            movie_default_profile = None
    else:
        movie_default_profile = None

    audio_profiles = get_profile_list()
    tagsDict = get_tags()

    try:
        # Get movie data from radarr api
        movie = None
        movie_data = get_movies_from_radarr_api(
            url=url_radarr(),
            apikey_radarr=settings.radarr.apikey,
            radarr_id=movie_id)
        if not movie_data:
            return
        else:
            if action == 'updated' and existing_movie:
                movie = movieParser(
                    movie_data,
                    action='update',
                    tags_dict=tagsDict,
                    movie_default_profile=movie_default_profile,
                    audio_profiles=audio_profiles)
            elif action == 'updated' and not existing_movie:
                movie = movieParser(
                    movie_data,
                    action='insert',
                    tags_dict=tagsDict,
                    movie_default_profile=movie_default_profile,
                    audio_profiles=audio_profiles)
    except Exception:
        logging.debug(
            'BAZARR cannot get movie returned by SignalR feed from Radarr API.'
        )
        return

    # Drop useless events
    if not movie and not existing_movie:
        return

    # Remove movie from DB
    if not movie and existing_movie:
        try:
            TableMovies.delete().where(
                TableMovies.radarrId == movie_id).execute()
        except Exception as e:
            logging.error(
                f"BAZARR cannot insert episode {existing_movie['path']} because of {e}"
            )
        else:
            event_stream(type='movie', action='delete', payload=int(movie_id))
            logging.debug(
                'BAZARR deleted this movie from the database:{}'.format(
                    path_mappings.path_replace_movie(existing_movie['path'])))
            return

    # Update existing movie in DB
    elif movie and existing_movie:
        try:
            TableMovies.update(movie).where(
                TableMovies.radarrId == movie['radarrId']).execute()
        except IntegrityError as e:
            logging.error(
                f"BAZARR cannot insert episode {movie['path']} because of {e}")
        else:
            event_stream(type='movie', action='update', payload=int(movie_id))
            logging.debug(
                'BAZARR updated this movie into the database:{}'.format(
                    path_mappings.path_replace_movie(movie['path'])))

    # Insert new movie in DB
    elif movie and not existing_movie:
        try:
            TableMovies.insert(movie).on_conflict(action='IGNORE').execute()
        except IntegrityError as e:
            logging.error(
                f"BAZARR cannot insert movie {movie['path']} because of {e}")
        else:
            event_stream(type='movie', action='update', payload=int(movie_id))
            logging.debug(
                'BAZARR inserted this movie into the database:{}'.format(
                    path_mappings.path_replace_movie(movie['path'])))

    # Storing existing subtitles
    logging.debug('BAZARR storing subtitles for this movie: {}'.format(
        path_mappings.path_replace_movie(movie['path'])))
    store_subtitles_movie(movie['path'],
                          path_mappings.path_replace_movie(movie['path']))

    # Downloading missing subtitles
    logging.debug(
        'BAZARR downloading missing subtitles for this movie: {}'.format(
            path_mappings.path_replace_movie(movie['path'])))
    movies_download_subtitles(movie_id)