예제 #1
0
def post_process(wanted_item_index, subtitle_index):
    log.info('Post processing an individual subtitle')

    # Get wanted queue lock
    if not get_wanted_queue_lock():
        return False

    # Get wanted item
    wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]
    found_subtitles = wanted_item.found_subtitles
    subtitles = found_subtitles['subtitles']
    language = found_subtitles['language']
    single = found_subtitles['single']

    # Only execute post processing when a subtitle is present
    processed = False
    subtitle_path = _get_subtitle_path(wanted_item)
    if os.path.exists(subtitle_path):
        # Get wanted subtitle
        wanted_subtitle = _get_wanted_subtitle(subtitles, subtitle_index)

        # Handle download
        download_item = _construct_download_item(wanted_item, [wanted_subtitle], language, single)
        downloader = SubDownloader(download_item)
        downloader.mark_downloaded()
        processed = downloader.post_process()

        if processed:
            # Remove downloaded language from wanted languages
            wanted_item.languages.remove(language)

            # Update wanted item if there are still wanted languages
            if len(wanted_item.languages) > 0:
                WantedItemsDb().update_wanted_item(wanted_item)

            # Remove wanted item if there are no more wanted languages
            else:
                # Remove wanted item
                autosubliminal.WANTEDQUEUE.pop(int(wanted_item_index))
                log.debug('Removed item from the wanted queue at index %s', int(wanted_item_index))
                WantedItemsDb().delete_wanted_item(wanted_item)
                log.debug('Removed %s from wanted_items database', wanted_item.videopath)

    else:
        log.warning('No subtitle downloaded, skipping post processing')

    # Release wanted queue lock
    release_wanted_queue_lock()

    return processed
예제 #2
0
    def put(self, imdb_id):
        """Save the settings for a movie."""
        input_json = cherrypy.request.json

        if all(k in input_json for k in ('wanted_languages', 'refine',
                                         'hearing_impaired', 'utf8_encoding')):
            wanted_languages = input_json['wanted_languages']
            refine = get_boolean(input_json['refine'])
            hearing_impaired = get_boolean(input_json['hearing_impaired'])
            utf8_encoding = get_boolean(input_json['utf8_encoding'])

            # Update settings
            db = MovieSettingsDb()
            movie_settings = db.get_movie_settings(imdb_id)
            movie_settings.wanted_languages = wanted_languages
            movie_settings.refine = refine
            movie_settings.hearing_impaired = hearing_impaired
            movie_settings.utf8_encoding = utf8_encoding
            db.update_movie_settings(movie_settings)

            # Delete wanted items for the movie so the new settings will be used in the next disk scan
            WantedItemsDb().delete_wanted_items_for_movie(imdb_id)

            # Send notification
            send_websocket_notification(
                'Settings will be applied on next disk scan.')

            return self._no_content()

        return self._bad_request('Missing data')
예제 #3
0
def post_process_no_subtitle(wanted_item_index):
    log.info('Post processing without subtitle')

    # Get wanted queue lock
    if not get_wanted_queue_lock():
        return False

    # Get wanted item
    wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]

    # Post process only (no need to check for individual or not because we are forcing post processing)
    processed = PostProcessor(wanted_item).run()

    # Remove wanted item if processed
    if processed:
        autosubliminal.WANTEDQUEUE.pop(int(wanted_item_index))
        log.debug('Removed item from the wanted queue at index %s', int(wanted_item_index))
        WantedItemsDb().delete_wanted_item(wanted_item)
        log.debug('Removed %s from wanted_items database', wanted_item.videopath)
    else:
        send_websocket_notification('Unable to handle post processing! Please check the log file!', type='error')

    # Release wanted queue lock
    release_wanted_queue_lock()

    return processed
