def movie_list_add(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 {}, creating'.format(options.list_name)) movie_list = MovieListList(name=options.list_name) session.add(movie_list) session.merge(movie_list) title, year = split_title_year(options.movie_title) movie_exist = get_movie_by_title(list_id=movie_list.id, title=title, session=session) if movie_exist: console("Movie with the title {} already exist with list {}. Will replace identifiers if given".format( title, movie_list.name)) output = 'Successfully updated movie {} to movie list {} '.format(title, movie_list.name) else: console("Adding movie with title {} to list {}".format(title, movie_list.name)) movie_exist = MovieListMovie(title=title, year=year, list_id=movie_list.id) session.add(movie_exist) output = 'Successfully added movie {} to movie list {} '.format(title, movie_list.name) if options.identifiers: identifiers = [parse_identifier(identifier) for identifier in options.identifiers if options.identifiers] console('Adding identifiers {} to movie {}'.format(identifiers, title)) movie_exist.ids = get_db_movie_identifiers(identifier_list=identifiers, session=session) console(output)
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, 'original_url': options.original_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)
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
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()
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.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)
def forget(manager, options): name = options.series_name if options.episode_id: # remove by id identifier = options.episode_id try: forget_series_episode(name, identifier) console('Removed episode `%s` from series `%s`.' % (identifier, name.capitalize())) except ValueError: # Try upper casing identifier if we fail at first try: forget_series_episode(name, identifier.upper()) console('Removed episode `%s` from series `%s`.' % (identifier, name.capitalize())) except ValueError as e: console(e.message) else: # remove whole series try: forget_series(name) console('Removed series `%s` from database.' % name.capitalize()) except ValueError as e: console(e.message) manager.config_changed()
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)
def entry_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 %s' % options.list_name) session.delete(entry_list)
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 movie_list_purge(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 console('Deleting list %s' % options.list_name) session.delete(movie_list)
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 = forget(forget_name) console("Removed %s titles (%s fields)" % (count, fcount)) manager.config_changed()
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
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()
def clear_rejected(manager): session = Session() try: results = session.query(RememberEntry).delete() console('Cleared %i items.' % results) session.commit() if results: manager.config_changed() finally: session.close()
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()
def clear(options): """Deletes waiting movies from queue""" items = queue_get(downloaded=False, queue_name=options.queue_name) console("Removing the following movies from movie queue:") console("-" * 79) for item in items: console(item.title) queue_del(title=item.title, queue_name=options.queue_name) if not items: console("No results") console("-" * 79)
def list_failed(): session = Session() try: results = session.query(FailedEntry).all() if not results: console('No failed entries recorded') for entry in results: console('%16s - %s - %s times - %s' % (entry.tof.strftime('%Y-%m-%d %H:%M'), entry.title, entry.count, entry.reason)) finally: session.close()
def clear(): """Deletes waiting movies from queue""" items = queue_get(downloaded=False) console('Removing the following movies from movie queue:') console('-' * 79) for item in items: console(item.title) queue_del(title=item.title) if not items: console('No results') console('-' * 79)
def clear(options): """Deletes waiting movies from queue""" items = queue_get(downloaded=False, queue_name=options.queue_name) console('Removing the following movies from movie queue:') console('-' * 79) for item in items: console(item.title) if not items: console('No results') console('-' * 79) queue_clear(options.queue_name)
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)
def add_credential(username, password): """ Add (or update) credential into database :param username: :param password: :return: """ proxy = T411Proxy() is_new = proxy.add_credential(username=username, password=password) if is_new: console('Credential successfully added') else: console('Credential successfully updated')
def on_manager_shutdown(manager): if not manager.options.mem_usage: return import resource print '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
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 with Session() as session: se = SeenEntry(seen_name, "cli_seen") sf = SeenField("cli_seen", seen_name) se.fields.append(sf) session.add(se) console("Added %s as seen. This will affect all tasks." % seen_name)
def get_access_token(account, token=None, refresh=False, re_auth=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 } 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) 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_auth(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' data['redirect_uri'] = 'urn:ietf:wg:oauth:2.0:oob' token_dict = token_auth(data) else: log.debug('No pin specified for an unknown account %s. Attempting to authorize device.', account) token_dict = device_auth() try: access_token = token_dict['access_token'] refresh_token = token_dict['refresh_token'] created_at = token_dict.get('created_at', time.time()) expires_in = token_dict['expires_in'] if acc: acc.access_token = access_token acc.refresh_token = refresh_token acc.created = token_created_date(created_at) acc.expires = token_expire_date(expires_in) else: acc = TraktUserAuth(account, access_token, refresh_token, created_at, expires_in) session.add(acc) return access_token except requests.RequestException as e: raise plugin.PluginError('Token exchange with trakt failed: {0}'.format(e.args[0]))
def on_exec_stopped(manager, options): if not options.mem_usage: return global heapy console('Calculating memory usage:') console(heapy.heap()) console('-' * 79) console(heapy.heap().get_rp(40)) heapy = None
def on_task_start(self, task, config): if task.options.dump_config: import yaml console('--- config from task: %s' % task.name) console(yaml.safe_dump(task.config)) console('---') task.abort(silent=True) if task.options.dump_config_python: console(task.config) task.abort(silent=True)
def seen_search(options, session=None): search_term = '%' + options.search_term + '%' seen_entries = seen.search(value=search_term, status=None, session=session) for se in seen_entries: console('ID: %s Name: %s Task: %s Added: %s' % (se.id, se.title, se.task, se.added.strftime('%c'))) for sf in se.fields: console(' %s: %s' % (sf.field, sf.value)) console('') if not seen_entries: console('No results')
def print_terms(category_name=None, term_type_name=None): proxy = T411Proxy() proxy.set_credential() formatting_main = '%-60s %-5s %-5s' formatting_sub = ' %-55s %-5s %-5s' console(formatting_main % ('Name', 'PID', 'ID')) if term_type_name: console("Not yet implemented !") else: with Session() as session: categories = proxy.find_categories(category_name=category_name, is_sub_category=True, session=session) for category in categories: console(formatting_main % (category.name, category.parent_id, category.id)) for term_type in category.term_types: console(formatting_main % (term_type.name, '', term_type.id)) for term in term_type.terms: console(formatting_sub % (term.name, term_type.id, term.id))
def do_cli(manager, options): import win32file import win32serviceutil if hasattr(sys, 'real_prefix'): # We are in a virtualenv, there is some special setup if not os.path.exists(os.path.join(sys.prefix, 'python.exe')): console('Creating a hard link to virtualenv python.exe in root of virtualenv') win32file.CreateHardLink(os.path.join(sys.prefix, 'python.exe'), os.path.join(sys.prefix, 'Scripts', 'python.exe')) argv = options.args if options.help: argv = [] # Hack sys.argv a bit so that we get a better usage message sys.argv[0] = 'flexget service' win32serviceutil.HandleCommandLine(AppServerSvc, argv=['flexget service'] + argv)
def print_ae(ae): diff = datetime.now() - ae.added console('ID: %-6s | Title: %s\nAdded: %s (%d days ago)\nURL: %s' % (ae.id, ae.title, ae.added, diff.days, ae.url)) source_names = ', '.join([s.name for s in ae.sources]) tag_names = ', '.join([t.name for t in ae.tags]) console('Source(s): %s | Tag(s): %s' % (source_names or 'N/A', tag_names or 'N/A')) if ae.description: console('Description: %s' % strip_html(ae.description)) console('---')
def do_cli(manager, options): """Handle movie-queue subcommand""" console( 'WARNING!: movie_queue plugin is deprecated. Please switch to using movie_list\n' ) if options.queue_action == 'list': queue_list(options) return # If the action affects make sure all entries are processed again next run. manager.config_changed() if options.queue_action == 'clear': clear(options) return if options.queue_action == 'del': try: what = parse_what(options.movie_name, lookup=False) title = queue_del(queue_name=options.queue_name, **what) except QueueError as e: console('ERROR: %s' % e.message) else: console('Removed %s from queue' % title) return if options.queue_action == 'forget': try: what = parse_what(options.movie_name, lookup=False) title = queue_forget(queue_name=options.queue_name, **what) except QueueError as e: console('ERROR: %s' % e.message) else: console( 'Forgot that %s was downloaded. Movie will be downloaded again.' % title.get('title')) return if options.queue_action == 'add': try: quality = qualities.Requirements(options.quality) except ValueError as e: console('`%s` is an invalid quality requirement string: %s' % (options.quality, e.message)) return # Adding to queue requires a lookup for missing information what = {} try: what = parse_what(options.movie_name) except QueueError as e: console('ERROR: %s' % e.message) if not what.get('title') or not (what.get('imdb_id') or what.get('tmdb_id')): console('could not determine movie') # TODO: Rethink errors return try: queue_add(quality=quality, queue_name=options.queue_name, **what) except QueueError as e: console(e.message) if e.errno == 1: # This is an invalid quality error, display some more info # TODO: Fix this error? # console('Recognized qualities are %s' % ', '.join([qual.name for qual in qualities.all()])) console( 'ANY is the default and can also be used explicitly to specify that quality should be ignored.' ) except OperationalError: console('OperationalError') return
def queue_list(options): """List movie queue""" if options.type == 'downloaded': downloaded = True elif options.type == 'waiting': downloaded = False else: downloaded = None items = queue_get(downloaded=downloaded, queue_name=options.queue_name) if options.porcelain: console('%-10s %-s %-7s %-s %-37s %-s %s' % ('IMDB id', '|', 'TMDB id', '|', 'Title', '|', 'Quality')) else: console('-' * 79) console('%-10s %-7s %-37s %s' % ('IMDB id', 'TMDB id', 'Title', 'Quality')) console('-' * 79) for item in items: if options.porcelain: console('%-10s %-s %-7s %-s %-37s %-s %s' % (item.imdb_id, '|', item.tmdb_id, '|', item.title, '|', item.quality)) else: console('%-10s %-7s %-37s %s' % (item.imdb_id, item.tmdb_id, item.title, item.quality)) if not items: console('No results') if options.porcelain: pass else: console('-' * 79)
def do_cli(manager, options): session = Session() try: console('-- History: ' + '-' * 67) 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) for item in reversed(query.all()): console(' Task : %s' % item.task) console(' Title : %s' % item.title) console(' Url : %s' % item.url) if item.filename: console(' Stored : %s' % item.filename) console(' Time : %s' % item.time.strftime("%c")) console(' Details : %s' % item.details) console('-' * 79) finally: session.close()
def do_cli(manager, options): if options.action == 'auth': if not (options.account): console('You must specify an account (local identifier) so we know where to save your access token!') return try: get_access_token(options.account, options.pin, re_auth=True) console('Successfully authorized Flexget app on Trakt.tv. Enjoy!') return except plugin.PluginError as e: console('Authorization failed: %s' % e) elif options.action == 'show': 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 console('{:-^21}|{:-^28}|{:-^28}'.format('Account', 'Created', 'Expires')) for auth in accounts: console('{:<21}|{:>28}|{:>28}'.format( auth.account, auth.created.strftime('%Y-%m-%d'), auth.expires.strftime('%Y-%m-%d'))) return # 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.') elif options.action == 'refresh': if not options.account: console('Please specify an account') return try: get_access_token(options.account, refresh=True) console('Successfully refreshed your access token.') return except plugin.PluginError as e: console('Authorization failed: %s' % e) elif options.action == 'delete': if not options.account: console('Please specify an account') return try: delete_account(options.account) console('Successfully deleted your access token.') return except plugin.PluginError as e: console('Deletion failed: %s' % e)
def display_details(name): """Display detailed series information, ie. series show 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('ERROR: Unknown series `%s`' % name) return # Pick the best matching series series = matches[0] console('Showing results for `%s`.' % series.name) if len(matches) > 1: console('WARNING: Multiple series match to `%s`.' % name) console('Be more specific to see the results of other matches:') for s in matches[1:]: console(' - %s' % s.name) console(' %-63s%-15s' % ('Identifier, Title', 'Quality')) console('-' * 79) episodes = show_episodes(series, session=session) for episode in episodes: if episode.identifier is None: console(' None <--- Broken!') else: console(' %s (%s) - %s' % (episode.identifier, episode.identified_by or 'N/A', episode.age)) for release in episode.releases: status = release.quality.name title = release.title if len(title) > 55: title = title[:55] + '...' if release.proper_count > 0: status += '-proper' if release.proper_count > 1: status += str(release.proper_count) if release.downloaded: console(' * %-60s%-15s' % (title, status)) else: console(' %-60s%-15s' % (title, status)) console('-' * 79) console(' * = downloaded') if not series.identified_by: console('') console( ' Series plugin is still learning which episode numbering mode is ' ) console(' correct for this series (identified_by: auto).') console( ' Few duplicate downloads can happen with different numbering schemes' ) console(' during this time.') else: console( ' Series uses `%s` mode to identify episode numbering (identified_by).' % series.identified_by) console(' See option `identified_by` for more information.') if series.begin: console(' Begin episode for this series set to `%s`.' % series.begin.identifier)
def reset(manager): Base.metadata.drop_all(bind=manager.engine) Base.metadata.create_all(bind=manager.engine) console('The FlexGet database has been reset.')
def cli_search(options): search_term = ' '.join(options.keywords) tags = options.tags sources = options.sources def print_ae(ae): diff = datetime.now() - ae.added console('ID: %-6s | Title: %s\nAdded: %s (%d days ago)\nURL: %s' % (ae.id, ae.title, ae.added, diff.days, ae.url)) source_names = ', '.join([s.name for s in ae.sources]) tag_names = ', '.join([t.name for t in ae.tags]) console('Source(s): %s | Tag(s): %s' % (source_names or 'N/A', tag_names or 'N/A')) if ae.description: console('Description: %s' % strip_html(ae.description)) console('---') session = Session() try: console('Searching: %s' % search_term) if tags: console('Tags: %s' % ', '.join(tags)) if sources: console('Sources: %s' % ', '.join(sources)) console('Please wait...') console('') results = False query = re.sub(r'[ \(\)]+', ' ', search_term).strip() for ae in search(session, query, tags=tags, sources=sources): print_ae(ae) results = True if not results: console('No results found.') finally: session.close()
def do_cli(manager, options): if options.action == 'clear': num = clear_entries(options.task) console('%s entries cleared from backlog.' % num) else: if options.porcelain: cols = '{:<65.64}{:<1.1}{:<15.15}' console(cols.format('Title', '|', 'Task')) else: cols = '{:<65.64}{:<15.15}' console('-' * 80) console(cols.format('Title', 'Task')) console('-' * 80) with Session() as session: entries = get_entries(options.task, session=session) for entry in entries: if options.porcelain: console(cols.format(entry.title, '|', entry.task)) else: console(cols.format(entry.title, entry.task)) if not entries: console('No items')
def entry_list_show(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 {}'.format( options.list_name)) return try: 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: entry = get_entry_by_title(entry_list.id, options.entry, session=session) if not entry: console( 'Could not find matching entry with title `{}` in list `{}`' .format(options.entry, options.list_name)) return console('Showing fields for entry ID {}'.format(options.list_name)) console('-' * 79) for k, v in sorted(entry.entry.items()): console('{}: {}'.format(k.upper(), v))
def cleanup(manager): manager.db_cleanup(force=True) console('Database cleanup complete.')
def display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ session = Session() try: query = (session.query(Series).outerjoin(Series.episodes).outerjoin(Episode.releases). outerjoin(Series.in_tasks).group_by(Series.id)) if options.configured == 'configured': query = query.having(func.count(SeriesTask.id) >= 1) elif options.configured == 'unconfigured': query = query.having(func.count(SeriesTask.id) < 1) if options.premieres: query = (query.having(func.max(Episode.season) <= 1).having(func.max(Episode.number) <= 2). having(func.count(SeriesTask.id) < 1)).filter(Release.downloaded == True) if options.new: query = query.having(func.max(Episode.first_seen) > datetime.now() - timedelta(days=options.new)) if options.stale: query = query.having(func.max(Episode.first_seen) < datetime.now() - timedelta(days=options.stale)) if options.porcelain: formatting = '%-30s %s %-10s %s %-10s %s %-20s' console(formatting % ('Name', '|', 'Latest', '|', 'Age', '|', 'Downloaded')) else: formatting = ' %-30s %-10s %-10s %-20s' console('-' * 79) console(formatting % ('Name', 'Latest', 'Age', 'Downloaded')) console('-' * 79) for series in query.order_by(Series.name).yield_per(10): series_name = series.name if len(series_name) > 30: series_name = series_name[:27] + '...' new_ep = ' ' behind = 0 status = 'N/A' age = 'N/A' episode_id = 'N/A' latest = get_latest_release(series) if latest: if latest.first_seen > datetime.now() - timedelta(days=2): if options.porcelain: pass else: new_ep = '>' behind = new_eps_after(latest) status = get_latest_status(latest) age = latest.age episode_id = latest.identifier if behind: episode_id += ' +%s' % behind if options.porcelain: console(formatting % (series_name, '|', episode_id, '|', age, '|', status)) else: console(new_ep + formatting[1:] % (series_name, episode_id, age, status)) if behind >= 3: console(' ! Latest download is %d episodes behind, this may require ' 'manual intervention' % behind) if options.porcelain: pass else: console('-' * 79) console(' > = new episode ') console(' Use `flexget series show NAME` to get detailed information') finally: session.close()
def reset_plugin(options): plugin = options.reset_plugin if not plugin: if options.porcelain: console('%-20s | Ver | Tables' % 'Name') else: console('-' * 79) console('%-20s Ver Tables' % 'Name') console('-' * 79) for k, v in sorted(plugin_schemas.items()): tables = '' line_len = 0 for name in v['tables']: if options.porcelain: pass else: if line_len + len(name) + 2 >= 53: tables += '\n' tables += ' ' * 26 line_len = len(name) + 2 else: line_len += len(name) + 2 tables += name + ', ' tables = tables.rstrip(', ') if options.porcelain: console('%-20s %s %-3s %s %s' % (k, '|', v['version'], '|', tables)) else: console('%-20s %-2s %s' % (k, v['version'], tables)) else: 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 display_summary(options): """ Display series summary. :param options: argparse options from the CLI """ with Session() as session: kwargs = { 'configured': options.configured, 'premieres': options.premieres, 'session': session } if options.new: kwargs['status'] = 'new' kwargs['days'] = options.new elif options.stale: kwargs['status'] = 'stale' kwargs['days'] = options.stale query = get_series_summary(**kwargs) if options.porcelain: formatting = '%-30s %s %-10s %s %-10s %s %-20s' console(formatting % ('Name', '|', 'Latest', '|', 'Age', '|', 'Downloaded')) else: formatting = ' %-30s %-10s %-10s %-20s' console('-' * 79) console(formatting % ('Name', 'Latest', 'Age', 'Downloaded')) console('-' * 79) for series in query.order_by(Series.name).yield_per(10): series_name = series.name if len(series_name) > 30: series_name = series_name[:27] + '...' new_ep = ' ' behind = 0 status = 'N/A' age = 'N/A' episode_id = 'N/A' latest = get_latest_release(series) if latest: if latest.first_seen > datetime.now() - timedelta(days=2): if options.porcelain: pass else: new_ep = '>' behind = new_eps_after(latest) status = get_latest_status(latest) age = latest.age episode_id = latest.identifier if behind: episode_id += ' +%s' % behind if options.porcelain: console(formatting % (series_name, '|', episode_id, '|', age, '|', status)) else: console(new_ep + formatting[1:] % (series_name, episode_id, age, status)) if behind >= 3: console( ' ! Latest download is %d episodes behind, this may require ' 'manual intervention' % behind) if options.porcelain: pass else: console('-' * 79) console(' > = new episode ') console( ' Use `flexget series show NAME` to get detailed information')
def exposed_console(self, text, *args, **kwargs): console(text, *args, **kwargs)
def movie_list_add(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 {}, creating'.format( options.list_name)) movie_list = MovieListList(name=options.list_name) session.merge(movie_list) title, year = split_title_year(options.movie_title) console('Trying to lookup movie %s title' % title) entry = lookup_movie(title=title, session=session, identifiers=options.identifiers) if not entry: console('movie lookup failed for movie %s, aborting') return title = entry['movie_name'] movie = get_movie_by_title(list_id=movie_list.id, title=title, session=session) if not movie: console("Adding movie with title {} to list {}".format( title, movie_list.name)) movie = MovieListMovie(title=entry['movie_name'], 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 SUPPORTED_IDS: if entry.get(_id): id_list.append({_id: entry.get(_id)}) if id_list: console('Setting movie identifiers:', id_list) movie.ids = 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))
def plugins_summary(manager, options): if options.porcelain: console('%-30s%-s%-30s%-s%s' % ('Name', '|', 'Roles (priority)', '|', 'Info')) else: console('-' * 79) console('%-30s%-30s%-s' % ('Name', 'Roles (priority)', 'Info')) console('-' * 79) # print the list for plugin in sorted(get_plugins(phase=options.phase, group=options.group)): # do not include test classes, unless in debug mode if plugin.get('debug_plugin', False) and not options.debug: continue flags = [] if plugin.instance.__doc__: flags.append('--doc') if plugin.builtin: flags.append('builtin') if plugin.debug: flags.append('debug') handlers = plugin.phase_handlers roles = ', '.join('%s(%s)' % (phase, handlers[phase].priority) for phase in handlers) tab = '|' if options.porcelain: console('%-30s%-s%-30s%-s%s' % (plugin.name, '|', roles, '|', ', '.join(flags))) else: console('%-30s%-30s%-s' % (plugin.name, roles, ', '.join(flags))) if options.porcelain: pass else: console('-' * 79)
def do_cli(manager, options, session=None): try: if hasattr(options, 'user'): options.user = options.user.lower() if options.action == 'list': users = session.query(User).all() if users: max_width = len(max([user.name for user in users], key=len)) + 4 console('_' * (max_width + 56 + 9)) console('| %-*s | %-*s |' % (max_width, 'Username', 56, 'API Token')) if users: for user in users: console('| %-*s | %-*s |' % (max_width, user.name, 56, user.token)) else: console('No users found') if options.action == 'add': exists = session.query(User).filter( User.name == options.user).first() if exists: console('User %s already exists' % options.user) return user = User(name=options.user, password=options.password) session.add(user) session.commit() console('Added %s to the database with generated API Token: %s' % (user.name, user.token)) if options.action == 'delete': user = session.query(User).filter( User.name == options.user).first() if not user: console('User %s does not exist' % options.user) return session.delete(user) session.commit() console('Deleted user %s' % options.user) if options.action == 'passwd': user = session.query(User).filter( User.name == options.user).first() if not user: console('User %s does not exist' % options.user) return user.password = options.password session.commit() console('Updated password for user %s' % options.user) if options.action == 'gentoken': user = session.query(User).filter( User.name == options.user).first() if not user: console('User %s does not exist' % options.user) return user.token = generate_key() session.commit() console('Generated new token for user %s' % user.name) console('Token %s' % user.token) finally: session.close()
def exposed_console(self, text): console(text)