def test_wanted_queue_lock(): assert get_wanted_queue_lock() assert autosubliminal.WANTEDQUEUELOCK assert not get_wanted_queue_lock() assert autosubliminal.WANTEDQUEUELOCK release_wanted_queue_lock() assert not autosubliminal.WANTEDQUEUELOCK release_wanted_queue_lock() assert not autosubliminal.WANTEDQUEUELOCK
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
def save_subtitle(wanted_item_index, subtitle_index): log.info('Saving 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'] # Get wanted subtitle wanted_subtitle = _get_wanted_subtitle(subtitles, subtitle_index) # Save subtitle (skip notify and post_process) download_item = _construct_download_item(wanted_item, [wanted_subtitle], language, single) downloaded = SubDownloader(download_item).save() # Release wanted queue lock release_wanted_queue_lock() return downloaded
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
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
def flush_wanted_items(self): if get_wanted_queue_lock(): # Flush db and wanted queue WantedItemsDb().flush_wanted_items() autosubliminal.WANTEDQUEUE = [] release_wanted_queue_lock() send_websocket_notification( 'Flushed wanted items database. Please launch \'Scan Disk\' from the \'System\' menu.') else: send_websocket_notification('Cannot flush wanted items database when wanted queue is in use!', type='notice') redirect('/home')
def update(self, force_update=False): log.info('Updating version') # Only get lock for force run because when called from run, we already have a queue lock if force_update and not get_wanted_queue_lock(): return # Update version self.manager.update_version() # Release wanted queue lock if force_update: release_wanted_queue_lock()
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
def update_wanted_item(self, wanted_item_index, **kwargs): if get_wanted_queue_lock(): # Get wanted item and update all keys that are passed wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)] for key in kwargs: wanted_item.set_attr(key, kwargs[key]) # Release wanted queue lock release_wanted_queue_lock() # Only return updatable fields # These values will be shown in the view through jquery, so apply the 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', uppercase=True), 'quality': display_value(wanted_item.quality, default_value='N/A', uppercase=True), 'codec': display_value(wanted_item.codec, default_value='N/A', uppercase=True), 'releasegrp': display_value(wanted_item.releasegrp, default_value='N/A', uppercase=True) } # Show notification if wanted queue is in use send_websocket_notification( 'Cannot update wanted item when wanted queue is in use!', type='notice')
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
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()
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')
def delete_subtitle(wanted_item_index): log.info('Deleting 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)] # Delete subtitle deleted = False subtitle_path = _get_subtitle_path(wanted_item) try: os.remove(subtitle_path) deleted = True except Exception: log.exception('Unable to delete subtitle: %s', subtitle_path) # Release wanted queue lock release_wanted_queue_lock() return deleted
def _run_process(self, current_time): # Check if the run needs a lock run_lock = self.process.force_run_lock if self._force_run else self.process.run_lock # Delay process if lock cannot be acquired if run_lock and not get_wanted_queue_lock(): # Increase delay with 1 second each time the process cannot yet run self._delay += 1 return try: # Mark as running self.process.running = True send_websocket_event(PROCESS_STARTED, data=self.to_json()) log.debug('Running %s thread process', self.name) self.process.run(self._force_run) # Update process properties after process run self.last_run = current_time self._delay = 0 if self._force_run: self._force_run = False # Mark as finished self.process.running = False send_websocket_event(PROCESS_FINISHED, data=self.to_json()) except: print(traceback.format_exc()) self.process.running = False os._exit(1) finally: # Release lock if needed if run_lock: release_wanted_queue_lock()
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')
def update_wanted_item(self, wanted_item_index, **kwargs): if get_wanted_queue_lock(): # Get wanted item and update all keys that are passed wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)] for key in kwargs: wanted_item.set_attr(key, kwargs[key]) # Release wanted queue lock release_wanted_queue_lock() # Only return updatable fields # These values will be shown in the view through jquery, so apply the 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', uppercase=True), 'quality': display_value(wanted_item.quality, default_value='N/A', uppercase=True), 'codec': display_value(wanted_item.codec, default_value='N/A', uppercase=True), 'releasegrp': display_value(wanted_item.releasegrp, default_value='N/A', uppercase=True)} # Show notification if wanted queue is in use send_websocket_notification('Cannot update wanted item when wanted queue is in use!', type='notice')
def test_function(): get_wanted_queue_lock() assert autosubliminal.WANTEDQUEUELOCK raise Exception('unexpected')
def search_subtitle(wanted_item_index, lang): log.info('Searching for an individual subtitle') subs = [] # Get wanted queue lock if not get_wanted_queue_lock(): return subs, 'Skipping! Cannot get a wanted queue lock because another thread is using the queues!' # Setup provider pool provider_pool = _get_provider_pool() if provider_pool: log.info('Searching subtitles with providers: %s', ', '.join(provider_pool.providers)) # Get wanted_item wanted_item = autosubliminal.WANTEDQUEUE[int(wanted_item_index)] log.info('Searching subtitles for video: %s', wanted_item.videopath) # Scan wanted_item for video video = _scan_wanted_item_for_video(wanted_item, is_manual=True) if video: # Search the subtitles with the default minimal score (to get all the possibilities to select from) default_min_score = _get_min_match_score(video, is_manual=True) subtitles, language, single = _search_subtitles(video, lang, False, provider_pool) # Check if subtitles are found for the video if subtitles: # Add found subtitles to wanted_item wanted_item.found_subtitles = {'subtitles': subtitles, 'language': language, 'single': single} # Order subtitles by score and create new dict # Use subliminal default compute_score for index, subtitle, score in sorted( [(index, s, subliminal.compute_score(s, video, autosubliminal.PREFERHEARINGIMPAIRED)) for index, s in enumerate(subtitles)], key=operator.itemgetter(2), reverse=True): # Filter out subtitles that do not match the default score if score < default_min_score: log.debug('Skipping subtitle %s with score below %d', subtitle, default_min_score) break # Only add subtitle when content is found if subtitle.content: # Create new sub dict for showing result sub = {'subtitle_index': index, 'score': score, 'provider_name': subtitle.provider_name, 'content': subtitle.content, 'language': language, 'single': single, 'page_link': subtitle.page_link, 'releases': _get_releases(subtitle), 'wanted_item_index': wanted_item_index, 'playvideo_url': _construct_playvideo_url(wanted_item)} # Get content preview (the first 28 lines and last 30 lines of the subtitle) # Use the subtitle text (decoded content) instead of content to generate the preview content_split = subtitle.text.splitlines(False) if len(content_split) < 58: content_preview = 'This seems to be an invalid subtitle.' content_preview += '<br> It has less than 58 lines to preview.' else: try: # First 28 lines content_preview = '<br>'.join(x.replace('"', '\'') for x in content_split[:28]) # Separator content_preview += '<br>' content_preview += '<br>' content_preview += '...' content_preview += '<br>' content_preview += '<br>' # Last 30 lines content_preview += '<br>'.join( x.replace('"', '\'') for x in content_split[len(content_split) - 30:]) except Exception: content_preview = 'Problem with parsing the first 28 and/or last 30 lines of the file.' sub['content_preview'] = content_preview subs.append(sub) # Release wanted queue lock release_wanted_queue_lock() if not provider_pool: return subs, 'Skipping! No subliminal providers are configured!' if not len(subs): return subs, 'No subtitles could be found or downloaded!' return subs, None