예제 #4
0
def skip_show(wanted_item_index, season):
    log.info('Skipping a show')

    # Get wanted queue lock
    if not get_wanted_queue_lock():
        return False

    # Get wanted item
    wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]
    show = wanted_item.title

    # Remove all wanted items for the same show and season
    to_delete_wanted_queue = []
    for index, item in enumerate(autosubliminal.WANTEDQUEUE):
        if item.title == show:
            # Skip show all seasons
            if season == '00':
                to_delete_wanted_queue.append(index)
            # Skip season (and specials = season 0)
            elif season == item.season:
                to_delete_wanted_queue.append(index)
    # Start at the end to delete to prevent index out of range error
    i = len(to_delete_wanted_queue) - 1
    while i >= 0:
        wanted_item_to_delete = autosubliminal.WANTEDQUEUE.pop(to_delete_wanted_queue[i])
        WantedItemsDb().delete_wanted_item(wanted_item_to_delete)
        i -= 1
    log.info('Skipped show %s season %s', show, season)

    # Release wanted queue lock
    release_wanted_queue_lock()

    return True
예제 #5
0
def force_id_search(wanted_item_index):
    log.info('Force id search')

    # Get wanted queue lock
    if not get_wanted_queue_lock():
        return

    # Force id search
    wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]
    title = wanted_item.title
    year = wanted_item.year
    if wanted_item.is_episode:
        wanted_item.tvdbid = autosubliminal.SHOWINDEXER.get_tvdb_id(title, year, force_search=True)
        WantedItemsDb().update_wanted_item(wanted_item)
    elif wanted_item.is_movie:
        wanted_item.imdbid, wanted_item.year = autosubliminal.MOVIEINDEXER.get_imdb_id_and_year(title, year,
                                                                                                force_search=True)
        WantedItemsDb().update_wanted_item(wanted_item)

    # Release wanted queue lock
    release_wanted_queue_lock()
예제 #6
0
def delete_video(wanted_item_index, cleanup):
    log.info('Deleting an individual video file')

    # Get wanted queue lock
    if not get_wanted_queue_lock():
        return False

    # Remove wanted item
    wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]
    autosubliminal.WANTEDQUEUE.pop(int(wanted_item_index))
    log.debug('Removed item from the wanted queue at index %s', int(wanted_item_index))
    WantedItemsDb().delete_wanted_item(wanted_item)
    log.debug('Removed %s from wanted_items database', wanted_item.videopath)

    # Physically delete the video file (and optionally leftovers)
    deleted = False
    video_path = wanted_item.videopath
    # Delete with cleanup
    if cleanup:
        norm_video_path = os.path.normcase(os.path.normpath(video_path))
        norm_video_folder = os.path.dirname(norm_video_path).rstrip(os.sep)
        for root_folder in autosubliminal.VIDEOPATHS:
            # Get root folder
            norm_root_folder = os.path.normcase(os.path.normpath(root_folder)).rstrip(os.sep)
            # Check if video is located in subfolder underneath root folder
            if os.path.commonprefix([norm_root_folder, norm_video_path]) == norm_root_folder:
                if norm_video_folder != norm_root_folder:
                    # Move up until the first subfolder underneath the root folder to cleanup
                    while norm_video_folder != norm_root_folder:
                        folder_to_clean = norm_video_folder
                        norm_video_folder = os.path.dirname(norm_video_folder).rstrip(os.sep)
                    try:
                        # Remove the folder of the video underneath the root folder
                        shutil.rmtree(folder_to_clean, onerror=set_rw_and_remove)
                        log.info('Deleted video folder: %s', folder_to_clean)
                        deleted = True
                        # Break for loop
                        break
                    except Exception:
                        log.exception('Unable to delete video folder: %s', folder_to_clean)
    # Delete video file only
    if not deleted:
        try:
            os.remove(video_path)
            log.info('Deleted file: %s', video_path)
            deleted = True
        except Exception:
            log.exception('Unable to delete file: %s', video_path)

    # Release wanted queue lock
    release_wanted_queue_lock()

    return deleted
