def pending_list_approve(options, approve=None):
    with Session() as session:
        try:
            entry_list = get_list_by_exact_name(options.list_name)
        except NoResultFound:
            console('Could not find pending list with name `{}`'.format(options.list_name))
            return
        try:
            db_entry = get_entry_by_id(entry_list.id, int(options.entry), session=session)
        except NoResultFound:
            console('Could not find matching entry with ID {} in list `{}`'.format(int(options.entry),
                                                                                   options.list_name))
            return
        except ValueError:
            db_entry = get_entry_by_title(entry_list.id, options.entry, session=session)
            if not db_entry:
                console('Could not find matching entry with title `{}` in list `{}`'.format(options.entry,
                                                                                            options.list_name))
                return
        approve_text = 'approved' if approve else 'rejected'
        if (db_entry.approved is True and approve is True) or (db_entry.approved is False and approve is False):
            console('entry {} is already {}'.format(db_entry.title, approve_text))
            return
        db_entry.approved = approve
        console('Successfully marked pending entry {} as {}'.format(db_entry.title, approve_text))
Exemple #2
0
def list_entries(options):
    """List pending entries"""
    approved = options.approved
    task_name = options.task_name

    with Session() as session:
        entries = db.list_pending_entries(session=session, task_name=task_name, approved=approved)
        header = ['#', 'Task Name', 'Title', 'URL', 'Approved', 'Added']
        table_data = [header]
        for entry in entries:
            table_data.append(
                [
                    entry.id,
                    entry.task_name,
                    entry.title,
                    entry.url,
                    colorize('green', 'Yes') if entry.approved else 'No',
                    entry.added.strftime("%c"),
                ]
            )
    try:
        table = TerminalTable(
            options.table_type, table_data, wrap_columns=[1, 2, 3], drop_columns=[5, 1, 3]
        )
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #3
0
def entry_list_add(options):
    with Session() as session:
        try:
            entry_list = get_list_by_exact_name(options.list_name, session=session)
        except NoResultFound:
            console('Could not find entry list with name `{}`, creating'.format(options.list_name))
            entry_list = EntryListList(name=options.list_name)
            session.add(entry_list)
        session.merge(entry_list)
        session.commit()
        title = options.entry_title
        entry = {'title': options.entry_title, 'url': options.url}
        db_entry = get_entry_by_title(list_id=entry_list.id, title=title, session=session)
        if db_entry:
            console("Entry with the title `{}` already exist with list `{}`. Will replace identifiers if given".format(
                title, entry_list.name))
            output = 'Successfully updated entry `{}` to entry list `{}` '.format(title, entry_list.name)
        else:
            console("Adding entry with title `{}` to list `{}`".format(title, entry_list.name))
            db_entry = EntryListEntry(entry=entry, entry_list_id=entry_list.id)
            session.add(db_entry)
            output = 'Successfully added entry `{}` to entry list `{}` '.format(title, entry_list.name)
        if options.attributes:
            console('Adding attributes to entry `{}`'.format(title))
            for identifier in options.attributes:
                for k, v in identifier.items():
                    entry[k] = v
            db_entry.entry = entry
        console(output)
Exemple #4
0
def remove(manager, options, forget=False):
    name = options.series_name
    if options.episode_id:
        # remove by id
        identifier = options.episode_id
        try:
            remove_series_episode(name, identifier, forget)
            console('Removed episode `%s` from series `%s`.' % (identifier, name.capitalize()))
        except ValueError:
            # Try upper casing identifier if we fail at first
            try:
                remove_series_episode(name, identifier.upper(), forget)
                console('Removed episode `%s` from series `%s`.' % (identifier, name.capitalize()))
            except ValueError as e:
                console(e.args[0])

    else:
        # remove whole series
        try:
            remove_series(name, forget)
            console('Removed series `%s` from database.' % name.capitalize())
        except ValueError as e:
            console(e.args[0])

    manager.config_changed()
Exemple #5
0
    def bootstrap(self, session, config):
        """bootstrap the plugin configuration and update db with cached chat_ids"""
        console('{0} - bootstrapping...'.format(_PLUGIN_NAME))
        chat_ids = self._real_init(session, config)

        found_usernames = [x.username for x in chat_ids if x.username]
        found_fullnames = [(x.firstname, x.surname) for x in chat_ids if x.firstname]
        found_grps = [x.group for x in chat_ids if x.group]

        missing_usernames = [x for x in self._usernames if x not in found_usernames]
        missing_fullnames = [x for x in self._fullnames if x not in found_fullnames]
        missing_grps = [x for x in self._groups if x not in found_grps]

        if missing_usernames or missing_fullnames or missing_grps:
            for i in missing_usernames:
                console('ERR: could not find chat_id for username: {0}'.format(i))
            for i in missing_fullnames:
                console('ERR: could not find chat_id for fullname: {0} {1}'.format(*i))
            for i in missing_grps:
                console('ERR: could not find chat_id for group: {0}'.format(i))
            res = False
        else:
            console('{0} - bootstrap was successful'.format(_PLUGIN_NAME))
            res = True

        return res
Exemple #6
0
def action_list(options):
    with Session() as session:
        if not options.account:
            # Print all accounts
            accounts = session.query(TraktUserAuth).all()
            if not accounts:
                console('No trakt authorizations stored in database.')
                return
            header = ['Account', 'Created', 'Expires']
            table_data = [header]

            for auth in accounts:
                table_data.append([auth.account, auth.created.strftime('%Y-%m-%d'), auth.expires.strftime('%Y-%m-%d')])
            try:
                table = TerminalTable(options.table_type, table_data)
                console(table.output)
                return
            except TerminalTableError as e:
                console('ERROR: %s' % str(e))

        # Show a specific account
        acc = session.query(TraktUserAuth).filter(TraktUserAuth.account == options.account).first()
        if acc:
            console('Authorization expires on %s' % acc.expires)
        else:
            console('Flexget has not been authorized to access your account.')
def pending_list_show(options):
    with Session() as session:
        try:
            pending_list = get_list_by_exact_name(options.list_name, session=session)
        except NoResultFound:
            console('Could not find pending list with name {}'.format(options.list_name))
            return

        try:
            entry = get_entry_by_id(pending_list.id, int(options.entry), session=session)
        except NoResultFound:
            console('Could not find matching pending entry with ID {} in list `{}`'.format(int(options.entry),
                                                                                           options.list_name))
            return
        except ValueError:
            entry = get_entry_by_title(pending_list.id, options.entry, session=session)
            if not entry:
                console('Could not find matching pending entry with title `{}` in list `{}`'.format(options.entry,
                                                                                                    options.list_name))
                return
        header = ['Field name', 'Value']
        table_data = [header]
        for k, v in sorted(entry.entry.items()):
            table_data.append([k, str(v)])
    table = TerminalTable(options.table_type, table_data, wrap_columns=[1])
    table.table.justify_columns[0] = 'center'
    try:
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #8
0
def seen_search(options, session=None):
    search_term = options.search_term
    if is_imdb_url(search_term):
        console('IMDB url detected, parsing ID')
        imdb_id = extract_id(search_term)
        if imdb_id:
            search_term = imdb_id
        else:
            console("Could not parse IMDB ID")
    else:
        search_term = '%' + options.search_term + '%'
    seen_entries = db.search(value=search_term, status=None, session=session)
    table_data = []
    for se in seen_entries.all():
        table_data.append(['Title', se.title])
        for sf in se.fields:
            if sf.field.lower() == 'title':
                continue
            table_data.append(['{}'.format(sf.field.upper()), str(sf.value)])
        table_data.append(['Task', se.task])
        table_data.append(['Added', se.added.strftime('%Y-%m-%d %H:%M')])
        if options.table_type != 'porcelain':
            table_data.append(['', ''])
    if not table_data:
        console('No results found for search')
        return
    if options.table_type != 'porcelain':
        del table_data[-1]

    try:
        table = TerminalTable(options.table_type, table_data, wrap_columns=[1])
        table.table.inner_heading_row_border = False
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #9
0
def reset_plugin(options):
    plugin = options.plugin_name[0]
    try:
        reset_schema(plugin)
        console("The database for `%s` has been reset." % plugin)
    except ValueError as e:
        console("Unable to reset %s: %s" % (plugin, e.message))
