def manually_correct_theme(name, url, type, rk, just_theme): """Set the correct fingerprint of the show in the hashes.db and process the eps of that show in the db against the new theme fingerprint. Args: name (str): name of the show url (str): the youtube/tvtunes url to the correct theme. type (str): What source to use for themes. rk (str): ratingkey of that show. Pass auto if your lazy. just_theme (bool): just add the theme song. Returns: None """ global HT HT = get_hashtable() # Assist for the lazy bastards.. if rk == 'auto': items = PMS.search(name) items = [i for i in items if i and i.TYPE == 'show'] items = choose('Select correct show', items, lambda x: '%s %s' % (x.title, x.TYPE)) if items: rk = items[0].ratingKey # I don't think think the themes in the hashdb should be removed anymore as # one show can now have several themes also it don't remove the files in THEMES, this is intended! themes = HT.get_theme(items[0]) for th in themes: LOG.debug('Removing %s from the hashtable', th) HT.remove(th) # Download the themes depending on the manual option or config file. download_theme(items[0], HT, theme_source=type, url=url) to_pp = [] if just_theme: return if rk: with session_scope() as se: # Find all episodes of this show. item = se.query(Processed).filter_by(grandparentRatingKey=rk) for i in item: to_pp.append(PMS.fetchItem(i.ratingKey)) # Prob should have used edit, but we do this so we can use process_to_db. se.delete(i) for media in to_pp: process_to_db(media)
def set_manual_theme_time(showname, season, episode, type, start, end): # pragma: no cover """Set a manual start and end time for a theme. Args: showname(str): name of the show you want to find season(int): season number fx 1 episode(int): episode number 1 type(str): theme, credit # Still TODO Stuff for credits start(int, str): This can be in seconds or MM:SS format start(int, str): This can be in seconds or MM:SS format Returns: None """ LOG.debug('Trying to set manual time') result = PMS.search(showname) if result: items = choose('Select show', result, 'title') show = items[0] ep = show.episode(season=season, episode=episode) if ep: with session_scope() as se: item = se.query(Processed).filter_by( ratingKey=ep.ratingKey).one() start = to_sec(start) end = to_sec(end) if type == 'ffmpeg': item.correct_ffmpeg = end elif type == 'theme': if start: item.correct_time_start = start if end: item.correct_time_end = end elif type == 'credits': if start: item.correct_credits_start = start if end: item.correct_credits_end = end LOG.debug('Set correct_time %s for %s to start %s end %s', type, ep._prettyfilename(), start, end)
def manually_correct_theme(name, url, type, rk, just_theme): """Set the correct fingerprint of the show in the hashes.db and process the eps of that show in the db against the new theme fingerprint. Args: name (str): name of the show url (str): the youtube url to the correct theme. rk (str): ratingkey of that show. Pass auto if your lazy. just_theme (bool): just add the theme song. Returns: None """ global HT HT = get_hashtable() # Assist for the lazy bastards.. if rk == 'auto': item = PMS.search(name) item = choose('Select correct show', item, lambda x: '%s %s' % (x.title, x.TYPE)) if item: rk = item[0].ratingKey theme_path = search_for_theme_youtube(name, rk=rk, url=url, save_path=THEMES) for fp in HT.names: if os.path.basename(fp).lower() == name.lower() and os.path.exists(fp): LOG.debug('Removing %s from the hashtable', fp) HT.remove(fp) analyzer().ingest(HT, theme_path) # HT.save(FP_HASHES) to_pp = [] if just_theme: return if rk: with session_scope() as se: item = se.query(Preprocessed).filter_by(grandparentRatingKey=rk) for i in item: to_pp.append(PMS.fetchItem(i.ratingKey)) # Prob should have edit, but we do this so we can use process_to_db. se.delete(i) for media in to_pp: process_to_db(media)
def create_edl_from_db(t, save_path): with session_scope() as se: db_items = se.query(Processed).all() for item in db_items: # Maybe remove this later? if save_path: loc = edl.create_edl_path( os.path.join(save_path, os.path.basename(item.location))) else: loc = item.location try: t = edl.write_edl(loc, edl.db_to_edl(item, edl.TYPES[t])) click.echo('Wrote %s' % t) except: LOG.exception('Failed to write edl.')
def export_db(format, save_path, write_file, show_html): """Test command for myself.""" import tablib f = Preprocessed keys = [k for k in Preprocessed.__dict__.keys() if not k.startswith('_')] data = [] with session_scope() as se: db_items = se.query(Preprocessed).all() for item in db_items: data.append(item._to_tuple(keys=keys)) td = tablib.Dataset(*data, headers=keys) if format != 'txt': t = td.export(format) else: t = td if write_file: fullpath = os.path.join(save_path, '%s.%s' % (Preprocessed.__name__, format)) with open(fullpath, 'wb') as f: f.write(t.encode('utf-8')) click.echo('Wrote file to %s' % fullpath) else: if format == 'html' and show_html: tf = tempfile.NamedTemporaryFile(suffix='.%s' % format) with tf as f: f.write(t.encode('utf-8')) webbrowser.open(tf.name) try: while True: time.sleep(10) except KeyboardInterrupt: pass else: click.echo(t)
def process_to_db(media, theme=None, vid=None, start=None, end=None, ffmpeg_end=None, recap=None): """Process a plex media item to the db Args: media (Episode obj): theme: path to the theme. vid: path to the stripped wav of the media item. start (None, int): of theme. end (None, int): of theme. ffmpeg_end (None, int): What does ffmpeg think is the start of the ep. Returns: None """ global HT ff = -1 name = media._prettyfilename() LOG.debug('Started to process %s', name) if theme is None: theme = get_theme(media) theme = convert_and_trim(theme, fs=11025, theme=True) if vid is None: vid = convert_and_trim(check_file_access(media), fs=11025, trim=600) # too cover manual process_to_db. if theme not in HT.names: analyzer().ingest(HT, theme) # Lets skip the start time for now. This need to be added later to support shows # that have show, theme song show. if end is None: start, end = get_offset_end(vid, HT) if ffmpeg_end is None: ffmpeg_end = find_offset_ffmpeg(check_file_access(media)) if recap is None: recap = has_recap(media, CONFIG.get('words'), audio=vid) if end is not None: with session_scope() as se: try: se.query(Preprocessed).filter_by(ratingKey=media.ratingKey).one() except NoResultFound: p = Preprocessed(show_name=media.grandparentTitle, ep_title=media.title, theme_end=end, theme_start=start, theme_start_str=to_time(start), theme_end_str=to_time(end), ffmpeg_end=ffmpeg_end, ffmpeg_end_str=to_time(ff), duration=media.duration, ratingKey=media.ratingKey, grandparentRatingKey=media.grandparentRatingKey, prettyname=media._prettyfilename(), updatedAt=media.updatedAt, has_recap=recap) se.add(p) LOG.debug('Added %s to media.db', name)
def check(data): global JUMP_LIST if data.get('type') == 'playing' and data.get( 'PlaySessionStateNotification'): sess = data.get('PlaySessionStateNotification')[0] if sess.get('state') != 'playing': return ratingkey = sess.get('ratingKey') sessionkey = int(sess.get('sessionKey')) progress = sess.get('viewOffset', 0) / 1000 # converted to sec. mode = CONFIG.get('mode', 'skip_only_theme') # This has to be removed if/when credits are added. if progress >= 600: return def best_time(item): """Find the best time in the db.""" if item.correct_theme_end and item.correct_theme_end != 1: sec = item.correct_theme_end elif item.correct_ffmpeg and item.correct_ffmpeg != 1: sec = item.correct_ffmpeg elif item.theme_end and item.theme_end != -1: sec = item.theme_end elif item.ffmpeg_end and item.ffmpeg_end != -1: sec = item.ffmpeg_end else: sec = -1 return sec def jump(item, sessionkey, sec=None): if sec is None: sec = best_time(item) if sessionkey not in JUMP_LIST: JUMP_LIST.append(sessionkey) POOL.apply_async(client_jump_to, args=(sec, sessionkey)) with session_scope() as se: try: item = se.query(Preprocessed).filter_by(ratingKey=ratingkey).one() if item: LOG.debug('Found %s theme start %s, theme end %s, progress %s', item.prettyname, item.theme_start_str, item.theme_end_str, to_time(progress)) bt = best_time(item) if mode == 'skip_if_recap' and item.theme_end and item.theme_start: return jump(item, sessionkey, bt) if mode == 'skip_only_theme': if item.correct_theme_end and item.correct_theme_start: if progress > item.correct_theme_start and progress < item.correct_theme_end: LOG.debug('%s is in the correct time range correct_theme_end', item.prettyname) return jump(item, sessionkey, item.correct_theme_end) elif item.theme_end and item.theme_start: if progress > item.theme_start and progress < item.theme_end: LOG.debug('%s is in the correct time range theme_end', item.prettyname) return jump(item, sessionkey, item.theme_end) #if progress > item.theme_start and progress < item.theme_end: # LOG.debug('%s is in the correct time range', item.prettyname) # return jump(item, sessionkey, item.correct_theme_end or item.theme_end) #else: # if item.theme_start - progress < 0: # n = item.theme_start - progress # if n > 0: # part = 'jumping in %s' % to_time(n) # else: # part = 'should have jumped %s ago' % to_time(n) # LOG.debug('Skipping %s as it not in the correct time range jumping in %s', # item.prettyname, part) except NoResultFound: if ratingkey not in IN_PROG: IN_PROG.append(ratingkey) LOG.debug('Failed to find %s in the db', ratingkey) POOL.apply_async(task, args=(ratingkey, sessionkey))
def process(name, sample, threads, skip_done): """Manual process some/all eps. You will asked for what you want to process Args: name (None): Pass a name of a show you want to process sample (int): process x eps for all shows. threads (int): How many thread to use skip_done(bool): Should we skip stuff that is processed. Return: None """ global HT global SHOWS all_eps = [] if name: load_themes() shows = find_all_shows() shows = [s for s in shows if s.title.lower().startswith(name.lower())] shows = choose('Select what show to process', shows, 'title') for show in shows: eps = show.episodes() eps = choose('Select episodes', eps, lambda x: '%s %s' % (x._prettyfilename(), x.title)) all_eps += eps if sample: def lol(i): x = i.episodes()[:sample] return all_eps.extend(x) find_all_shows(lol) if skip_done: # Now there must be a better way.. with session_scope() as se: items = se.query(Preprocessed).all() for item in items: for ep in all_eps: if ep.ratingKey == item.ratingKey: click.secho('Removing as %s already is processed' % item.prettyname, fg='red') all_eps.remove(ep) HT = get_hashtable() def prot(item): try: process_to_db(item) except Exception as e: logging.error(e, exc_info=True) if all_eps: p = Pool(threads) # process_to_db craps out because off a race condition in get_theme(media) # if the user is selecting n eps > 1 for the same theme. # Lets just download the the themes first so the shit is actually processed. gr = set([i.grandparentRatingKey for i in all_eps]) - SHOWS.keys() LOG.debug('Downloading theme for %s shows this might take a while..', len(gr)) if len(gr): sh = p.map(PMS.fetchItem, gr) try: p.map(search_for_theme_youtube, [(s.title, s. ratingKey, THEMES) for s in sh]) except KeyboardInterrupt: pass try: load_themes() p.map(prot, all_eps) except KeyboardInterrupt: p.terminate()
def check_db(client_name, skip_done): """Do a manual check of the db. This will start playback on a client and seek the video file where we have found theme start/end and ffmpeg_end. You will be asked if its a correct match, press y or set the correct time in mm:ss format. Args: client_name (None, str): Name of the client you want to use (watch) skip_done (bool): Skip shit that is verified before. Returns: None """ if client_name is None: client = choose('Select what client to use', PMS.clients(), 'title')[0] else: client = PMS.client(client_name).connect() with session_scope() as se: items = se.query(Preprocessed).all() click.echo('') for item in sorted(items, key=lambda k: k.ratingKey): click.echo('%s %s' % (click.style('Checking', fg='white'), click.style(item.prettyname, bold=True, fg='green'))) click.echo('theme_start %s theme_end %s ffmpeg_end %s' % (item.theme_start, item.theme_end_str, item.ffmpeg_end)) click.echo('*%s*' % ('-' * 80)) click.echo('') if item.theme_start == -1 or item.theme_end == -1: click.echo('Exists in the db but the start of the theme was not found.' ' Check the audio file and run it again.') if item.theme_end != -1: if (not skip_done and item.correct_theme_start) or not item.correct_theme_start: click.echo('Found theme_start at %s %s theme_end %s %s' % (item.theme_start, item.theme_start_str, item.theme_end, item.theme_end_str)) client.playMedia(PMS.fetchItem(item.ratingKey)) time.sleep(1) client.seekTo(item.theme_start * 1000) start_match = click.prompt('Was theme_start at %s correct?' % item.theme_start_str) if start_match: if start_match == 'y': item.correct_theme_start = item.theme_start else: item.correct_theme_start = to_sec(start_match) if (not skip_done and item.correct_theme_end) or not item.correct_theme_end: client.seekTo(item.theme_end * 1000) end_match = click.prompt('Was theme_end at %s correct?' % item.theme_end_str) if end_match: if end_match == 'y': item.correct_theme_end = item.theme_end else: item.correct_theme_end = to_sec(end_match) if item.ffmpeg_end: if (not skip_done and item.correct_ffmpeg) or not item.correct_ffmpeg: click.echo('Found ffmpeg_end at sec %s time %s' % (item.ffmpeg_end, item.ffmpeg_end_str)) if item.ffmpeg_end > 30: j = item.ffmpeg_end - 20 else: j = item.ffmpeg_end client.playMedia(PMS.fetchItem(item.ratingKey)) time.sleep(1) client.seekTo(j * 1000) match = click.prompt('Was ffmpeg_end at %s correct?' % item.ffmpeg_end_str) if match: if match.lower() in ['y', 'yes']: item.correct_ffmpeg = item.ffmpeg_end else: item.correct_ffmpeg = to_sec(match) click.clear() # Commit thit shit after each loop. if se.dirty: se.commit() click.echo('Done')
def check(data): global JUMP_LIST if data.get('type') == 'playing' and data.get( 'PlaySessionStateNotification'): sess = data.get('PlaySessionStateNotification')[0] if sess.get('state') != 'playing': return ratingkey = int(sess.get('ratingKey')) sessionkey = int(sess.get('sessionKey')) progress = sess.get('viewOffset', 0) / 1000 # converted to sec. mode = CONFIG['general'].get('mode', 'skip_only_theme') no_wait_tick = CONFIG['general'].get('no_wait_tick', 0) def best_time(item): """Find the best time in the db.""" if item.type == 'episode' and item.correct_theme_end and item.correct_theme_end != 1: sec = item.correct_theme_end elif item.correct_ffmpeg and item.correct_ffmpeg != 1: sec = item.correct_ffmpeg elif item.type == 'episode' and item.theme_end and item.theme_end != -1: sec = item.theme_end elif item.ffmpeg_end and item.ffmpeg_end != -1: sec = item.ffmpeg_end else: sec = -1 return sec def jump(item, sessionkey, sec=None, action=None): # pragma: no cover if sec is None: sec = best_time(item) if action: POOL.apply_async(client_action, args=(sec, sessionkey, action)) return if sessionkey not in JUMP_LIST: LOG.debug('Called jump with %s %s %s %s', item.prettyname, sessionkey, sec, action) JUMP_LIST.append(sessionkey) POOL.apply_async(client_action, args=(sec, sessionkey, action)) with session_scope() as se: try: item = se.query(Processed).filter_by(ratingKey=ratingkey).one() if item: bt = best_time(item) LOG.debug( 'Found %s theme start %s, theme end %s, ffmpeg_end %s progress %s ' 'best_time %s credits_start %s credits_end %s', item.prettyname, item.theme_start_str, item.theme_end_str, item.ffmpeg_end_str, to_time(progress), to_time(bt), item.credits_start_str, item.credits_end_str) if (item.type == 'episode' and CONFIG['tv'].get('check_credits') is True and CONFIG['tv'].get('check_credits_action') == 'stop' or item.type == 'movie' and CONFIG['movie'].get('check_credits') is True and CONFIG['movie'].get('check_credits_action') == 'stop'): # todo check for correct credits too if item.credits_start and item.credits_start != -1 and progress >= item.credits_start: LOG.debug('We found the start of the credits.') return jump(item, sessionkey, item.credits_start, action='stop') # Let's try to not wait for the next tick. progress = progress + no_wait_tick # If recap is detected just instantly skip to intro end. # Now this can failed is there is: recap, new episode stuff, intro, new episode stuff # So thats why skip_only_theme is default as its the safest option. if (mode == 'skip_if_recap' and item.type == 'episode' and item.has_recap is True and bt != -1): return jump(item, sessionkey, bt) # This mode will allow playback until the theme starts so it should be faster then skip_if_recap. if mode == 'skip_only_theme': # For manual corrected themes.. if item.type == 'episode' and item.correct_theme_end and item.correct_theme_start: if progress > item.correct_theme_start and progress < item.correct_theme_end: LOG.debug( '%s is in the correct time range correct_theme_end', item.prettyname) return jump(item, sessionkey, item.correct_theme_end) elif item.type == 'episode' and item.theme_end and item.theme_start: if progress > item.theme_start and progress < item.theme_end: LOG.debug( '%s is in the correct time range theme_end', item.prettyname) return jump(item, sessionkey, item.theme_end) except NoResultFound: if ratingkey not in IN_PROG: IN_PROG.append(ratingkey) LOG.debug('Failed to find ratingkey %s in the db', ratingkey) ret = POOL.apply_async(task, args=(ratingkey, sessionkey)) return ret elif data.get('type') == 'timeline': timeline = data.get('TimelineEntry')[0] state = timeline.get('state') ratingkey = timeline.get('itemID') title = timeline.get('title') metadata_type = timeline.get('type') identifier = timeline.get('identifier') metadata_state = timeline.get('metadataState') if (metadata_type in (1, 4) and state == 0 and metadata_state == 'created' and identifier == 'com.plexapp.plugins.library'): LOG.debug('%s was added to %s', title, PMS.friendlyName) # Youtubedl can fail if we batch add loads of eps at the same time if there is no # theme. if (metadata_type == 1 and not CONFIG['movie'].get('process_recently_added') or metadata_state == 4 and not CONFIG['tv'].get('process_recently_added')): LOG.debug( "Didnt start to process %s is process_recently_added is disabled" ) return if ratingkey not in IN_PROG: IN_PROG.append(ratingkey) ep = PMS.fetchItem(int(ratingkey)) ret = POOL.apply_async(process_to_db, args=(ep, )) return ret elif (metadata_type in (1, 4) and state == 9 and metadata_state == 'deleted'): if (metadata_type == 1 and not CONFIG['movie'].get('process_deleted') or metadata_state == 4 and not CONFIG['tv'].get('process_deleted')): LOG.debug( "Didnt start to process %s is process_deleted is disabled for" ) return with session_scope() as se: try: item = se.query(Processed).filter_by( ratingKey=ratingkey).one() item.delete() LOG.debug('%s was deleted from %s and from media.db', title, PMS.friendlyName) except NoResultFound: LOG.debug('%s was deleted from %s', title, PMS.friendlyName)
def process_to_db(media, theme=None, vid=None, start=None, end=None, ffmpeg_end=None, recap=None, credits_start=None, credits_end=None): """Process a plex media item to the db Args: media (Episode obj): theme: path to the theme. vid: path to the stripped wav of the media item. start (None, int): of theme. end (None, int): of theme. ffmpeg_end (None, int): What does ffmpeg think is the start of the ep. recap(None, bool): If this how has a recap or not credits_start(None, int): The offset (in sec) the credits text starts credits_end(None, int): The offset (in sec) the credits text ends Returns: None """ global HT # Disable for now. # if media.TYPE == 'movie': # return # This will download the theme and add it to # the hashtable if its missing if media.TYPE == 'episode' and theme is None: if HT.has_theme(media, add_if_missing=False) is False: LOG.debug('downloading theme from process_to_db') theme = download_theme(media, HT) name = media._prettyfilename() LOG.debug('Started to process %s', name) if vid is None and media.TYPE == 'episode': vid = convert_and_trim(check_file_access(media), fs=11025, trim=CONFIG['tv'].get('check_for_theme_sec', 600)) # Find the start and the end of the theme in the episode file. if end is None and media.TYPE == 'episode': start, end = get_offset_end(vid, HT) # Guess when the intro ended using blackframes and audio silence. if ffmpeg_end is None: if media.TYPE == 'episode': trim = CONFIG['tv'].get('check_intro_ffmpeg_sec') else: trim = CONFIG['movie'].get('check_intro_ffmpeg_sec') ffmpeg_end = find_offset_ffmpeg(check_file_access(media), trim=trim) # Check for recap. if recap is None: recap = has_recap(media, CONFIG['tv'].get('words', []), audio=vid) if (media.TYPE == 'episode' and CONFIG['tv'].get('check_credits') is True and credits_start is None and credits_end is None): dur = media.duration / 1000 - CONFIG['tv'].get('check_credits_sec', 120) credits_start, credits_end = find_credits(check_file_access(media), offset=dur, check=-1) elif (media.TYPE == 'movie' and CONFIG['movie'].get('check_credits') is True and credits_start is None and credits_end is None): dur = media.duration / 1000 - CONFIG['movie'].get( 'check_credits_sec', 600) credits_start, credits_end = find_credits(check_file_access(media), offset=dur, check=-1) else: # We dont want to find the credits. credits_start = -1 credits_end = -1 # We assume this is kinda right, # double check this # TODO location = list(i.file for i in media.iterParts() if i)[0] with session_scope() as se: try: se.query(Processed).filter_by(ratingKey=media.ratingKey).one() except NoResultFound: if media.TYPE == 'episode': p = Processed(show_name=media.grandparentTitle, title=media.title, type=media.TYPE, theme_end=end, theme_start=start, theme_start_str=to_time(start), theme_end_str=to_time(end), ffmpeg_end=ffmpeg_end, ffmpeg_end_str=to_time(ffmpeg_end), credits_start=credits_start, credits_start_str=to_time(credits_start), credits_end=credits_end, credits_end_str=to_time(credits_end), duration=media.duration, ratingKey=media.ratingKey, grandparentRatingKey=media.grandparentRatingKey, prettyname=media._prettyfilename(), updatedAt=media.updatedAt, has_recap=recap, location=location) elif media.TYPE == 'movie': p = Processed(title=media.title, type=media.TYPE, ffmpeg_end=ffmpeg_end, ffmpeg_end_str=to_time(ffmpeg_end), credits_start=credits_start, credits_start_str=to_time(credits_start), credits_end=credits_end, credits_end_str=to_time(credits_end), duration=media.duration, ratingKey=media.ratingKey, prettyname=media._prettyfilename(), updatedAt=media.updatedAt, location=location) se.add(p) LOG.debug('Added %s to media.db', name) if media.TYPE == 'movie' and CONFIG['movie']['create_edl']: edl.write_edl( location, edl.db_to_edl(p, type=CONFIG['movie']['edl_action_type'])) elif media.TYPE == 'episode' and CONFIG['tv']['create_edl']: edl.write_edl( location, edl.db_to_edl(p, type=CONFIG['tv']['edl_action_type']))
def process(name, sample, threads, skip_done): """Manual process some/all eps. You will asked for what you want to process Args: name (None): Pass a name of a show you want to process sample (int): process x eps for all shows. threads (int): How many thread to use skip_done(bool): Should we skip stuff that is processed. Return: None """ global HT all_items = [] if name: medias = find_all_movies_shows() medias = [ s for s in medias if s.title.lower().startswith(name.lower()) ] medias = choose('Select what item to process', medias, 'title') for media in medias: if media.TYPE == 'show': eps = media.episodes() eps = choose( 'Select episodes', eps, lambda x: '%s %s' % (x._prettyfilename(), x.title)) all_items += eps else: all_items.append(media) if sample: def lol(i): if i.TYPE == 'show': x = i.episodes()[:sample] return all_items.extend(x) else: return all_items.append(i) find_all_movies_shows(lol) if skip_done: # Now there must be a better way.. with session_scope() as se: items = se.query(Processed).all() for item in items: for ep in all_items: if ep.ratingKey == item.ratingKey: click.secho( "Removing %s at it's already is processed" % item.prettyname, fg='red') all_items.remove(ep) HT = get_hashtable() def prot(item): try: process_to_db(item) except Exception as e: logging.error(e, exc_info=True) if all_items: p = Pool(threads) # Download all the themes first, skip the ones that we already have.. gr = set([ i.grandparentRatingKey for i in all_items if i.TYPE == 'episode' ]) - set(HT.get_themes().keys()) LOG.debug('Downloading theme for %s shows this might take a while..', len(gr)) if len(gr): sh = p.map(PMS.fetchItem, gr) try: p.map(HT.has_theme, sh) except KeyboardInterrupt: pass try: p.map(prot, all_items) except KeyboardInterrupt: p.terminate()
def check_db(client_name, skip_done): # pragma: no cover """Do a manual check of the db. This will start playback on a client and seek the video file where we have found theme start/end and ffmpeg_end. You will be asked if its a correct match, press y or set the correct time in mm:ss format. Args: client_name (None, str): Name of the client you want to use (watch) skip_done (bool): Skip episodes that already exist in the db. Returns: None """ if client_name is None: client = choose('Select what client to use', PMS.clients(), 'title') if len(client): client = client[0] else: click.echo('No client to check with.. Aborting') return else: client = PMS.client(client_name).connect() client.proxyThroughServer() with session_scope() as se: items = se.query(Processed).all() click.echo('') for item in sorted(items, key=lambda k: k.ratingKey): click.echo('%s %s' % (click.style('Checking', fg='white'), click.style(item.prettyname, bold=True, fg='green'))) click.echo('theme_start %s theme_end %s ffmpeg_end %s' % (item.theme_start, item.theme_end_str, item.ffmpeg_end)) click.echo('*%s*' % ('-' * 80)) click.echo('') media = PMS.fetchItem(item.ratingKey) if item.theme_start == -1 or item.theme_end == -1: click.echo( 'Exists in the db but the start of the theme was not found.' ' Check the audio file and run it again. Use cmd manually_correct_theme' ) if item.theme_end != -1: if (not skip_done and item.correct_theme_start ) or not item.correct_theme_start: click.echo('Found theme_start at %s %s theme_end %s %s' % (item.theme_start, item.theme_start_str, item.theme_end, item.theme_end_str)) client.playMedia(media, offset=item.theme_start * 1000) time.sleep(1) start_match = click.prompt( 'Was theme_start at %s correct? [y or MM:SS]' % item.theme_start_str) if start_match: if start_match in ['y', 'yes']: item.correct_theme_start = item.theme_start else: item.correct_theme_start = to_sec(start_match) if (not skip_done and item.correct_theme_end) or not item.correct_theme_end: client.playMedia(media, offset=item.theme_end * 1000) end_match = click.prompt( 'Was theme_end at %s correct? [y or MM:SS]' % item.theme_end_str) if end_match: if end_match in ['y', 'yes']: item.correct_theme_end = item.theme_end else: item.correct_theme_end = to_sec(end_match) if item.ffmpeg_end: if (not skip_done and item.correct_ffmpeg) or not item.correct_ffmpeg: click.echo('Found ffmpeg_end at sec %s time %s' % (item.ffmpeg_end, item.ffmpeg_end_str)) if item.ffmpeg_end > 30: j = item.ffmpeg_end - 20 else: j = item.ffmpeg_end client.playMedia(media, offset=j * 1000) time.sleep(1) match = click.prompt( 'Was ffmpeg_end at %s correct? [y or MM:SS]' % item.ffmpeg_end_str) if match: if match.lower() in ['y', 'yes']: item.correct_ffmpeg = item.ffmpeg_end else: item.correct_ffmpeg = to_sec(match) # This needs to be tested manually. if item.credits_start and item.credits_start != 1: if (not skip_done and item.correct_credits_start ) or not item.correct_credits_start: click.echo('Found credits start as sec %s time %s' % (item.credits_start, item.credits_start_str)) client.playMedia(media, offset=item.credits_start - 10) time.sleep(1) match = click.prompt( 'Did the credits start at %s correct? [y or MM:SS]' % item.credits_start_str) if match: if match.lower() in ['y', 'yes']: item.correct_credits_start = item.credits_start else: item.correct_credits_start = to_sec(match) click.clear() # Commit this shit after each loop. if se.dirty: se.commit() click.echo('Done')
def process_to_db(media, theme=None, vid=None, start=None, end=None, ffmpeg_end=None, recap=None): """Process a plex media item to the db Args: media (Episode obj): theme: path to the theme. vid: path to the stripped wav of the media item. start (None, int): of theme. end (None, int): of theme. ffmpeg_end (None, int): What does ffmpeg think is the start of the ep. Returns: None """ global HT # This will download the theme and add it to # the hashtable if its missing if theme is None: if HT.has_theme(media, add_if_missing=False) is False: LOG.debug('downloading theme from process_to_db') theme = download_theme(media, HT) ff = -1 name = media._prettyfilename() LOG.debug('Started to process %s', name) if vid is None: vid = convert_and_trim(check_file_access(media), fs=11025, trim=600) # Find the start and the end of the theme in the video file. if end is None: start, end = get_offset_end(vid, HT) # Guess when the intro ended using blackframes and audio silence. if ffmpeg_end is None: ffmpeg_end = find_offset_ffmpeg(check_file_access(media)) # Check for recap. if recap is None: recap = has_recap(media, CONFIG.get('words', []), audio=vid) with session_scope() as se: try: se.query(Preprocessed).filter_by(ratingKey=media.ratingKey).one() except NoResultFound: p = Preprocessed(show_name=media.grandparentTitle, ep_title=media.title, theme_end=end, theme_start=start, theme_start_str=to_time(start), theme_end_str=to_time(end), ffmpeg_end=ffmpeg_end, ffmpeg_end_str=to_time(ffmpeg_end), duration=media.duration, ratingKey=media.ratingKey, grandparentRatingKey=media.grandparentRatingKey, prettyname=media._prettyfilename(), updatedAt=media.updatedAt, has_recap=recap) se.add(p) LOG.debug('Added %s to media.db', name)