예제 #7
0
    def reset_wanted_item(self, wanted_item_index, **kwargs):
        if get_wanted_queue_lock():
            # Get wanted item and reset values
            wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]
            wanted_item_db = WantedItemsDb().get_wanted_item(
                wanted_item.videopath)
            wanted_item_db.copy_to(wanted_item)

            # Release wanted queue lock
            release_wanted_queue_lock()

            # Only return updatable fields
            # These values represent the original values, so apply default display_value() on it!
            return {
                'displaytitle':
                display_item_title(wanted_item),
                'title':
                display_value(wanted_item.title),
                'year':
                display_value(wanted_item.year),
                'season':
                display_value(wanted_item.season),
                'episode':
                display_value(wanted_item.episode),
                'source':
                display_value(wanted_item.source, default_value='N/A'),
                'quality':
                display_value(wanted_item.quality, default_value='N/A'),
                'codec':
                display_value(wanted_item.codec, default_value='N/A'),
                'releasegrp':
                display_value(wanted_item.releasegrp, default_value='N/A')
            }

        # Show notification if wanted queue is in use
        send_websocket_notification(
            'Cannot reset wanted item when wanted queue is in use!',
            type='notice')
예제 #8
0
    def reset_wanted_item(self, wanted_item_index, **kwargs):
        if get_wanted_queue_lock():
            # Get wanted item and reset values
            wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)]
            wanted_item_db = WantedItemsDb().get_wanted_item(wanted_item.videopath)
            wanted_item_db.copy_to(wanted_item)

            # Release wanted queue lock
            release_wanted_queue_lock()

            # Only return updatable fields
            # These values represent the original values, so apply default display_value() on it!
            return {'displaytitle': display_item_title(wanted_item),
                    'title': display_value(wanted_item.title),
                    'year': display_value(wanted_item.year),
                    'season': display_value(wanted_item.season),
                    'episode': display_value(wanted_item.episode),
                    'source': display_value(wanted_item.source, default_value='N/A'),
                    'quality': display_value(wanted_item.quality, default_value='N/A'),
                    'codec': display_value(wanted_item.codec, default_value='N/A'),
                    'releasegrp': display_value(wanted_item.releasegrp, default_value='N/A')}

        # Show notification if wanted queue is in use
        send_websocket_notification('Cannot reset wanted item when wanted queue is in use!', type='notice')
예제 #9
0
def skip_movie(wanted_item_index):
    log.info('Skipping a movie')

    # Get wanted queue lock
    if not get_wanted_queue_lock():
        return False

    # Remove wanted item from queue and db
    wanted_item = autosubliminal.WANTEDQUEUE.pop(int(wanted_item_index))
    WantedItemsDb().delete_wanted_item(wanted_item)
    movie = wanted_item.title
    if wanted_item.year:
        movie += ' (' + wanted_item.year + ')'
    log.info('Skipped movie %s', movie)

    # Release wanted queue lock
    release_wanted_queue_lock()

    return True
예제 #10
0
    def run(self, force_run):
        log.info('Starting round of subtitle checking')

        # Wait for internet connection
        wait_for_internet_connection()

        # Show info message (only when run was forced manually)
        if force_run:
            send_websocket_notification('Checking subtitles...')

        to_delete_wanted_queue = []

        # Setup provider pool
        provider_pool = _get_provider_pool()
        if provider_pool:
            log.info('Searching subtitles with providers: %s', ', '.join(provider_pool.providers))

            # Process all items in wanted queue
            db = WantedItemsDb()
            for index, wanted_item in enumerate(autosubliminal.WANTEDQUEUE):
                log.info('Searching subtitles for video: %s', wanted_item.videopath)

                # Check if the search is currently active for the wanted_item
                if not wanted_item.is_search_active:
                    log.info('Search not active in this run for video: %s', wanted_item.videopath)
                    continue

                # Scan wanted_item for video, skip when no video could be determined
                video = _scan_wanted_item_for_video(wanted_item)
                if not video:
                    continue

                # Clear discarded providers for each new wanted_item
                provider_pool.discarded_providers.clear()

                # Check subtitles for each language
                languages = wanted_item.languages
                for lang in languages[:]:
                    # Search the best subtitle with the minimal score
                    try:
                        subtitles, language, single = _search_subtitles(video, lang, True, provider_pool)
                    except Exception:
                        log.exception('Error while searching subtitles for video %r', wanted_item.videopath)
                        continue

                    # Subtitle is found for the video
                    if subtitles:
                        # Handle download
                        download_item = _construct_download_item(wanted_item, subtitles, language, single)
                        SubDownloader(download_item).run()

                        # Remove downloaded language from wanted languages
                        languages.remove(lang)

                        # Update wanted item if there are still wanted languages
                        if len(languages) > 0:
                            db.update_wanted_item(wanted_item)

                        # Mark wanted item as deleted if there are no more wanted languages
                        else:
                            to_delete_wanted_queue.append(index)

            # Cleanup wanted item(s)
            i = len(to_delete_wanted_queue) - 1
            while i >= 0:
                wanted_item_to_delete = autosubliminal.WANTEDQUEUE.pop(to_delete_wanted_queue[i])
                log.debug('Removed item from the wanted queue at index %s', to_delete_wanted_queue[i])
                db.delete_wanted_item(wanted_item_to_delete)
                log.debug('Removed %s from wanted_items database', wanted_item_to_delete.videopath)
                i -= 1

        else:
            log.info('No subliminal providers configured, skipping')

        # Send home page reload event
        send_websocket_event(PAGE_RELOAD, data={'name': 'home'})

        log.info('Finished round of subtitle checking')