def clear_rejected(manager):
    with Session() as session:
        results = session.query(RememberEntry).delete()
        console('Cleared %i items.' % results)
        session.commit()
        if results:
            manager.config_changed()
Exemple #11
0
def do_cli(manager, options):
    with Session() as session:
        query = session.query(History)
        if options.search:
            search_term = options.search.replace(' ', '%').replace('.', '%')
            query = query.filter(History.title.like('%' + search_term + '%'))
        if options.task:
            query = query.filter(History.task.like('%' + options.task + '%'))
        query = query.order_by(desc(History.time)).limit(options.limit)
        table_data = []
        if options.short:
            table_data.append(['Time', 'Title'])
        for item in reversed(query.all()):
            if not options.short:
                table_data.append(['Task', item.task])
                table_data.append(['Title', item.title])
                table_data.append(['URL', item.url])
                table_data.append(['Time', item.time.strftime("%c")])
                table_data.append(['Details', item.details])
                if item.filename:
                    table_data.append(['Stored', item.filename])
                if options.table_type != 'porcelain':
                    table_data.append([''])
            else:
                table_data.append([item.time.strftime("%c"), item.title])
    title = 'Showing {} entries from History'.format(query.count())
    if options.table_type != 'porcelain':
        del table_data[-1]
    table = TerminalTable(options.table_type, table_data, title=title, wrap_columns=[1])
    if not options.short:
        table.table.inner_heading_row_border = False
    try:
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #12
0
def do_cli(manager, options):
    if not options.url:
        # Determine if first positional argument is a URL or a title
        if '://' in options.title:
            options.url = options.title
            options.title = None

    if options.url and not options.title:
        # Attempt to get a title from the URL response's headers
        try:
            value, params = cgi.parse_header(requests.head(options.url).headers['Content-Disposition'])
            options.title = params['filename']
        except KeyError:
            console('No title given, and couldn\'t get one from the URL\'s HTTP response. Aborting.')
            return

    entry = Entry(title=options.title)
    if options.url:
        entry['url'] = options.url
    else:
        entry['url'] = 'http://localhost/inject/%s' % ''.join(random.sample(string.ascii_letters + string.digits, 30))
    if options.force:
        entry['immortal'] = True
    if options.accept:
        entry.accept(reason='accepted by CLI inject')
    if options.fields:
        for key, value in options.fields:
            entry[key] = value
    options.inject = [entry]
    manager.execute_command(options)
Exemple #13
0
def get_access_token(account, token=None, refresh=False, re_auth=False, called_from_cli=False):
    """
    Gets authorization info from a pin or refresh token.
    :param account: Arbitrary account name to attach authorization to.
    :param unicode token: The pin or refresh token, as supplied by the trakt website.
    :param bool refresh: If True, refresh the access token using refresh_token from db.
    :param bool re_auth: If True, account is re-authorized even if it already exists in db.
    :raises RequestException: If there is a network error while authorizing.
    """
    data = {
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',
    }
    with Session() as session:
        acc = session.query(TraktUserAuth).filter(TraktUserAuth.account == account).first()
        if acc and datetime.now() < acc.expires and not refresh and not re_auth:
            return acc.access_token
        else:
            if (
                acc
                and (refresh or datetime.now() >= acc.expires - timedelta(days=5))
                and not re_auth
            ):
                log.debug('Using refresh token to re-authorize account %s.', account)
                data['refresh_token'] = acc.refresh_token
                data['grant_type'] = 'refresh_token'
                token_dict = token_oauth(data)
            elif token:
                # We are only in here if a pin was specified, so it's safe to use console instead of logging
                console(
                    'Warning: PIN authorization has been deprecated. Use Device Authorization instead.'
                )
                data['code'] = token
                data['grant_type'] = 'authorization_code'
                token_dict = token_oauth(data)
            elif called_from_cli:
                log.debug(
                    'No pin specified for an unknown account %s. Attempting to authorize device.',
                    account,
                )
                token_dict = device_auth()
            else:
                raise plugin.PluginError(
                    'Account %s has not been authorized. See `flexget trakt auth -h` on how to.'
                    % account
                )
            try:
                new_acc = TraktUserAuth(
                    account,
                    token_dict['access_token'],
                    token_dict['refresh_token'],
                    token_dict.get('created_at', time.time()),
                    token_dict['expires_in'],
                )
                session.merge(new_acc)
                return new_acc.access_token
            except requests.RequestException as e:
                raise plugin.PluginError('Token exchange with trakt failed: {0}'.format(e))
Exemple #14
0
def action_purge(options):
    with Session() as session:
        regexp_list = db.get_list_by_exact_name(options.list_name)
        if not regexp_list:
            console('Could not find regexp list with name {}'.format(options.list_name))
            return
        console('Deleting list %s' % options.list_name)
        session.delete(regexp_list)
Exemple #15
0
def clear_failed(manager):
    # TODO: this should be a function in db.py
    with Session() as session:
        results = session.query(db.FailedEntry).delete()
        console('Cleared %i items.' % results)
        session.commit()
        if results:
            manager.config_changed()
Exemple #16
0
def clear_entries(options):
    """Clear pending entries"""
    with Session() as session:
        query = session.query(PendingEntry).filter(PendingEntry.approved == False)
        if options.task_name:
            query = query.filter(PendingEntry.task_name == options.task_name)
        deleted = query.delete()
        console('Successfully deleted %i pending entries' % deleted)
Exemple #17
0
def seen_add(options):
    seen_name = options.add_value
    if is_imdb_url(seen_name):
        imdb_id = extract_id(seen_name)
        if imdb_id:
            seen_name = imdb_id
    seen.add(seen_name, "cli_add", {"cli_add": seen_name})
    console("Added %s as seen. This will affect all tasks." % seen_name)
Exemple #18
0
def vacuum():
    console("Running VACUUM on sqlite database, this could take a while.")
    session = Session()
    try:
        session.execute("VACUUM")
        session.commit()
    finally:
        session.close()
    console("VACUUM complete.")
def pending_list_purge(options):
    with Session() as session:
        try:
            entry_list = get_list_by_exact_name(options.list_name)
        except NoResultFound:
            console('Could not find entry list with name `{}`'.format(options.list_name))
            return
        console('Deleting list {}'.format(options.list_name))
        session.delete(entry_list)
