Beispiel #1
0
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)
Beispiel #2
0
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)
Beispiel #3
0
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)
Beispiel #4
0
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.')
Beispiel #5
0
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)
Beispiel #6
0
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)
Beispiel #7
0
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))
Beispiel #8
0
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()
Beispiel #9
0
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')
Beispiel #10
0
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)
Beispiel #11
0
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']))
Beispiel #12
0
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()
Beispiel #13
0
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')
Beispiel #14
0
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)