예제 #11
0
 def __init__(self):
     super(DiskScanner, self).__init__()
     self.wanted_db = WantedItemsDb()
     self.show_settings_db = ShowSettingsDb()
     self.movie_settings_db = MovieSettingsDb()
예제 #12
0
class DiskScanner(ScheduledProcess):
    """Disk scanner.

    Scan the specified path for episodes and movies with missing subtitles.
    If found, episodes and movies are added to the WANTEDQUEUE.
    """

    def __init__(self):
        super(DiskScanner, self).__init__()
        self.wanted_db = WantedItemsDb()
        self.show_settings_db = ShowSettingsDb()
        self.movie_settings_db = MovieSettingsDb()

    @release_wanted_queue_lock_on_exception
    def run(self, force_run):
        paths = autosubliminal.VIDEOPATHS
        log.info('Starting round of local disk checking at %r', paths)

        # Show info message (only when run was forced manually)
        if force_run:
            send_websocket_notification('Scanning disk...')

        # Check if a path exists to scan
        if not one_path_exists(paths):
            log.error('None of the configured video paths (%r) exists, aborting...', paths)
            return

        # Walk through paths to search for wanted items
        new_wanted_items = []
        old_wanted_items = self.wanted_db.get_wanted_items()
        for path in paths:
            try:
                new_wanted_items.extend(self._scan_path(path))
            except Exception:
                log.exception('Could not scan the video path (%s), skipping it', path)

        # Cleanup wanted items that have been removed from disk manually but are still stored in the db
        log.debug('Checking for non existing wanted items in wanted_items database')
        for item in old_wanted_items:
            if item not in new_wanted_items:
                self.wanted_db.delete_wanted_item(item)
                log.debug('Deleted non existing wanted item: %s', item.videopath)

        # Populate WANTEDQUEUE with all items from wanted_items database
        log.info('Listing videos with missing subtitles:')
        autosubliminal.WANTEDQUEUE = []
        for item in self.wanted_db.get_wanted_items():
            log.info('%s %s', item.videopath, item.languages)
            autosubliminal.WANTEDQUEUE.append(item)

        # Send home page reload event
        send_websocket_event(PAGE_RELOAD, data={'name': 'home'})

        log.info('Finished round of local disk checking')

    def _scan_path(self, path):
        log.info('Scanning video path: %s', path)
        wanted_items = []

        # Check all folders and files
        for dirname, dirnames, filenames in os.walk(os.path.join(path)):
            log.debug('Directory: %s', dirname)

            # Ignore skipped dirs
            if is_skipped_dir(dirname):
                continue

            # Check files
            for filename in filenames:

                # Only scan valid video files
                if is_valid_video_file(filename):
                    log.debug('Video file found: %s', filename)
                    wanted_item = None
                    try:
                        wanted_item = self._scan_file(dirname, filename)
                    except Exception:
                        log.exception('Error while scanning video file: %s', os.path.join(dirname, filename))

                    # Add it to list of wanted items
                    if wanted_item:
                        log.debug('Video added to list of wanted items')
                        wanted_items.append(wanted_item)

        return wanted_items

    def _scan_file(self, dirname, filename):
        # Check if video file has already been processed before, so we don't need to process it again
        wanted_item = self.wanted_db.get_wanted_item(os.path.join(dirname, filename))
        if wanted_item:
            log.debug('Video found in wanted_items database, no need to scan it again')
        else:
            log.debug('Video not found in wanted_items database, start scanning it')

            # Process file
            wanted_item = fileprocessor.process_file(dirname, filename)
            if wanted_item:
                # Determine wanted languages
                wanted_languages = []
                if wanted_item.is_episode and wanted_item.tvdbid:
                    settings = self.show_settings_db.get_show_settings(wanted_item.tvdbid)
                    if settings and settings.wanted_languages:
                        wanted_languages = settings.wanted_languages
                elif wanted_item.is_movie and wanted_item.imdbid:
                    settings = self.movie_settings_db.get_movie_settings(wanted_item.imdbid)
                    if settings and settings.wanted_languages:
                        wanted_languages = settings.wanted_languages

                # Check for missing subtitles (scan embedded and detect invalid if configured to do so)
                languages = check_missing_subtitle_languages(dirname, filename,
                                                             scan_embedded=autosubliminal.SCANEMBEDDEDSUBS,
                                                             scan_hardcoded=autosubliminal.SCANHARDCODEDSUBS,
                                                             detect_invalid=autosubliminal.DETECTINVALIDSUBLANGUAGE,
                                                             wanted_languages=wanted_languages)

                # Process the video file if there are missing subtitles
                if len(languages) > 0:
                    # Add missing languages and store in wanted_items database
                    wanted_item.languages = languages
                    self.wanted_db.set_wanted_item(wanted_item)

                else:
                    log.debug('Video has no missing subtitles')
                    return None

            else:
                return None

        # Check if we need to skip it and delete it from the database
        log.debug('Checking if the video needs to be skipped')
        if wanted_item:
            # Skip episode check
            if wanted_item.is_episode:
                title = wanted_item.title
                season = wanted_item.season
                if skip_show(title, season):
                    self.wanted_db.delete_wanted_item(wanted_item)
                    log.info('Skipping %s - Season %s', title, season)
                    return None

            # Skip movie check
            if wanted_item.is_movie:
                title = wanted_item.title
                year = wanted_item.year
                if skip_movie(title, year):
                    self.wanted_db.delete_wanted_item(wanted_item)
                    log.info('Skipping %s (%s)', title, year)
                    return None

        return wanted_item