Exemple #20
0
def movie_list_purge(options):
    with Session() as session:
        try:
            movie_list = db.get_list_by_exact_name(options.list_name)
        except NoResultFound:
            console('Could not find movie list with name {}'.format(options.list_name))
            return
        console('Deleting list {}'.format(options.list_name))
        session.delete(movie_list)
Exemple #21
0
    def test_msg(self, session, config):
        """send test message to configured recipients"""
        console('{0} loading chat_ids...'.format(_PLUGIN_NAME))
        chat_ids = self._real_init(session, config)

        console('{0} sending test message(s)...'.format(_PLUGIN_NAME))
        for chat_id in (x.id for x in chat_ids):
            self._bot.sendMessage(chat_id=chat_id, text='test message from flexget')

        return True
Exemple #22
0
def clear_failed(manager):
    session = Session()
    try:
        results = session.query(FailedEntry).delete()
        console('Cleared %i items.' % results)
        session.commit()
        if results:
            manager.config_changed()
    finally:
        session.close()
Exemple #23
0
def seen_forget(manager, options):
    forget_name = options.forget_value
    if is_imdb_url(forget_name):
        imdb_id = extract_id(forget_name)
        if imdb_id:
            forget_name = imdb_id

    count, fcount = seen.forget(forget_name)
    console("Removed %s titles (%s fields)" % (count, fcount))
    manager.config_changed()
Exemple #24
0
def cli_perf_test(manager, options):
    if options.test_name not in TESTS:
        console("Unknown performance test %s" % options.test_name)
        return
    session = Session()
    try:
        if options.test_name == "imdb_query":
            imdb_query(session)
    finally:
        session.close()
Exemple #25
0
def print_doc(manager, options):
    plugin_name = options.doc
    plugin = plugins.get(plugin_name, None)
    if plugin:
        if not plugin.instance.__doc__:
            console('Plugin %s does not have documentation' % plugin_name)
        else:
            console('')
            console(trim(plugin.instance.__doc__))
            console('')
    else:
        console('Could not find plugin %s' % plugin_name)
Exemple #26
0
def movie_list_lists(options):
    """ Show all movie lists """
    lists = get_movie_lists()
    header = ["#", "List Name"]
    table_data = [header]
    for movie_list in lists:
        table_data.append([movie_list.id, movie_list.name])
    table = TerminalTable(options.table_type, table_data)
    try:
        console(table.output)
    except TerminalTableError as e:
        console("ERROR: %s" % str(e))
Exemple #27
0
def action_all(options):
    """ Show all regexp lists """
    lists = db.get_regexp_lists()
    header = ['#', 'List Name']
    table_data = [header]
    for regexp_list in lists:
        table_data.append([regexp_list.id, regexp_list.name])
    table = TerminalTable(options.table_type, table_data)
    try:
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
def pending_list_lists(options):
    """ Show all pending lists """
    with Session() as session:
        lists = get_pending_lists(session=session)
        header = ['#', 'List Name']
        table_data = [header]
        for entry_list in lists:
            table_data.append([entry_list.id, entry_list.name])
    table = TerminalTable(options.table_type, table_data)
    try:
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
def list_rejected(options):
    with Session() as session:
        results = session.query(RememberEntry).all()
        header = ['#', 'Title', 'Task', 'Rejected by', 'Reason']
        table_data = [header]
        for entry in results:
            table_data.append([entry.id, entry.title, entry.task.name, entry.rejected_by, entry.reason or ''])
    try:
        table = TerminalTable(options.table_type, table_data)
        table.table.justify_columns[0] = 'center'
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #30
0
def movie_list_lists(options):
    """ Show all movie lists """
    lists = db.get_movie_lists()
    header = ['#', 'List Name']
    table_data = [header]
    for movie_list in lists:
        table_data.append([movie_list.id, movie_list.name])
    try:
        table = TerminalTable(options.table_type, table_data)
    except TerminalTableError as e:
        console('ERROR: {}'.format(e))
    else:
        console(table.output)
Exemple #31
0
def plugins_summary(manager, options):
    if options.table_type == 'porcelain':
        disable_all_colors()
    header = ['Keyword', 'Interfaces', 'Phases', 'Flags']
    table_data = [header]
    for plugin in sorted(
            get_plugins(phase=options.phase, interface=options.interface)):
        if options.builtins and not plugin.builtin:
            continue

        flags = []
        if plugin.instance.__doc__:
            flags.append('doc')
        if plugin.builtin:
            flags.append('builtin')
        if plugin.debug:
            if not options.debug:
                continue
            flags.append('developers')

        handlers = plugin.phase_handlers
        roles = []
        for phase in handlers:
            priority = handlers[phase].priority
            roles.append('{0}({1})'.format(phase, priority))

        name = colorize('green',
                        plugin.name) if 'builtin' in flags else plugin.name
        table_data.append([
            name, ', '.join(plugin.interfaces), ', '.join(roles),
            ', '.join(flags)
        ])

    try:
        table = TerminalTable(options.table_type,
                              table_data,
                              wrap_columns=[1, 2])
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
        return
    console(colorize('green', ' Built-in plugins'))
Exemple #32
0
def print_categories(parent_category_name=None):
    """
    Print category and its sub-categories
    :param parent_category_name: if None, all categories will be displayed
    :return:
    """
    proxy = T411Proxy()
    proxy.set_credential()
    with Session() as session:
        if parent_category_name is None:
            categories = proxy.main_categories(session=session)
        else:
            categories = proxy.find_categories(parent_category_name, session=session)
        formatting_main = '%-30s %-5s %-5s'
        formatting_sub = '     %-25s %-5s %-5s'
        console(formatting_main % ('Category name', 'PID', 'ID'))
        for category in categories:
            console(formatting_main % (category.name, category.parent_id, category.id))
            for sub_category in category.sub_categories:
                console(formatting_sub % (sub_category.name, sub_category.parent_id, sub_category.id))
Exemple #33
0
def do_cli(manager, options):
    with Session() as session:
        query = session.query(History)
        if options.search:
            search_term = options.search.replace(' ', '%').replace('.', '%')
            query = query.filter(History.title.like('%' + search_term + '%'))
        if options.task:
            query = query.filter(History.task.like('%' + options.task + '%'))
        query = query.order_by(desc(History.time)).limit(options.limit)
        table_data = []
        if options.short:
            table_data.append(['Time', 'Title'])
        for item in reversed(query.all()):
            if not options.short:
                table_data.append(['Task', item.task])
                table_data.append(['Title', item.title])
                table_data.append(['URL', item.url])
                table_data.append(['Time', item.time.strftime("%c")])
                table_data.append(['Details', item.details])
                if item.filename:
                    table_data.append(['Stored', item.filename])
                if options.table_type != 'porcelain':
                    table_data.append([''])
            else:
                table_data.append([item.time.strftime("%c"), item.title])
    if not table_data:
        console('No history to display')
        return
    title = 'Showing {} entries from History'.format(query.count())
    if options.table_type != 'porcelain' and not options.short:
        del table_data[-1]
    table = TerminalTable(options.table_type,
                          table_data,
                          title=title,
                          wrap_columns=[1])
    if not options.short:
        table.table.inner_heading_row_border = False
    try:
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #34
0
def do_cli(manager, options):
    if options.action == 'clear':
        num = db.clear_entries(options.task, all=True)
        console('%s entries cleared from backlog.' % num)
    else:
        header = ['Title', 'Task', 'Expires']
        table_data = [header]
        with Session() as session:
            entries = db.get_entries(options.task, session=session)
            for entry in entries:
                table_data.append([
                    entry.title, entry.task,
                    entry.expire.strftime('%Y-%m-%d %H:%M')
                ])
        try:
            table = TerminalTable(options.table_type,
                                  table_data,
                                  wrap_columns=[0])
            console(table.output)
        except TerminalTableError as e:
            console('ERROR: %s' % str(e))
Exemple #35
0
def movie_list_del(options):
    with Session() as session:
        try:
            movie_list = get_list_by_exact_name(options.list_name)
        except NoResultFound:
            console('Could not find movie list with name {}'.format(
                options.list_name))
            return
        title, year = split_title_year(options.movie_title)
        movie_exist = get_movie_by_title_and_year(list_id=movie_list.id,
                                                  title=title,
                                                  year=year,
                                                  session=session)
        if movie_exist:
            console('Removing movie %s from list %s' %
                    (options.movie_title, options.list_name))
            session.delete(movie_exist)
        else:
            console('Could not find movie with title %s in list %s' %
                    (options.movie_title, options.list_name))
            return
Exemple #36
0
def do_cli_task(manager, options):
    header = [
        'Start', 'Duration', 'Produced', 'Accepted', 'Rejected', 'Failed',
        'Abort Reason'
    ]
    table_data = [header]
    with Session() as session:
        try:
            task = session.query(StatusTask).filter(
                StatusTask.name == options.task).one()
        except NoResultFound:
            console(
                'Task name `%s` does not exists or does not have any records' %
                options.task)
            return
        else:
            query = task.executions.order_by(desc(
                TaskExecution.start))[:options.limit]
            for ex in reversed(query):
                start = ex.start.strftime('%Y-%m-%d %H:%M')
                start = colorize('green', start) if ex.succeeded else colorize(
                    'red', start)

                if ex.end is not None and ex.start is not None:
                    delta = ex.end - ex.start
                    duration = '%1.fs' % delta.total_seconds()
                else:
                    duration = '?'

                table_data.append([
                    start, duration, ex.produced, ex.accepted, ex.rejected,
                    ex.failed,
                    ex.abort_reason if ex.abort_reason is not None else ''
                ])

    try:
        table = TerminalTable(options.table_type, table_data)
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #37
0
def entry_list_list(options):
    """List entry list"""
    with Session() as session:
        try:
            entry_list = db.get_list_by_exact_name(options.list_name,
                                                   session=session)
        except NoResultFound:
            console('Could not find entry list with name {}'.format(
                options.list_name))
            return
        header = ['#', 'Title', '# of fields']
        table_data = [header]
        for entry in db.get_entries_by_list_id(entry_list.id,
                                               order_by='added',
                                               descending=True,
                                               session=session):
            table_data.append([entry.id, entry.title, len(entry.entry)])
    try:
        table = TerminalTable(options.table_type, table_data)
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #38
0
def action_list(options):
    """List regexp list"""
    with Session() as session:
        regexp_list = get_list_by_exact_name(options.list_name)
        if not regexp_list:
            console('Could not find regexp list with name {}'.format(
                options.list_name))
            return
        header = ['Regexp']
        table_data = [header]
        regexps = get_regexps_by_list_id(regexp_list.id,
                                         order_by='added',
                                         descending=True,
                                         session=session)
        for regexp in regexps:
            regexp_row = [regexp.regexp or '']
            table_data.append(regexp_row)
        table = TerminalTable(options.table_type, table_data)
        try:
            console(table.output)
        except TerminalTableError as e:
            console('ERROR: %s' % str(e))
Exemple #39
0
def begin(manager, options):
    series_name = options.series_name
    series_name = series_name.replace(r'\!', '!')
    ep_id = options.episode_id
    normalized_name = normalize_series_name(series_name)
    with Session() as session:
        series = shows_by_exact_name(normalized_name, session)
        if not series:
            console('Series not yet in database, adding `%s`' % series_name)
            series = Series()
            series.name = series_name
            session.add(series)
        else:
            series = series[0]
        try:
            set_series_begin(series, ep_id)
        except ValueError as e:
            console(e)
        else:
            console('Episodes for `%s` will be accepted starting with `%s`' % (series.name, ep_id))
            session.commit()
        manager.config_changed()
Exemple #40
0
def movie_list_list(options):
    """List movie list"""
    with Session() as session:
        try:
            movie_list = get_list_by_exact_name(options.list_name)
        except NoResultFound:
            console('Could not find movie list with name {}'.format(options.list_name))
            return
    header = ['Movie Name', 'Movie year']
    header += MovieListBase().supported_ids
    table_data = [header]
    movies = get_movies_by_list_id(movie_list.id, order_by='added', descending=True, session=session)
    for movie in movies:
        movie_row = [movie.title, movie.year or '']
        for identifier in MovieListBase().supported_ids:
            movie_row.append(movie.identifiers.get(identifier, ''))
        table_data.append(movie_row)
    title = '{} Movies in movie list: `{}`'.format(len(movies), options.list_name)
    table = TerminalTable(options.table_type, table_data, title, drop_columns=[5, 2, 4])
    try:
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #41
0
def cli_search(options):
    search_term = ' '.join(options.keywords)
    tags = options.tags
    sources = options.sources
    query = re.sub(r'[ \(\)]+', ' ', search_term).strip()

    table_data = []
    with Session() as session:
        for archived_entry in plugin_archive.search(session,
                                                    query,
                                                    tags=tags,
                                                    sources=sources):
            days_ago = (datetime.now() - archived_entry.added).days
            source_names = ', '.join([s.name for s in archived_entry.sources])
            tag_names = ', '.join([t.name for t in archived_entry.tags])

            table_data.append(['ID', str(archived_entry.id)])
            table_data.append(['Title', archived_entry.title])
            table_data.append(['Added', str(days_ago) + ' days ago'])
            table_data.append(['URL', archived_entry.url])
            table_data.append(['Source(s)', source_names or 'N/A'])
            table_data.append(['Tag(s)', tag_names or 'N/A'])
            if archived_entry.description:
                table_data.append(
                    ['Description',
                     strip_html(archived_entry.description)])
            table_data.append([])
    if not table_data:
        console('No results found for search')
        return

    try:
        table = TerminalTable(options.table_type, table_data, wrap_columns=[1])
        table.table.inner_heading_row_border = False
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #42
0
def display_summary(options):
    """
    Display series summary.
    :param options: argparse options from the CLI
    """
    porcelain = options.table_type == 'porcelain'
    configured = options.configured or os.environ.get(ENV_LIST_CONFIGURED,
                                                      'configured')
    premieres = (True if (os.environ.get(ENV_LIST_PREMIERES) == 'yes'
                          or options.premieres) else False)
    sort_by = options.sort_by or os.environ.get(ENV_LIST_SORTBY_FIELD, 'name')
    if options.order is not None:
        descending = True if options.order == 'desc' else False
    else:
        descending = True if os.environ.get(
            ENV_LIST_SORTBY_ORDER) == 'desc' else False
    with Session() as session:
        kwargs = {
            'configured': configured,
            'premieres': premieres,
            'session': session,
            'sort_by': sort_by,
            'descending': descending,
        }
        if sort_by == 'name':
            kwargs['sort_by'] = 'show_name'
        else:
            kwargs['sort_by'] = 'last_download_date'

        query = db.get_series_summary(**kwargs)
        header = [
            'Name', 'Begin', 'Last Encountered', 'Age', 'Downloaded',
            'Identified By'
        ]
        for index, value in enumerate(header):
            if value.lower() == options.sort_by:
                header[index] = colorize(SORT_COLUMN_COLOR, value)
        table = TerminalTable(*header, table_type=options.table_type)

        for series in query:
            name_column = series.name

            behind = (0, )
            begin = series.begin.identifier if series.begin else '-'
            latest_release = '-'
            age_col = '-'
            episode_id = '-'
            latest = db.get_latest_release(series)
            identifier_type = series.identified_by
            if identifier_type == 'auto':
                identifier_type = colorize('yellow', 'auto')
            if latest:
                behind = db.new_entities_after(latest)
                latest_release = get_latest_status(latest)
                # colorize age
                age_col = latest.age
                if latest.age_timedelta is not None:
                    if latest.age_timedelta < timedelta(days=1):
                        age_col = colorize(NEW_EP_COLOR, latest.age)
                    elif latest.age_timedelta < timedelta(days=3):
                        age_col = colorize(FRESH_EP_COLOR, latest.age)
                    elif latest.age_timedelta > timedelta(days=400):
                        age_col = colorize(OLD_EP_COLOR, latest.age)
                episode_id = latest.identifier
            if not porcelain:
                if behind[0] > 0:
                    name_column += colorize(
                        BEHIND_EP_COLOR,
                        ' {} {} behind'.format(behind[0], behind[1]))

            table.add_row(name_column, begin, episode_id, age_col,
                          latest_release, identifier_type)
    console(table)
    if not porcelain:
        if not query.count():
            console('Use `flexget series list all` to view all known series.')
        else:
            console(
                'Use `flexget series show NAME` to get detailed information.')