예제 #13
0
 def __init__(self):
     super(DiskScanner, self).__init__()
     self.wanted_db = WantedItemsDb()
     self.show_settings_db = ShowSettingsDb()
     self.movie_settings_db = MovieSettingsDb()
예제 #14
0
class DiskScanner(ScheduledProcess):
    """Disk scanner.

    Scan the specified path for episodes and movies with missing subtitles.
    If found, episodes and movies are added to the WANTEDQUEUE.
    """
    def __init__(self):
        super(DiskScanner, self).__init__()
        self.wanted_db = WantedItemsDb()
        self.show_settings_db = ShowSettingsDb()
        self.movie_settings_db = MovieSettingsDb()

    @release_wanted_queue_lock_on_exception
    def run(self, force_run):
        paths = autosubliminal.VIDEOPATHS
        log.info('Starting round of local disk checking at %r', paths)

        # Show info message (only when run was forced manually)
        if force_run:
            send_websocket_notification('Scanning disk...')

        # Check if a path exists to scan
        if not one_path_exists(paths):
            log.error(
                'None of the configured video paths (%r) exists, aborting...',
                paths)
            return

        # Walk through paths to search for wanted items
        new_wanted_items = []
        old_wanted_items = self.wanted_db.get_wanted_items()
        for path in paths:
            try:
                new_wanted_items.extend(self._scan_path(path))
            except Exception:
                log.exception(
                    'Could not scan the video path (%s), skipping it', path)

        # Cleanup wanted items that have been removed from disk manually but are still stored in the db
        log.debug(
            'Checking for non existing wanted items in wanted_items database')
        for item in old_wanted_items:
            if item not in new_wanted_items:
                self.wanted_db.delete_wanted_item(item)
                log.debug('Deleted non existing wanted item: %s',
                          item.videopath)

        # Populate WANTEDQUEUE with all items from wanted_items database
        log.info('Listing videos with missing subtitles:')
        autosubliminal.WANTEDQUEUE = []
        for item in self.wanted_db.get_wanted_items():
            log.info('%s %s', item.videopath, item.languages)
            autosubliminal.WANTEDQUEUE.append(item)

        # Send home page reload event
        send_websocket_event(PAGE_RELOAD, data={'name': 'home'})

        log.info('Finished round of local disk checking')

    def _scan_path(self, path):
        log.info('Scanning video path: %s', path)
        wanted_items = []

        # Check all folders and files
        for dirname, dirnames, filenames in os.walk(os.path.join(path)):
            log.debug('Directory: %s', dirname)

            # Ignore skipped dirs
            if is_skipped_dir(dirname):
                continue

            # Check files
            for filename in filenames:

                # Only scan valid video files
                if is_valid_video_file(filename):
                    log.debug('Video file found: %s', filename)
                    wanted_item = None
                    try:
                        wanted_item = self._scan_file(dirname, filename)
                    except Exception:
                        log.exception('Error while scanning video file: %s',
                                      os.path.join(dirname, filename))

                    # Add it to list of wanted items
                    if wanted_item:
                        log.debug('Video added to list of wanted items')
                        wanted_items.append(wanted_item)

        return wanted_items

    def _scan_file(self, dirname, filename):
        # Check if video file has already been processed before, so we don't need to process it again
        wanted_item = self.wanted_db.get_wanted_item(
            os.path.join(dirname, filename))
        if wanted_item:
            log.debug(
                'Video found in wanted_items database, no need to scan it again'
            )
        else:
            log.debug(
                'Video not found in wanted_items database, start scanning it')

            # Process file
            wanted_item = fileprocessor.process_file(dirname, filename)
            if wanted_item:
                # Determine wanted languages
                wanted_languages = []
                if wanted_item.is_episode and wanted_item.tvdbid:
                    settings = self.show_settings_db.get_show_settings(
                        wanted_item.tvdbid)
                    if settings and settings.wanted_languages:
                        wanted_languages = settings.wanted_languages
                elif wanted_item.is_movie and wanted_item.imdbid:
                    settings = self.movie_settings_db.get_movie_settings(
                        wanted_item.imdbid)
                    if settings and settings.wanted_languages:
                        wanted_languages = settings.wanted_languages

                # Check for missing subtitles (scan embedded and detect invalid if configured to do so)
                languages = check_missing_subtitle_languages(
                    dirname,
                    filename,
                    scan_embedded=autosubliminal.SCANEMBEDDEDSUBS,
                    scan_hardcoded=autosubliminal.SCANHARDCODEDSUBS,
                    detect_invalid=autosubliminal.DETECTINVALIDSUBLANGUAGE,
                    wanted_languages=wanted_languages)

                # Process the video file if there are missing subtitles
                if len(languages) > 0:
                    # Add missing languages and store in wanted_items database
                    wanted_item.languages = languages
                    self.wanted_db.set_wanted_item(wanted_item)

                else:
                    log.debug('Video has no missing subtitles')
                    return None

            else:
                return None

        # Check if we need to skip it and delete it from the database
        log.debug('Checking if the video needs to be skipped')
        if wanted_item:
            # Skip episode check
            if wanted_item.is_episode:
                title = wanted_item.title
                season = wanted_item.season
                if skip_show(title, season):
                    self.wanted_db.delete_wanted_item(wanted_item)
                    log.info('Skipping %s - Season %s', title, season)
                    return None

            # Skip movie check
            if wanted_item.is_movie:
                title = wanted_item.title
                year = wanted_item.year
                if skip_movie(title, year):
                    self.wanted_db.delete_wanted_item(wanted_item)
                    log.info('Skipping %s (%s)', title, year)
                    return None

        return wanted_item