Exemple #43
0
def display_details(options):
    """Display detailed series information, ie. series show NAME"""
    name = options.series_name
    sort_by = options.sort_by or os.environ.get(ENV_SHOW_SORTBY_FIELD, 'age')
    if options.order is not None:
        reverse = True if options.order == 'desc' else False
    else:
        reverse = True if os.environ.get(
            ENV_SHOW_SORTBY_ORDER) == 'desc' else False
    with Session() as session:
        name = flexget.components.series.utils.normalize_series_name(name)
        # Sort by length of name, so that partial matches always show shortest matching title
        matches = db.shows_by_name(name, session=session)
        if not matches:
            console(colorize(ERROR_COLOR, 'ERROR: Unknown series `%s`' % name))
            return
        # Pick the best matching series
        series = matches[0]
        table_title = series.name
        if len(matches) > 1:
            warning = (
                colorize('red', ' WARNING: ') +
                'Multiple series match to `{}`.\n '
                'Be more specific to see the results of other matches:\n\n'
                ' {}'.format(name, ', '.join(s.name for s in matches[1:])))
            if not options.table_type == 'porcelain':
                console(warning)
        header = [
            'Identifier', 'Last seen', 'Release titles', 'Quality', 'Proper'
        ]
        table_data = []
        entities = db.get_all_entities(series,
                                       session=session,
                                       sort_by=sort_by,
                                       reverse=reverse)
        for entity in entities:
            if not entity.releases:
                continue
            if entity.identifier is None:
                identifier = colorize(ERROR_COLOR, 'MISSING')
                age = ''
            else:
                identifier = entity.identifier
                age = entity.age
            entity_data = [identifier, age]
            release_titles = []
            release_qualities = []
            release_propers = []
            for release in entity.releases:
                title = release.title
                quality = release.quality.name
                if not release.downloaded:
                    title = colorize(UNDOWNLOADED_RELEASE_COLOR, title)
                    quality = quality
                else:
                    title += ' *'
                    title = colorize(DOWNLOADED_RELEASE_COLOR, title)
                    quality = quality
                release_titles.append(title)
                release_qualities.append(quality)
                release_propers.append(
                    'Yes' if release.proper_count > 0 else '')
            entity_data.append('\n'.join(release_titles))
            entity_data.append('\n'.join(release_qualities))
            entity_data.append('\n'.join(release_propers))
            table_data.append(entity_data)
        footer = ' %s \n' % (colorize(DOWNLOADED_RELEASE_COLOR,
                                      '* Downloaded'))
        if not series.identified_by:
            footer += (
                '\n Series plugin is still learning which episode numbering mode is \n'
                ' correct for this series (identified_by: auto).\n'
                ' Few duplicate downloads can happen with different numbering schemes\n'
                ' during this time.')
        else:
            footer += '\n `%s` uses `%s` mode to identify episode numbering.' % (
                series.name,
                series.identified_by,
            )
        begin_text = 'option'
        if series.begin:
            footer += ' \n Begin for `%s` is set to `%s`.' % (
                series.name, series.begin.identifier)
            begin_text = 'and `begin` options'
        footer += ' \n See `identified_by` %s for more information.' % begin_text
    table = TerminalTable(*header,
                          table_type=options.table_type,
                          title=table_title)
    for row in table_data:
        table.add_row(*row)
    console(table)
    if not options.table_type == 'porcelain':
        console(footer)
Exemple #44
0
def begin(manager, options):
    series_name = options.series_name
    series_name = series_name.replace(r'\!', '!')
    normalized_name = flexget.components.series.utils.normalize_series_name(
        series_name)
    with Session() as session:
        series = db.shows_by_exact_name(normalized_name, session)
        if options.forget:
            if not series:
                console('Series `%s` was not found in the database.' %
                        series_name)
            else:
                series = series[0]
                series.begin = None
                console('The begin episode for `%s` has been forgotten.' %
                        series.name)
                session.commit()
                manager.config_changed()
        elif options.episode_id:
            ep_id = options.episode_id
            if not series:
                console('Series not yet in database. Adding `%s`.' %
                        series_name)
                series = db.Series()
                series.name = series_name
                session.add(series)
            else:
                series = series[0]
            try:
                _, entity_type = db.set_series_begin(series, ep_id)
            except ValueError as e:
                console(e)
            else:
                if entity_type == 'season':
                    console('`%s` was identified as a season.' % ep_id)
                    ep_id += 'E01'
                console(
                    'Releases for `%s` will be accepted starting with `%s`.' %
                    (series.name, ep_id))
                session.commit()
            manager.config_changed()
Exemple #45
0
def dump(entries, debug=False, eval_lazy=False, trace=False, title_only=False):
    """
    Dump *entries* to stdout

    :param list entries: Entries to be dumped.
    :param bool debug: Print non printable fields as well.
    :param bool eval_lazy: Evaluate lazy fields.
    :param bool trace: Display trace information.
    :param bool title_only: Display only title field
    """
    def sort_key(field):
        # Sort certain fields above the rest
        if field == 'title':
            return (0, )
        if field == 'url':
            return (1, )
        if field == 'original_url':
            return (2, )
        return 3, field

    highlighter = ReprHighlighter()

    for entry in entries:
        entry_table = TerminalTable(
            'field',
            ':',
            'value',
            show_header=False,
            show_edge=False,
            pad_edge=False,
            collapse_padding=True,
            box=None,
            padding=0,
        )
        for field in sorted(entry, key=sort_key):
            if field.startswith('_') and not debug:
                continue
            if title_only and field != 'title':
                continue
            if entry.is_lazy(field) and not eval_lazy:
                renderable = (
                    '[italic]<LazyField - value will be determined when it is accessed>[/italic]'
                )
            else:
                try:
                    value = entry[field]
                except KeyError:
                    renderable = '[italic]<LazyField - lazy lookup failed>[/italic]'
                else:
                    if field.rsplit('_', maxsplit=1)[-1] == 'url':
                        renderable = f'[link={value}][repr.url]{value}[/repr.url][/link]'
                    elif isinstance(value, str):
                        renderable = value.replace('\r', '').replace('\n', '')
                    elif is_expandable(value):
                        renderable = Pretty(value)
                    else:
                        try:
                            renderable = highlighter(str(value))
                        except Exception:
                            renderable = f'[[i]not printable[/i]] ({repr(value)})'
            entry_table.add_row(f'{field}', ': ', renderable)
        console(entry_table)
        if trace:
            console('── Processing trace:', style='italic')
            trace_table = TerminalTable(
                'Plugin',
                'Operation',
                'Message',
                show_edge=False,
                pad_edge=False,
            )
            for item in entry.traces:
                trace_table.add_row(item[0],
                                    '' if item[1] is None else item[1],
                                    item[2])
            console(trace_table)
        if not title_only:
            console('')
Exemple #46
0
def movie_list_add(options):
    with Session() as session:
        try:
            movie_list = db.get_list_by_exact_name(options.list_name,
                                                   session=session)
        except NoResultFound:
            console('Could not find movie list with name {}, creating'.format(
                options.list_name))
            movie_list = db.MovieListList(name=options.list_name)
            session.add(movie_list)
            session.commit()

        title, year = split_title_year(options.movie_title)
        console('Trying to lookup movie title: `{}`'.format(title))
        movie_lookup = lookup_movie(title=title,
                                    session=session,
                                    identifiers=options.identifiers)
        if not movie_lookup:
            console('ERROR: movie lookup failed for movie {}, aborting'.format(
                options.movie_title))
            return

        title = movie_lookup['movie_name']
        movie = db.get_movie_by_title_and_year(list_id=movie_list.id,
                                               title=title,
                                               year=year,
                                               session=session)
        if not movie:
            console("Adding movie with title {} to list {}".format(
                title, movie_list.name))
            movie = db.MovieListMovie(title=title,
                                      year=year,
                                      list_id=movie_list.id)
        else:
            console("Movie with title {} already exist in list {}".format(
                title, movie_list.name))

        id_list = []
        if options.identifiers:
            id_list = options.identifiers
        else:
            for _id in db.MovieListBase().supported_ids:
                if movie_lookup.get(_id):
                    id_list.append({_id: movie_lookup.get(_id)})
        if id_list:
            console('Setting movie identifiers:')
            for ident in id_list:
                for key in ident:
                    console('{}: {}'.format(key, ident[key]))
            movie.ids = db.get_db_movie_identifiers(identifier_list=id_list,
                                                    session=session)
        session.merge(movie)
        console('Successfully added movie {} to movie list {} '.format(
            title, movie_list.name))
Exemple #47
0
def pending_list_add(options):
    with Session() as session:
        try:
            pending_list = plugin_pending_list.get_list_by_exact_name(options.list_name, session=session)
        except NoResultFound:
            console('Could not find a pending list with name `{}`, creating'.format(options.list_name))
            pending_list = plugin_pending_list.PendingListList(name=options.list_name)
            session.add(pending_list)
        session.merge(pending_list)
        session.commit()
        title = options.entry_title
        entry = {'title': options.entry_title, 'url': options.url}
        db_entry = plugin_pending_list.get_entry_by_title(list_id=pending_list.id, title=title, session=session)
        if db_entry:
            console("Entry with the title `{}` already exist with list `{}`. Will replace identifiers if given".format(
                title, pending_list.name))
            operation = 'updated'
        else:
            console("Adding entry with title `{}` to list `{}`".format(title, pending_list.name))
            db_entry = plugin_pending_list.PendingListEntry(entry=entry, pending_list_id=pending_list.id)
            if options.approved:
                console('marking entry as approved')
                db_entry.approved = True
            session.add(db_entry)
            operation = 'added'
        if options.attributes:
            console('Adding attributes to entry `{}`'.format(title))
            for identifier in options.attributes:
                for k, v in identifier.items():
                    entry[k] = v
            db_entry.entry = entry
        console('Successfully {} entry `{}` to pending list `{}` '.format(operation, title, pending_list.name))
Exemple #48
0
def display_details(options):
    """Display detailed series information, ie. series show NAME"""
    name = options.series_name
    with Session() as session:
        name = normalize_series_name(name)
        # Sort by length of name, so that partial matches always show shortest matching title
        matches = shows_by_name(name, session=session)
        if not matches:
            console(colorize(ERROR_COLOR, 'ERROR: Unknown series `%s`' % name))
            return
        # Pick the best matching series
        series = matches[0]
        table_title = colorize('white', series.name)
        if len(matches) > 1:
            warning = (
                colorize('red', ' WARNING: ') +
                'Multiple series match to `{}`.\n '
                'Be more specific to see the results of other matches:\n\n'
                ' {}'.format(name, ', '.join(s.name for s in matches[1:])))
            if not options.table_type == 'porcelain':
                console(warning)
        header = [
            'Entity ID', 'Latest age', 'Release titles', 'Release Quality',
            'Proper'
        ]
        table_data = [header]
        entities = get_all_entities(series, session=session)
        for entity in entities:
            if entity.identifier is None:
                identifier = colorize(ERROR_COLOR, 'MISSING')
                age = ''
            else:
                identifier = entity.identifier
                age = entity.age
            entity_data = [identifier, age]
            release_titles = []
            release_qualities = []
            release_propers = []
            for release in entity.releases:
                title = release.title
                quality = release.quality.name
                if not release.downloaded:
                    title = colorize(UNDOWNLOADED_RELEASE_COLOR, title)
                    quality = quality
                else:
                    title += ' *'
                    title = colorize(DOWNLOADED_RELEASE_COLOR, title)
                    quality = quality
                release_titles.append(title)
                release_qualities.append(quality)
                release_propers.append(
                    'Yes' if release.proper_count > 0 else '')
            entity_data.append('\n'.join(release_titles))
            entity_data.append('\n'.join(release_qualities))
            entity_data.append('\n'.join(release_propers))
            table_data.append(entity_data)
        footer = ' %s \n' % (colorize(DOWNLOADED_RELEASE_COLOR,
                                      '* Downloaded'))
        if not series.identified_by:
            footer += (
                '\n Series plugin is still learning which episode numbering mode is \n'
                ' correct for this series (identified_by: auto).\n'
                ' Few duplicate downloads can happen with different numbering schemes\n'
                ' during this time.')
        else:
            footer += '\n Series uses `%s` mode to identify episode numbering (identified_by).' % series.identified_by
        footer += ' \n See option `identified_by` for more information.\n'
        if series.begin:
            footer += ' Begin episode for this series set to `%s`.' % series.begin.identifier
    try:
        table = TerminalTable(options.table_type,
                              table_data,
                              table_title,
                              drop_columns=[4, 3, 1])
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
        return
    if not options.table_type == 'porcelain':
        console(footer)
Exemple #49
0
def do_cli_summary(manager, options):
    header = [
        'Task',
        'Last execution',
        'Last success',
        'Produced',
        'Accepted',
        'Rejected',
        'Failed',
        'Duration',
    ]
    table_data = [header]

    with Session() as session:
        for task in session.query(db.StatusTask).all():
            ok = (
                session.query(db.TaskExecution)
                .filter(db.TaskExecution.task_id == task.id)
                .filter(db.TaskExecution.succeeded == True)
                .filter(db.TaskExecution.produced > 0)
                .order_by(db.TaskExecution.start.desc())
                .first()
            )

            if ok is None:
                duration = None
                last_success = '-'
            else:
                duration = ok.end - ok.start
                last_success = ok.start.strftime('%Y-%m-%d %H:%M')

                age = datetime.datetime.utcnow() - ok.start
                if age > timedelta(days=7):
                    last_success = colorize('red', last_success)
                elif age < timedelta(minutes=10):
                    last_success = colorize('green', last_success)
            # Fix weird issue that a task registers StatusTask but without an execution. GH #2022
            last_exec = (
                task.last_execution_time.strftime('%Y-%m-%d %H:%M')
                if task.last_execution_time
                else '-'
            )

            table_data.append(
                [
                    task.name,
                    last_exec,
                    last_success,
                    ok.produced if ok is not None else '-',
                    ok.accepted if ok is not None else '-',
                    ok.rejected if ok is not None else '-',
                    ok.failed if ok is not None else '-',
                    '%1.fs' % duration.total_seconds() if duration is not None else '-',
                ]
            )

    table = TerminalTable(options.table_type, table_data)
    try:
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
Exemple #50
0
 def exposed_console(self, text, *args, **kwargs):
     text = rpyc.classic.obtain(text)
     terminal.console(text, *args, **kwargs)
Exemple #51
0
def reset(manager):
    Base.metadata.drop_all(bind=manager.engine)
    Base.metadata.create_all(bind=manager.engine)
    console('The FlexGet database has been reset.')
Exemple #52
0
def cleanup(manager):
    manager.db_cleanup(force=True)
    console('Database cleanup complete.')
Exemple #53
0
def get_access_token(account,
                     token=None,
                     refresh=False,
                     re_auth=False,
                     called_from_cli=False):
    """
    Gets authorization info from a pin or refresh token.
    :param account: Arbitrary account name to attach authorization to.
    :param unicode token: The pin or refresh token, as supplied by the trakt website.
    :param bool refresh: If True, refresh the access token using refresh_token from db.
    :param bool re_auth: If True, account is re-authorized even if it already exists in db.
    :raises RequestException: If there is a network error while authorizing.
    """
    data = {
        'client_id': CLIENT_ID,
        'client_secret': CLIENT_SECRET,
        'redirect_uri': 'urn:ietf:wg:oauth:2.0:oob',
    }
    with Session() as session:
        acc = session.query(TraktUserAuth).filter(
            TraktUserAuth.account == account).first()
        if acc and datetime.now(
        ) < acc.expires and not refresh and not re_auth:
            return acc.access_token
        else:
            if (acc and
                (refresh or datetime.now() >= acc.expires - timedelta(days=5))
                    and not re_auth):
                logger.debug('Using refresh token to re-authorize account {}.',
                             account)
                data['refresh_token'] = acc.refresh_token
                data['grant_type'] = 'refresh_token'
                token_dict = token_oauth(data)
            elif token:
                # We are only in here if a pin was specified, so it's safe to use console instead of logging
                console(
                    'Warning: PIN authorization has been deprecated. Use Device Authorization instead.'
                )
                data['code'] = token
                data['grant_type'] = 'authorization_code'
                token_dict = token_oauth(data)
            elif called_from_cli:
                logger.debug(
                    'No pin specified for an unknown account {}. Attempting to authorize device.',
                    account,
                )
                token_dict = device_auth()
            else:
                raise plugin.PluginError(
                    'Account %s has not been authorized. See `flexget trakt auth -h` on how to.'
                    % account)
            try:
                new_acc = TraktUserAuth(
                    account,
                    token_dict['access_token'],
                    token_dict['refresh_token'],
                    token_dict.get('created_at', time.time()),
                    token_dict['expires_in'],
                )
                session.merge(new_acc)
                return new_acc.access_token
            except requests.RequestException as e:
                raise plugin.PluginError(
                    'Token exchange with trakt failed: {0}'.format(e))
Exemple #54
0
    def daemon_command(self, options: argparse.Namespace) -> None:
        """
        Handles the 'daemon' CLI command.

        Fires events:

        * manager.daemon.started
        * manager.daemon.completed

        :param options: argparse options
        """

        # Import API so it can register to daemon.started event
        if options.action == 'start':
            if self.is_daemon:
                logger.error('Daemon already running for this config.')
                return
            elif self.task_queue.is_alive():
                logger.error(
                    'Non-daemon execution of FlexGet is running. Cannot start daemon until it is finished.'
                )
                return
            if options.daemonize:
                self.daemonize()
            if options.autoreload_config:
                self.autoreload_config = True
            try:
                signal.signal(signal.SIGTERM, self._handle_sigterm)
            except ValueError as e:
                # If flexget is being called from another script, e.g. windows service helper, and we are not the
                # main thread, this error will occur.
                logger.debug('Error registering sigterm handler: {}', e)
            self.is_daemon = True

            def run_daemon(tray_icon: 'TrayIcon' = None):
                fire_event('manager.daemon.started', self)
                self.task_queue.start()
                self.ipc_server.start()
                self.task_queue.wait()
                fire_event('manager.daemon.completed', self)
                if tray_icon:
                    tray_icon.stop()

            if options.tray_icon:
                from flexget.tray_icon import tray_icon  # noqa

                self._add_tray_icon_items(tray_icon)

                # Tray icon must be run in the main thread.
                m = threading.Thread(target=run_daemon, args=(tray_icon, ))
                m.start()
                tray_icon.run()
                m.join()
            else:
                run_daemon()

        elif options.action in ['stop', 'reload-config', 'status']:
            if not self.is_daemon:
                console('There does not appear to be a daemon running.')
                return
            if options.action == 'status':
                logger.debug(
                    '`daemon status` called. Daemon running. (PID: {})',
                    os.getpid())
                console(f'Daemon running. (PID: {os.getpid()})')
            elif options.action == 'stop':
                tasks = ('all queued tasks (if any) have' if options.wait else
                         'currently running task (if any) has')
                logger.info(
                    'Daemon shutdown requested. Shutdown will commence when {} finished executing.',
                    tasks,
                )
                self.shutdown(options.wait)
            elif options.action == 'reload-config':
                logger.info('Reloading config from disk.')
                try:
                    self.load_config()
                except ValueError as e:
                    logger.error('Error loading config: {}', e.args[0])
                else:
                    logger.info('Config successfully reloaded from disk.')
Exemple #55
0
def display_summary(options):
    """
    Display series summary.
    :param options: argparse options from the CLI
    """
    porcelain = options.table_type == 'porcelain'
    with Session() as session:
        kwargs = {
            'configured': options.configured,
            'premieres': options.premieres,
            'session': session,
            'sort_by': options.sort_by,
            'descending': options.order
        }
        if options.new:
            kwargs['status'] = 'new'
            kwargs['days'] = options.new
        elif options.stale:
            kwargs['status'] = 'stale'
            kwargs['days'] = options.stale
        if options.sort_by == 'name':
            kwargs['sort_by'] = 'show_name'
        else:
            kwargs['sort_by'] = 'last_download_date'

        query = get_series_summary(**kwargs)
        header = ['Name', 'Latest', 'Age', 'Downloaded', 'Identified By']
        for index, value in enumerate(header):
            if value.lower() == options.sort_by:
                header[index] = colorize(SORT_COLUMN_COLOR, value)

        table_data = [header]
        for series in query:
            name_column = series.name

            behind = (0, )
            latest_release = '-'
            age_col = '-'
            episode_id = '-'
            latest = get_latest_release(series)
            identifier_type = series.identified_by
            if identifier_type == 'auto':
                identifier_type = colorize('yellow', 'auto')
            if latest:
                behind = new_entities_after(latest)
                latest_release = get_latest_status(latest)
                # colorize age
                age_col = latest.age
                if latest.age_timedelta is not None:
                    if latest.age_timedelta < timedelta(days=1):
                        age_col = colorize(NEW_EP_COLOR, latest.age)
                    elif latest.age_timedelta < timedelta(days=3):
                        age_col = colorize(FRESH_EP_COLOR, latest.age)
                    elif latest.age_timedelta > timedelta(days=400):
                        age_col = colorize(OLD_EP_COLOR, latest.age)
                episode_id = latest.identifier
            if not porcelain:
                if behind[0] > 0:
                    name_column += colorize(
                        BEHIND_EP_COLOR,
                        ' {} {} behind'.format(behind[0], behind[1]))

            table_data.append([
                name_column, episode_id, age_col, latest_release,
                identifier_type
            ])
    try:
        table = TerminalTable(options.table_type,
                              table_data,
                              wrap_columns=[3],
                              drop_columns=[4, 3, 2])
        console(table.output)
    except TerminalTableError as e:
        console('ERROR: %s' % str(e))
        return
    if not porcelain:
        if not query.count():
            console('Use `flexget series list all` to view all known series.')
        else:
            console(
                'Use `flexget series show NAME` to get detailed information.')
Exemple #56
0
    def on_task_filter(self, task, config):
        if not task.options.try_regexp:
            return
        if self.abort:
            return

        console('-' * 79)
        console('Hi there, welcome to try regexps in realtime!')
        console(
            'Press ^D or type \'exit\' to continue. Type \'continue\' to continue non-interactive execution.'
        )
        console(
            'Task \'%s\' has %s entries, enter regexp to see what matches it.'
            % (task.name, len(task.entries)))
        while (True):
            try:
                s = input('--> ')
                if s == 'exit':
                    break
                if s == 'abort' or s == 'continue':
                    self.abort = True
                    break
            except EOFError:
                break

            count = 0
            for entry in task.entries:
                try:
                    match, field = self.matches(entry, s)
                    if match:
                        console('Title: %-40s URL: %-30s From: %s' %
                                (entry['title'], entry['url'], field))
                        count += 1
                except re.error:
                    console('Invalid regular expression')
                    break
            console('%s of %s entries matched' % (count, len(task.entries)))
        console('Bye!')
Exemple #57
0
 def exposed_console(self, text, *args, **kwargs):
     console(text, *args, **kwargs)
Exemple #58
0
    def on_task_output(self, task, config):
        if not config and task.options.dump_entries is None:
            return

        eval_lazy = 'eval' in task.options.dump_entries
        trace = 'trace' in task.options.dump_entries
        title = 'title' in task.options.dump_entries
        states = ['accepted', 'rejected', 'failed', 'undecided']
        dumpstates = [s for s in states if s in task.options.dump_entries]
        specificstates = dumpstates
        if not dumpstates:
            dumpstates = states
        undecided = [entry for entry in task.all_entries if entry.undecided]
        if 'undecided' in dumpstates:
            if undecided:
                console('-- Undecided: --------------------------')
                dump(undecided, task.options.debug, eval_lazy, trace, title)
            elif specificstates:
                console('No undecided entries')
        if 'accepted' in dumpstates:
            if task.accepted:
                console('-- Accepted: ---------------------------')
                dump(task.accepted, task.options.debug, eval_lazy, trace, title)
            elif specificstates:
                console('No accepted entries')
        if 'rejected' in dumpstates:
            if task.rejected:
                console('-- Rejected: ---------------------------')
                dump(task.rejected, task.options.debug, eval_lazy, trace, title)
            elif specificstates:
                console('No rejected entries')
        if 'failed' in dumpstates:
            if task.failed:
                console('-- Failed: -----------------------------')
                dump(task.failed, task.options.debug, eval_lazy, trace, title)
            elif specificstates:
                console('No failed entries')
Exemple #59
0
def on_manager_shutdown(manager):
    if not manager.options.mem_usage:
        return

    import resource

    console(
        'Resource Module memory usage: %s (kb)'
        % resource.getrusage(resource.RUSAGE_SELF).ru_maxrss
    )
    global heapy
    console('Heapy module calculating memory usage:')
    console(heapy.heap())
    console('-' * 79)
    console('Heapy module calculating report (this may take a while):')
    console(heapy.heap().get_rp(40))
    heapy = None
Exemple #60
0
def dump(entries, debug=False, eval_lazy=False, trace=False, title_only=False):
    """
    Dump *entries* to stdout

    :param list entries: Entries to be dumped.
    :param bool debug: Print non printable fields as well.
    :param bool eval_lazy: Evaluate lazy fields.
    :param bool trace: Display trace information.
    :param bool title_only: Display only title field
    """

    def sort_key(field):
        # Sort certain fields above the rest
        if field == 'title':
            return (0,)
        if field == 'url':
            return (1,)
        if field == 'original_url':
            return (2,)
        return 3, field

    for entry in entries:
        for field in sorted(entry, key=sort_key):
            if field.startswith('_') and not debug:
                continue
            if title_only and field != 'title':
                continue
            if entry.is_lazy(field) and not eval_lazy:
                value = '<LazyField - value will be determined when it is accessed>'
            else:
                try:
                    value = entry[field]
                except KeyError:
                    value = '<LazyField - lazy lookup failed>'
            if isinstance(value, str):
                try:
                    console('%-17s: %s' % (field, value.replace('\r', '').replace('\n', '')))
                except Exception:
                    console('%-17s: %r (warning: unable to print)' % (field, value))
            elif isinstance(value, list):
                console('%-17s: %s' % (field, '[%s]' % ', '.join(str(v) for v in value)))
            elif isinstance(value, (int, float, dict)):
                console('%-17s: %s' % (field, value))
            elif value is None:
                console('%-17s: %s' % (field, value))
            else:
                try:
                    value = str(entry[field])
                    console('%-17s: %s' % (field, value.replace('\r', '').replace('\n', '')))
                except Exception:
                    if debug:
                        console('%-17s: [not printable] (%r)' % (field, value))
        if trace:
            console('-- Processing trace:')
            for item in entry.traces:
                console('%-10s %-7s %s' % (item[0], '' if item[1] is None else item[1], item[2]))
        if not title_only:
            console('')