'episode_identifier': latest_ep_identifier, 'episode_age': latest_ep_age, 'number_of_episodes_behind': new_eps_after_latest_ep, 'last_downloaded_release': release } show_item = { 'show_id': show.id, 'show_name': show.name, 'begin_episode': begin, 'latest_downloaded_episode': latest } return show_item series_list_parser = api.parser() series_list_parser.add_argument('in_config', choices=('configured', 'unconfigured', 'all'), default='configured', help="Filter list if shows are currently in configuration.") series_list_parser.add_argument('premieres', type=inputs.boolean, default=False, help="Filter by downloaded premieres only.") series_list_parser.add_argument('status', choices=('new', 'stale'), help="Filter by status") series_list_parser.add_argument('days', type=int, help="Filter status by number of days. Default is 7 for new and 365 for stale") series_list_parser.add_argument('page', type=int, default=1, help='Page number. Default is 1') series_list_parser.add_argument('number_of_shows', type=int, default=100, help='Shows per page. Default is 100.') series_list_parser.add_argument('sort_by', choices=('show_name', 'episodes_behind_latest', 'last_download_date'), default='show_name', help="Sort response by attribute.") series_list_parser.add_argument('order', choices=('desc', 'asc'), default='desc', help="Sorting order.")
'input_movie_list_id_object', ObjectsContainer.input_movie_list_id_object) movie_list_id_object_schema = api.schema( 'movie_list_id_object', ObjectsContainer.return_movie_list_id_object) movie_list_object_schema = api.schema('movie_list_object', ObjectsContainer.movie_list_object) list_object_schema = api.schema('list_object', ObjectsContainer.list_object) return_lists_schema = api.schema('return_lists', ObjectsContainer.return_lists) return_movies_schema = api.schema('return_movies', ObjectsContainer.return_movies) new_list_schema = api.schema('new_list', ObjectsContainer.list_input) identifiers_schema = api.schema('movie_list.identifiers', ObjectsContainer.return_identifiers) movie_list_parser = api.parser() movie_list_parser.add_argument('name', help='Filter results by list name') @movie_list_api.route('/') class MovieListAPI(APIResource): @etag @api.response(200, model=return_lists_schema) @api.doc(parser=movie_list_parser) def get(self, session=None): """ Gets movies lists """ args = movie_list_parser.parse_args() name = args.get('name') movie_lists = [ movie_list.to_dict() for movie_list in ml.get_movie_lists(name=name, session=session)
'message': 'DB Cleanup triggered'}, 200 @db_api.route('/vacuum/') class DBVacuum(APIResource): @api.response(200, 'DB VACUUM triggered') def get(self, session=None): """ Potentially increase performance and decrease database size""" session.execute('VACUUM') session.commit() return {'status': 'success', 'message': 'DB VACUUM triggered'}, 200 plugin_parser = api.parser() plugin_parser.add_argument('plugin_name', required=True, help='Name of plugin to reset') @db_api.route('/reset_plugin/') class DBPluginReset(APIResource): @api.response(200, 'Plugin DB reset triggered') @api.response(400, 'The plugin has no stored schema to reset') @api.doc(parser=plugin_parser) def get(self, session=None): """ Reset the DB of a specific plugin """ args = plugin_parser.parse_args() plugin = args['plugin_name'] try: reset_schema(plugin)
show_item = { 'show_id': show.id, 'show_name': show.name, 'alternate_names': [n.alt_name for n in show.alternate_names], 'begin_episode': begin, 'latest_downloaded_episode': latest, 'in_tasks': [_show.name for _show in show.in_tasks] } return show_item show_details_schema = api.schema('show_details', show_details_schema) shows_schema = api.schema('list_of_shows', shows_schema) series_list_parser = api.parser() series_list_parser.add_argument('in_config', choices=('configured', 'unconfigured', 'all'), default='configured', help="Filter list if shows are currently in configuration.") series_list_parser.add_argument('premieres', type=inputs.boolean, default=False, help="Filter by downloaded premieres only.") series_list_parser.add_argument('status', choices=('new', 'stale'), help="Filter by status") series_list_parser.add_argument('days', type=int, help="Filter status by number of days.") series_list_parser.add_argument('page', type=int, default=1, help='Page number. Default is 1') series_list_parser.add_argument('page_size', type=int, default=10, help='Shows per page. Max is 100.') series_list_parser.add_argument('sort_by', choices=('show_name', 'last_download_date'), default='last_download_date', help="Sort response by attribute.") series_list_parser.add_argument('descending', type=inputs.boolean, default=True, store_missing=True, help="Sorting order.")
'id': {'type': 'integer'}, 'name': {'type': 'string'}, 'added_on': {'type': 'string'} } } entry_list_input_object = copy.deepcopy(entry_list_base_object) del entry_list_input_object['properties']['id'] del entry_list_input_object['properties']['added_on'] entry_list_return_lists = {'type': 'array', 'items': entry_list_base_object} entry_list_object_schema = api.schema('entry_list_object_schema', entry_list_base_object) entry_list_input_object_schema = api.schema('entry_list_input_object_schema', entry_list_input_object) entry_list_return_lists_schema = api.schema('entry_list_return_lists_schema', entry_list_return_lists) entry_list_parser = api.parser() entry_list_parser.add_argument('name', help='Filter results by list name') @entry_list_api.route('/') class EntryListListsAPI(APIResource): @api.doc(parser=entry_list_parser) @api.response(200, 'Successfully retrieved entry lists', entry_list_return_lists_schema) def get(self, session=None): """ Get entry lists """ args = entry_list_parser.parse_args() name = args.get('name') entry_lists = [entry_list.to_dict() for entry_list in el.get_entry_lists(name=name, session=session)] return jsonify({'entry_lists': entry_lists})
from __future__ import unicode_literals, division, absolute_import from builtins import * # noqa pylint: disable=unused-import, redefined-builtin from flask.helpers import send_file from flask_restplus import inputs from flexget.api import api, APIResource from flexget.api.app import APIError, BadRequest from flexget.utils.cache import cached_resource from requests import RequestException cached_api = api.namespace('cached', description='Cache remote resources') cached_parser = api.parser() cached_parser.add_argument('url', required=True, help='URL to cache') cached_parser.add_argument( 'force', type=inputs.boolean, default=False, help='Force fetching remote resource' ) @cached_api.route('/') @api.doc(description='Returns a cached copy of the requested resource, matching its mime type') class CachedResource(APIResource): @api.response(200, description='Cached resource') @api.response(BadRequest) @api.response(APIError) @api.doc(parser=cached_parser) def get(self, session=None): """ Cache remote resources """ args = cached_parser.parse_args() url = args.get('url') force = args.get('force')
from __future__ import unicode_literals, division, absolute_import from builtins import * # pylint: disable=unused-import, redefined-builtin from flask.helpers import send_file from flask_restplus import inputs from flexget.api import api, APIResource from flexget.api.app import APIError, BadRequest from flexget.utils.cache import cached_resource from requests import RequestException cached_api = api.namespace('cached', description='Cache remote resources') cached_parser = api.parser() cached_parser.add_argument('url', required=True, help='URL to cache') cached_parser.add_argument('force', type=inputs.boolean, default=False, help='Force fetching remote resource') @cached_api.route('/') @api.doc( description= 'Returns a cached copy of the requested resource, matching its mime type') class CachedResource(APIResource): @api.response(200, description='Cached resource') @api.response(BadRequest) @api.response(APIError) @api.doc(parser=cached_parser) def get(self, session=None): """ Cache remote resources """
'revenue', 'homepage', 'genres', 'updated', ], 'additionalProperties': False, } description = 'Either title, TMDB ID or IMDB ID are required for a lookup' return_schema = api.schema_model('tmdb_search_schema', ObjectsContainer.movie_object) tmdb_parser = api.parser() tmdb_parser.add_argument('title', help='Movie title') tmdb_parser.add_argument('tmdb_id', help='TMDB ID') tmdb_parser.add_argument('tmdb_id', help='TMDB ID') tmdb_parser.add_argument('language', help='ISO 639-1 language code') tmdb_parser.add_argument('year', type=int, help='Movie year') tmdb_parser.add_argument('only_cached', type=int, help='Return only cached results') tmdb_parser.add_argument('include_posters', type=inputs.boolean, default=False, help='Include posters in response') tmdb_parser.add_argument('include_backdrops', type=inputs.boolean, default=False,
'type': 'integer' }, 'number_of_seen_entries': { 'type': 'integer' }, 'total_number_of_pages': { 'type': 'integer' }, 'page_number': { 'type': 'integer' } } } seen_search_schema = api.schema('seen_search_schema', seen_search_schema) seen_search_parser = api.parser() seen_search_parser.add_argument( 'value', help='Search by any field value or leave empty to get entries') seen_search_parser.add_argument('page', type=int, default=1, help='Page number') seen_search_parser.add_argument('page_size', type=int, default=10, help='Seen entries per page. Max value is 100') seen_search_parser.add_argument('is_seen_local', type=inputs.boolean, default=None, help='Filter results by seen locality.') seen_search_parser.add_argument('sort_by',
'backdrops': {'type': 'array', 'items': poster_object}, 'genres': {'type': 'array', 'items': {'type': 'string'}}, 'updated': {'type': 'string', 'format': 'date-time'}, }, 'required': ['id', 'name', 'url', 'year', 'original_name', 'alternative_name', 'runtime', 'language', 'overview', 'tagline', 'rating', 'votes', 'popularity', 'adult', 'budget', 'revenue', 'homepage', 'genres', 'updated'], 'additionalProperties': False } description = 'Either title, TMDB ID or IMDB ID are required for a lookup' return_schema = api.schema('tmdb_search_schema', ObjectsContainer.movie_object) tmdb_parser = api.parser() tmdb_parser.add_argument('title', help='Movie title') tmdb_parser.add_argument('tmdb_id', help='TMDB ID') tmdb_parser.add_argument('imdb_id', help='IMDB ID') tmdb_parser.add_argument('year', type=int, help='Movie year') tmdb_parser.add_argument('only_cached', type=int, help='Return only cached results') tmdb_parser.add_argument('include_posters', type=inputs.boolean, default=False, help='Include posters in response') tmdb_parser.add_argument('include_backdrops', type=inputs.boolean, default=False, help='Include backdrops in response') @tmdb_api.route('/movies/') @api.doc(description=description) class TMDBMoviesAPI(APIResource): @etag @api.response(200, model=return_schema) @api.response(NotFoundError)
'items': search_result_object } } } default_error_schema = api.schema('default_error_schema', objects_container.default_error_schema) tvdb_series_schema = api.schema('tvdb_series_schema', objects_container.tvdb_series_object) tvdb_episode_schema = api.schema('tvdb_episode_schema', objects_container.episode_object) search_results_schema = api.schema('tvdb_search_results_schema', objects_container.search_results_object) series_parser = api.parser() series_parser.add_argument('include_actors', type=inputs.boolean, help='Include actors in response') @tvdb_api.route('/series/<string:title>/') @api.doc(params={'title': 'TV Show name or TVDB ID'}, parser=series_parser) class TVDBSeriesSearchApi(APIResource): @api.response(200, 'Successfully found show', tvdb_series_schema) @api.response(404, 'No show found', default_error_schema) def get(self, title, session=None): args = series_parser.parse_args() try: tvdb_id = int(title) except ValueError:
tasks = [{ 'id': task_id, 'name': task_name } for task_id, task_name, task_event in self.manager.execute( options=options)] return {'tasks': tasks} class ExecuteQueue(Queue): """ Supports task log streaming by acting like a file object """ def write(self, s): self.put(json.dumps({'log': s})) stream_parser = api.parser() stream_parser.add_argument('progress', type=bool, required=False, default=True, help='Include task progress updates') stream_parser.add_argument('summary', type=bool, required=False, default=True, help='Include task summary') stream_parser.add_argument('log', type=bool, required=False, default=False,
def get(self, session=None): """ Dump Server threads for debugging """ id2name = dict([(th.ident, th.name) for th in threading.enumerate()]) threads = [] for threadId, stack in sys._current_frames().items(): dump = [] for filename, lineno, name, line in traceback.extract_stack(stack): dump.append('File: "%s", line %d, in %s' % (filename, lineno, name)) if line: dump.append(line.strip()) threads.append({'name': id2name.get(threadId), 'id': threadId, 'dump': dump}) return jsonify(threads=threads) server_log_parser = api.parser() server_log_parser.add_argument( 'lines', type=int, default=200, help='How many lines to find before streaming' ) server_log_parser.add_argument('search', help='Search filter support google like syntax') def reverse_readline(fh, start_byte=0, buf_size=8192): """a generator that returns the lines of a file in reverse order""" segment = None offset = 0 if start_byte: fh.seek(start_byte) else: fh.seek(0, os.SEEK_END) total_size = remaining_size = fh.tell()
'episode_identifier': latest_ep_identifier, 'episode_age': latest_ep_age, 'number_of_episodes_behind': new_eps_after_latest_ep, 'last_downloaded_release': release } show_item = { 'show_id': show.id, 'show_name': show.name, 'begin_episode': begin, 'latest_downloaded_episode': latest } return show_item series_list_parser = api.parser() series_list_parser.add_argument( 'in_config', choices=('configured', 'unconfigured', 'all'), default='configured', help="Filter list if shows are currently in configuration.") series_list_parser.add_argument('premieres', type=inputs.boolean, default=False, help="Filter by downloaded premieres only.") series_list_parser.add_argument('status', choices=('new', 'stale'), help="Filter by status") series_list_parser.add_argument( 'days', type=int,
} } search_results_object = { 'type': 'object', 'properties': { 'search_results': {'type': 'array', 'items': search_result_object} } } default_error_schema = api.schema('default_error_schema', objects_container.default_error_schema) tvdb_series_schema = api.schema('tvdb_series_schema', objects_container.tvdb_series_object) tvdb_episode_schema = api.schema('tvdb_episode_schema', objects_container.episode_object) search_results_schema = api.schema('tvdb_search_results_schema', objects_container.search_results_object) series_parser = api.parser() series_parser.add_argument('include_actors', type=inputs.boolean, help='Include actors in response') @tvdb_api.route('/series/<string:title>/') @api.doc(params={'title': 'TV Show name or TVDB ID'}, parser=series_parser) class TVDBSeriesSearchApi(APIResource): @api.response(200, 'Successfully found show', tvdb_series_schema) @api.response(404, 'No show found', default_error_schema) def get(self, title, session=None): args = series_parser.parse_args() try: tvdb_id = int(title) except ValueError: tvdb_id = None
seen_search_schema = { 'type': 'object', 'properties': { 'seen_entries': { 'type': 'array', 'items': seen_object }, 'total_number_of_seen_entries': {'type': 'integer'}, 'number_of_seen_entries': {'type': 'integer'}, 'total_number_of_pages': {'type': 'integer'}, 'page_number': {'type': 'integer'} } } seen_search_schema = api.schema('seen_search_schema', seen_search_schema) seen_search_parser = api.parser() seen_search_parser.add_argument('value', help='Search by any field value or leave empty to get entries') seen_search_parser.add_argument('page', type=int, default=1, help='Page number') seen_search_parser.add_argument('page_size', type=int, default=10, help='Seen entries per page. Max value is 100') seen_search_parser.add_argument('is_seen_local', type=inputs.boolean, default=None, help='Filter results by seen locality.') seen_search_parser.add_argument('sort_by', choices=('title', 'task', 'added', 'local', 'id'), default='added', help="Sort response by attribute") seen_search_parser.add_argument('order', choices=('asc', 'desc'), default='desc', help='Sorting order.') seen_delete_parser = api.parser() seen_delete_parser.add_argument('value', help='Delete by value or leave empty to delete all. BE CAREFUL WITH THIS') seen_delete_parser.add_argument('is_seen_local', type=inputs.boolean, default=None, help='Filter results by seen locality.')
task_api_queue_schema = api.schema_model('task.queue', ObjectsContainer.task_queue_schema) task_api_execute_schema = api.schema_model( 'task.execution', ObjectsContainer.task_execution_results_schema ) task_execution_schema = api.schema_model( 'task_execution_input', ObjectsContainer.task_execution_input ) task_execution_params = api.schema_model( 'tasks.execution_params', ObjectsContainer.params_return_schema ) task_api_desc = ( 'Task config schema too large to display, you can view the schema using the schema API' ) tasks_parser = api.parser() tasks_parser.add_argument( 'include_config', type=inputs.boolean, default=True, help='Include task config' ) @tasks_api.route('/') @api.doc(description=task_api_desc) class TasksAPI(APIResource): @etag @api.response(200, model=tasks_list_schema) @api.doc(parser=tasks_parser) def get(self, session=None): """ List all tasks """ active_tasks = {
login_api = api.namespace('login', description='API Authentication') login_api_schema = api.schema( 'login', { 'type': 'object', 'properties': { 'username': { 'type': 'string' }, 'password': { 'type': 'string' } } }) login_parser = api.parser() login_parser.add_argument('remember', type=bool, required=False, default=False, help='Remember for next time') @login_api.route('/') @api.doc(description='Login to API with username and password') class LoginAPI(APIResource): @api.expect(login_api_schema) @api.response(400, 'Invalid username or password') @api.response(200, 'Login successful') @api.doc(parser=login_parser) def post(self, session=None):
tasks = [_task_info_dict(task) for task in self.manager.task_queue.run_queue.queue] if self.manager.task_queue.current_task: tasks.insert(0, _task_info_dict(self.manager.task_queue.current_task)) return jsonify({'tasks': tasks}) class ExecuteLog(Queue): """ Supports task log streaming by acting like a file object """ def write(self, s): self.put(json.dumps({'log': s})) execute_parser = api.parser() execute_parser.add_argument('progress', type=flask_restplus.inputs.boolean, required=False, default=True, help='Include task progress updates') execute_parser.add_argument('summary', type=flask_restplus.inputs.boolean, required=False, default=True, help='Include task summary') execute_parser.add_argument('log', type=flask_restplus.inputs.boolean, required=False, default=False, help='Include execution log') execute_parser.add_argument('entry_dump', type=flask_restplus.inputs.boolean, required=False, default=False, help='Include dump of entries including fields') _streams = {} @tasks_api.route('/<task>/execute/') @api.doc(params={'task': 'task name'})
}, 'number_of_movies': { 'type': 'integer' }, 'total_number_of_pages': { 'type': 'integer' }, 'page_number': { 'type': 'integer' } } } movie_queue_schema = api.schema('list_movie_queue', movie_queue_schema) movie_queue_parser = api.parser() movie_queue_parser.add_argument('page', type=int, default=1, help='Page number') movie_queue_parser.add_argument('max', type=int, default=100, help='Movies per page') movie_queue_parser.add_argument('queue_name', default='default', help='Filter by movie queue name') movie_queue_parser.add_argument('is_downloaded', type=inputs.boolean, help='Filter list by movies download status') movie_queue_parser.add_argument('sort_by',
tasks = [_task_info_dict(task) for task in self.manager.task_queue.run_queue.queue] if self.manager.task_queue.current_task: tasks.insert(0, _task_info_dict(self.manager.task_queue.current_task)) return jsonify({'tasks': tasks}) class ExecuteLog(Queue): """ Supports task log streaming by acting like a file object """ def write(self, s): self.put(json.dumps({'log': s})) stream_parser = api.parser() stream_parser.add_argument('progress', type=flask_restplus.inputs.boolean, required=False, default=True, help='Include task progress updates') stream_parser.add_argument('summary', type=flask_restplus.inputs.boolean, required=False, default=True, help='Include task summary') stream_parser.add_argument('log', type=flask_restplus.inputs.boolean, required=False, default=False, help='Include execution log') stream_parser.add_argument('entry_dump', type=flask_restplus.inputs.boolean, required=False, default=False, help='Include dump of entries including fields') _streams = {} @tasks_api.route('/<task>/execute/') @api.doc(params={'task': 'task name'})
'pid': { 'type': 'integer' } } }) @server_api.route('/pid/') class ServerPIDAPI(APIResource): @api.response(200, description='Reloaded config', model=pid_schema) def get(self, session=None): """ Get server PID """ return {'pid': os.getpid()} shutdown_parser = api.parser() shutdown_parser.add_argument('force', type=inputs.boolean, required=False, default=False, help='Ignore tasks in the queue') @server_api.route('/shutdown/') class ServerShutdownAPI(APIResource): @api.doc(parser=shutdown_parser) @api.response(200, 'Shutdown requested') def get(self, session=None): """ Shutdown Flexget Daemon """ args = shutdown_parser.parse_args() self.manager.shutdown(args['force'])
from __future__ import unicode_literals, division, absolute_import from builtins import * # noqa pylint: disable=unused-import, redefined-builtin from flask import jsonify from flask_restplus import inputs from flexget.api import api, APIResource from flexget.api.app import BadRequest, NotFoundError, success_response, base_message_schema, empty_response irc_api = api.namespace('irc', description='View and manage IRC connections') irc_parser = api.parser() irc_parser.add_argument('name', help='Name of connection. Leave empty to apply to all connections.') class ObjectsContainer(object): connection_object = { 'type': 'object', 'properties': { 'alive': {'type': 'boolean'}, 'channels': { 'type': 'array', 'items': { 'type': 'object', 'patternProperties': { '\w': {'type': 'integer'} } } }, 'connected_channels': {'type': 'array', 'items': {'type': 'string'}}, 'port': {'type': 'integer'}, 'server': {'type': 'string'} }
} params_return_schema = {'type': 'array', 'items': {'type': 'object'}} tasks_list_schema = api.schema('tasks.list', ObjectsContainer.tasks_list_object) task_input_schema = api.schema('tasks.task', ObjectsContainer.task_input_object) task_return_schema = api.schema('tasks.task', ObjectsContainer.task_return_object) task_api_queue_schema = api.schema('task.queue', ObjectsContainer.task_queue_schema) task_api_execute_schema = api.schema('task.execution', ObjectsContainer.task_execution_results_schema) task_execution_schema = api.schema('task_execution_input', ObjectsContainer.task_execution_input) task_execution_params = api.schema('tasks.execution_params', ObjectsContainer.params_return_schema) task_api_desc = 'Task config schema too large to display, you can view the schema using the schema API' tasks_parser = api.parser() tasks_parser.add_argument('include_config', type=inputs.boolean, default=True, help='Include task config') @tasks_api.route('/') @api.doc(description=task_api_desc) class TasksAPI(APIResource): @etag @api.response(200, model=tasks_list_schema) @api.doc(parser=tasks_parser) def get(self, session=None): """ List all tasks """ args = tasks_parser.parse_args() if not args.get('include_config'): return jsonify(list(self.manager.user_config.get('tasks', {})))
dump = [] for filename, lineno, name, line in traceback.extract_stack(stack): dump.append('File: "%s", line %d, in %s' % (filename, lineno, name)) if line: dump.append(line.strip()) threads.append({ 'name': id2name.get(threadId), 'id': threadId, 'dump': dump }) return jsonify(threads=threads) server_log_parser = api.parser() server_log_parser.add_argument('lines', type=int, default=200, help='How many lines to find before streaming') server_log_parser.add_argument('search', help='Search filter support google like syntax') def reverse_readline(fh: IO, start_byte: int = 0, buf_size: int = 8192) -> Generator[str, None, None]: """a generator that returns the lines of a file in reverse order""" segment: OptionalType[str] = None offset = 0 if start_byte:
pending_lists_entries_return_object = { 'type': 'array', 'items': pending_list_entry_base_object } pending_list_object_schema = api.schema_model( 'pending_list.return_list', ObjectsContainer.pending_list_base_object) pending_list_input_object_schema = api.schema_model( 'pending_list.input_list', ObjectsContainer.pending_list_input_object) pending_list_return_lists_schema = api.schema_model( 'pending_list.return_lists', ObjectsContainer.pending_list_return_lists) pending_list_operation_schema = api.schema_model( 'pending_list.operation_schema', ObjectsContainer.operation_object) list_parser = api.parser() list_parser.add_argument('name', help='Filter results by list name') @pending_list_api.route('/') class PendingListListsAPI(APIResource): @etag @api.doc(parser=list_parser) @api.response(200, 'Successfully retrieved pending lists', pending_list_return_lists_schema) def get(self, session=None): """ Get pending lists """ args = list_parser.parse_args() name = args.get('name') pending_lists = [
'status', 'overview', 'tvdb_id', ], 'additionalProperties': False, } search_results_object = {'type': 'array', 'items': search_result_object} tvdb_series_schema = api.schema_model('tvdb_series_schema', ObjectsContainer.tvdb_series_object) tvdb_episode_schema = api.schema_model('tvdb_episode_schema', ObjectsContainer.episode_object) search_results_schema = api.schema_model( 'tvdb_search_results_schema', ObjectsContainer.search_results_object ) base_parser = api.parser() base_parser.add_argument( 'language', default='en', help='Language abbreviation string for different language support' ) series_parser = base_parser.copy() series_parser.add_argument( 'include_actors', type=inputs.boolean, help='Include actors in response' ) @tvdb_api.route('/series/<string:title>/') @api.doc(params={'title': 'TV Show name or TVDB ID'}, parser=series_parser) class TVDBSeriesLookupAPI(APIResource): @etag(cache_age=3600) @api.response(200, 'Successfully found show', tvdb_series_schema)
operation_object = { 'type': 'object', 'properties': {'operation': {'type': 'string', 'enum': ['approve', 'reject']}}, 'required': ['operation'], 'additionalProperties': False, } pending_entry_schema = api.schema_model('pending.entry', ObjectsContainer.pending_entry_object) pending_entry_list_schema = api.schema_model( 'pending.entry_list', ObjectsContainer.pending_entry_list ) operation_schema = api.schema_model('pending.operation', ObjectsContainer.operation_object) filter_parser = api.parser() filter_parser.add_argument('task_name', help='Filter by task name') filter_parser.add_argument('approved', type=inputs.boolean, help='Filter by approval status') sort_choices = ('added', 'task_name', 'title', 'url', 'approved') pending_parser = api.pagination_parser(parser=filter_parser, sort_choices=sort_choices) just_task_parser = filter_parser.copy() just_task_parser.remove_argument('approved') description = 'Either \'approve\' or \'reject\'' @pending_api.route('/') class PendingEntriesAPI(APIResource): @etag
for chunk in chunked(expired_series): num = session.query(TVDBSeries).filter(TVDBSeries.id.in_(chunk)).update({'expired': True}, 'fetch') log.debug('%s series marked as expired', num) for chunk in chunked(expired_episodes): num = session.query(TVDBEpisode).filter(TVDBEpisode.id.in_(chunk)).update({'expired': True}, 'fetch') log.debug('%s episodes marked as expired', num) # Save the time of this update session.commit() persist['last_local'] = datetime.now() persist['last_server'] = new_server tvdb_api = api.namespace('tvdb', description='TheTVDB Shows') tvdb_api_parser = api.parser() tvdb_api_parser.add_argument('search', type=str, required=True, help='TV Show name or tvdbid') @tvdb_api.route('/search/') class TVDBSearchApi(APIResource): @api.doc(parser=tvdb_api_parser) @api.response(400, 'missing search parameter') def get(self, session=None): args = tvdb_api_parser.parse_args() search = args['search'] if not search: return {'detail': 'missing query parameter'}, 400
show_item = { 'show_id': show.id, 'show_name': show.name, 'alternate_names': [n.alt_name for n in show.alternate_names], 'begin_episode': begin, 'latest_downloaded_episode': latest, 'in_tasks': [_show.name for _show in show.in_tasks] } return show_item show_details_schema = api.schema('show_details', show_details_schema) shows_schema = api.schema('list_of_shows', shows_schema) series_list_parser = api.parser() series_list_parser.add_argument('in_config', choices=('configured', 'unconfigured', 'all'), default='configured', help="Filter list if shows are currently in configuration.") series_list_parser.add_argument('premieres', type=inputs.boolean, default=False, help="Filter by downloaded premieres only.") series_list_parser.add_argument('status', choices=('new', 'stale'), help="Filter by status") series_list_parser.add_argument('days', type=int, help="Filter status by number of days.") series_list_parser.add_argument('page', type=int, default=1, help='Page number. Default is 1') series_list_parser.add_argument('page_size', type=int, default=10, help='Shows per page. Max is 100.') series_list_parser.add_argument('sort_by', choices=('show_name', 'episodes_behind_latest', 'last_download_date'), default='show_name', help="Sort response by attribute.") series_list_parser.add_argument('order', choices=('desc', 'asc'), default='desc', help="Sorting order.") series_list_parser.add_argument('lookup', choices=('tvdb', 'tvmaze'), action='append',
'absolute_number': {'type': 'integer'}, 'episode_name': {'type': 'string'}, 'overview': {'type': 'string'}, 'director': {'type': 'array', 'items': {'type': 'string'}}, 'writer': {'type': 'array', 'items': {'type': 'string'}}, 'rating': {'type': 'number'}, 'image': {'type': 'string'}, 'first_aired': {'type': 'string'}, 'series_id': {'type': 'integer'} } } tvdb_series_schema = api.schema('tvdb_series_schema', tvdb_series_object) tvdb_episode_schema = api.schema('tvdb_episode_schema', episode_object) series_parser = api.parser() series_parser.add_argument('include_actors', type=inputs.boolean, help='Include actors in response') @tvdb_api.route('/series/<string:title>/') @api.doc(params={'title': 'TV Show name or TVDB ID'}, parser=series_parser) class TVDBSeriesSearchApi(APIResource): @api.response(200, 'Successfully found show', tvdb_series_schema) @api.response(404, 'No show found', default_error_schema) def get(self, title, session=None): args = series_parser.parse_args() try: tvdb_id = int(title) except ValueError: tvdb_id = None
'phase_handlers': { 'type': 'array', 'items': phase_object }, }, } plugin_list_reply = {'type': 'array', 'items': plugin_object} plugin_schema = api.schema_model('plugin_object', ObjectsContainer.plugin_object) plugin_list_reply_schema = api.schema_model('plugin_list_reply', ObjectsContainer.plugin_list_reply) plugin_parser = api.parser() plugin_parser.add_argument( 'include_schema', type=inputs.boolean, default=False, help='Include plugin schema. This will increase response size', ) plugins_parser = api.pagination_parser(plugin_parser) plugins_parser.add_argument('interface', case_sensitive=False, help='Show plugins which implement this interface') plugins_parser.add_argument('phase', case_sensitive=False, help='Show plugins that act on this phase')
del series_input_object['anyOf'] series_input_object['required'] = ['name'] series_list_schema = api.schema_model('list_series', ObjectsContainer.series_list_schema) series_edit_schema = api.schema_model('series_edit_schema', ObjectsContainer.series_edit_object) series_input_schema = api.schema_model('series_input_schema', ObjectsContainer.series_input_object) show_details_schema = api.schema_model('show_details', ObjectsContainer.single_series_object) episode_list_schema = api.schema_model('episode_list', ObjectsContainer.episode_list_schema) episode_schema = api.schema_model('episode_item', ObjectsContainer.episode_object) release_schema = api.schema_model('release_schema', ObjectsContainer.release_object) release_list_schema = api.schema_model('release_list_schema', ObjectsContainer.release_list_schema) base_series_parser = api.parser() base_series_parser.add_argument('begin', type=inputs.boolean, default=True, help='Show series begin episode') base_series_parser.add_argument('latest', type=inputs.boolean, default=True, help='Show series latest downloaded episode and release') sort_choices = ('show_name', 'last_download_date') series_list_parser = api.pagination_parser(base_series_parser, sort_choices=sort_choices) series_list_parser.add_argument('in_config', choices=('configured', 'unconfigured', 'all'), default='configured', help="Filter list if shows are currently in configuration.") series_list_parser.add_argument('premieres', type=inputs.boolean, default=False, help="Filter by downloaded premieres only.") series_list_parser.add_argument('status', choices=('new', 'stale'), help="Filter by status") series_list_parser.add_argument('days', type=int, help="Filter status by number of days.") series_list_parser.add_argument('lookup', choices=('tvdb', 'tvmaze'), action='append', help="Get lookup result for every show by sending another request to lookup API")
def movie_queue_sort_order_enum(value): enum = ['desc', 'asc'] if isinstance(value, bool): return value if value not in enum: raise ValueError('Value expected to be in' + ' ,'.join(enum)) if value == 'desc': return True return False movie_queue_schema = api.schema('list_movie_queue', movie_queue_schema) movie_queue_parser = api.parser() movie_queue_parser.add_argument('page', type=int, default=1, help='Page number') movie_queue_parser.add_argument('max', type=int, default=100, help='Movies per page') movie_queue_parser.add_argument('status', type=movie_queue_status_value_enum, default=False, help='Filter list by status. Filter by {0}. Default is "pending"'.format( ' ,'.join(movie_queue_status_value_enum_list))) movie_queue_parser.add_argument('sort_by', type=movie_queue_sort_value_enum, default='added', help="Sort response by 'added', 'downloaded', 'id', 'title'") movie_queue_parser.add_argument('order', type=movie_queue_sort_order_enum, default='desc', help="Sorting order, can be 'asc' or 'desc'") movie_add_results_schema = { 'type': 'object', 'properties': { 'message': {'type': 'string'}, 'movie': movie_object
'title': {'type': 'string'}, 'reason': {'type': 'string'}, 'task': {'type': 'string'}, 'added': {'type': 'string', 'format': 'date-time'}, 'local': {'type': 'boolean'}, 'fields': {'type': 'array', 'items': seen_field_object}, }, } seen_search_object = {'type': 'array', 'items': seen_object} seen_object_schema = api.schema_model('seen_object_schema', ObjectsContainer.seen_object) seen_search_schema = api.schema_model('seen_search_schema', ObjectsContainer.seen_search_object) seen_base_parser = api.parser() seen_base_parser.add_argument( 'value', help='Filter by any field value or leave empty to get all entries' ) seen_base_parser.add_argument( 'local', type=inputs.boolean, default=None, help='Filter results by seen locality.' ) sort_choices = ('title', 'task', 'added', 'local', 'reason', 'id') seen_search_parser = api.pagination_parser(seen_base_parser, sort_choices) @seen_api.route('/') class SeenSearchAPI(APIResource): @etag @api.response(NotFoundError)
task_return_schema = api.schema_model('tasks.task', ObjectsContainer.task_return_object) task_api_queue_schema = api.schema_model('task.queue', ObjectsContainer.task_queue_schema) task_api_execute_schema = api.schema_model( 'task.execution', ObjectsContainer.task_execution_results_schema) task_execution_schema = api.schema_model('task_execution_input', ObjectsContainer.task_execution_input) task_execution_params = api.schema_model('tasks.execution_params', ObjectsContainer.params_return_schema) task_api_desc = ( 'Task config schema too large to display, you can view the schema using the schema API' ) tasks_parser = api.parser() tasks_parser.add_argument('include_config', type=inputs.boolean, default=True, help='Include task config') @tasks_api.route('/') @api.doc(description=task_api_desc) class TasksAPI(APIResource): @etag @api.response(200, model=tasks_list_schema) @api.doc(parser=tasks_parser) def get(self, session: Session = None) -> Response: """ List all tasks """
'pid': { 'type': 'integer' } } }) @server_api.route('/pid/') class ServerPIDAPI(APIResource): @api.response(200, description='Reloaded config', model=pid_schema) def get(self, session=None): """ Get server PID """ return {'pid': os.getpid()} shutdown_parser = api.parser() shutdown_parser.add_argument('force', type=inputs.boolean, required=False, default=False, help='Ignore tasks in the queue') @server_api.route('/shutdown/') class ServerShutdownAPI(APIResource): @api.doc(parser=shutdown_parser) @api.response(200, 'Shutdown requested') def get(self, session=None): """ Shutdown Flexget Daemon """ args = shutdown_parser.parse_args() self.manager.shutdown(args['force']) return {}
tvmaze_id = int(title) except ValueError: tvmaze_id = None try: if tvmaze_id: series = APITVMaze.series_lookup(tvmaze_id=tvmaze_id, session=session) else: series = APITVMaze.series_lookup(series_name=title, session=session) except LookupError as e: raise NotFoundError(e.args[0]) return jsonify(series.to_dict()) episode_parser = api.parser() episode_parser.add_argument('season_num', type=int, help='Season number') episode_parser.add_argument('ep_num', type=int, help='Episode number') episode_parser.add_argument('air_date', type=inputs.date_from_iso8601, help="Air date in the format of '2012-01-01'") @tvmaze_api.route('/episode/<int:tvmaze_id>/') @api.doc(params={'tvmaze_id': 'TVMaze ID of show'}) @api.doc(parser=episode_parser) class TVDBEpisodeSearchAPI(APIResource): @etag(cache_age=3600) @api.response(200, 'Successfully found episode', tvmaze_episode_schema) @api.response(NotFoundError) @api.response(BadRequest)
'fields': { 'type': 'array', 'items': seen_field_object }, }, } seen_search_object = {'type': 'array', 'items': seen_object} seen_object_schema = api.schema_model('seen_object_schema', ObjectsContainer.seen_object) seen_search_schema = api.schema_model('seen_search_schema', ObjectsContainer.seen_search_object) seen_base_parser = api.parser() seen_base_parser.add_argument( 'value', help='Filter by any field value or leave empty to get all entries') seen_base_parser.add_argument('local', type=inputs.boolean, default=None, help='Filter results by seen locality.') sort_choices = ('title', 'task', 'added', 'local', 'reason', 'id') seen_search_parser = api.pagination_parser(seen_base_parser, sort_choices) @seen_api.route('/') class SeenSearchAPI(APIResource): @etag
tvmaze_id = None try: if tvmaze_id: result = tvm.series_lookup(tvmaze_id=tvmaze_id, session=session) else: result = tvm.series_lookup(series_name=title, session=session) except LookupError as e: return {'status': 'error', 'message': e.args[0] }, 404 return jsonify(result.to_dict()) episode_parser = api.parser() episode_parser.add_argument('season_num', type=int, help='Season number') episode_parser.add_argument('ep_num', type=int, help='Episode number') episode_parser.add_argument('air_date', type=inputs.date_from_iso8601, help="Air date in the format of '2012-01-01'") @tvmaze_api.route('/episode/<int:tvmaze_id>/') @api.doc(params={'tvmaze_id': 'TVMaze ID of show'}) @api.doc(parser=episode_parser) class TVDBEpisodeSearchAPI(APIResource): @api.response(200, 'Successfully found episode', tvmaze_episode_schema) @api.response(404, 'No show found', default_error_schema) @api.response(500, 'Not enough parameters for lookup', default_error_schema) def get(self, tvmaze_id, session=None): args = episode_parser.parse_args()
series_edit_schema = api.schema('series_edit_schema', ObjectsContainer.series_edit_object) series_input_schema = api.schema('series_input_schema', ObjectsContainer.series_input_object) show_details_schema = api.schema('show_details', ObjectsContainer.single_series_object) episode_list_schema = api.schema('episode_list', ObjectsContainer.episode_list_schema) episode_schema = api.schema('episode_item', ObjectsContainer.episode_object) release_schema = api.schema('release_schema', ObjectsContainer.release_object) release_list_schema = api.schema('release_list_schema', ObjectsContainer.release_list_schema) base_series_parser = api.parser() base_series_parser.add_argument('begin', type=inputs.boolean, default=True, help='Show series begin episode') base_series_parser.add_argument( 'latest', type=inputs.boolean, default=True, help='Show series latest downloaded episode and release') sort_choices = ('show_name', 'last_download_date') series_list_parser = api.pagination_parser(base_series_parser, sort_choices=sort_choices) series_list_parser.add_argument( 'in_config',
'series_name': {'type': 'string'}, 'status': {'type': 'string'}, 'overview': {'type': ['string', 'null']}, 'tvdb_id': {'type': 'integer'} }, 'required': ['aliases', 'first_aired', 'banner', 'network', 'series_name', 'status', 'overview', 'tvdb_id'], 'additionalProperties': False } search_results_object = {'type': 'array', 'items': search_result_object} tvdb_series_schema = api.schema('tvdb_series_schema', ObjectsContainer.tvdb_series_object) tvdb_episode_schema = api.schema('tvdb_episode_schema', ObjectsContainer.episode_object) search_results_schema = api.schema('tvdb_search_results_schema', ObjectsContainer.search_results_object) base_parser = api.parser() base_parser.add_argument('language', default='en', help='Language abbreviation string for different language support') series_parser = base_parser.copy() series_parser.add_argument('include_actors', type=inputs.boolean, help='Include actors in response') @tvdb_api.route('/series/<string:title>/') @api.doc(params={'title': 'TV Show name or TVDB ID'}, parser=series_parser) class TVDBSeriesLookupAPI(APIResource): @etag @api.response(200, 'Successfully found show', tvdb_series_schema) @api.response(NotFoundError) def get(self, title, session=None): args = series_parser.parse_args() language = args['language']
} } history_api_schema = api.schema('history.list', history_api_schema) default_error_schema = { 'type': 'object', 'properties': { 'status': {'type': 'string'}, 'message': {'type': 'string'} } } default_error_schema = api.schema('default_error_schema', default_error_schema) history_parser = api.parser() history_parser.add_argument('page', type=int, required=False, default=1, help='Page number') history_parser.add_argument('max', type=int, required=False, default=50, help='Results per page') history_parser.add_argument('task', type=str, required=False, default=None, help='Filter by task name') @history_api.route('/') @api.doc(parser=history_parser) class HistoryAPI(APIResource): @api.response(404, description='Page does not exist', model=default_error_schema) @api.response(200, model=history_api_schema) def get(self, session=None): """ List of previously accepted entries """ args = history_parser.parse_args() page = args['page'] max_results = args['max']
if not current_user.is_authenticated: return current_app.login_manager.unauthorized() # API Authentication and Authorization login_api = api.namespace('login', description='API Authentication') login_api_schema = api.schema('login', { 'type': 'object', 'properties': { 'username': {'type': 'string'}, 'password': {'type': 'string'} } }) login_parser = api.parser() login_parser.add_argument('remember', type=bool, required=False, default=False, help='Remember for next time') @login_api.route('/') @api.doc(description='Login to API with username and password') class LoginAPI(APIResource): @api.expect(login_api_schema) @api.response(400, 'Invalid username or password') @api.response(200, 'Login successful') @api.doc(parser=login_parser) def post(self, session=None): data = request.json if data:
from flask import jsonify from flask_restx import inputs from flexget.api import APIResource, api from flexget.api.app import ( BadRequest, NotFoundError, base_message_schema, empty_response, success_response, ) irc_api = api.namespace('irc', description='View and manage IRC connections') irc_parser = api.parser() irc_parser.add_argument( 'name', help='Name of connection. Leave empty to apply to all connections.') class ObjectsContainer: connection_object = { 'type': 'object', 'properties': { 'alive': { 'type': 'boolean' }, 'channels': { 'type': 'array', 'items': { 'type': 'object',
} } entry_list_input_object = copy.deepcopy(entry_list_base_object) del entry_list_input_object['properties']['id'] del entry_list_input_object['properties']['added_on'] entry_list_return_lists = {'type': 'array', 'items': entry_list_base_object} entry_list_object_schema = api.schema('entry_list_object_schema', entry_list_base_object) entry_list_input_object_schema = api.schema('entry_list_input_object_schema', entry_list_input_object) entry_list_return_lists_schema = api.schema('entry_list_return_lists_schema', entry_list_return_lists) entry_list_parser = api.parser() entry_list_parser.add_argument('name', help='Filter results by list name') @entry_list_api.route('/') class EntryListListsAPI(APIResource): @api.doc(parser=entry_list_parser) @api.response(200, 'Successfully retrieved entry lists', entry_list_return_lists_schema) def get(self, session=None): """ Get entry lists """ args = entry_list_parser.parse_args() name = args.get('name') entry_lists = [ entry_list.to_dict()
return_identifiers = {"type": "array", "items": {"type": "string"}} input_movie_entry_schema = api.schema("input_movie_entry", ObjectsContainer.input_movie_entry) input_movie_list_id_schema = api.schema("input_movie_list_id_object", ObjectsContainer.input_movie_list_id_object) movie_list_id_object_schema = api.schema("movie_list_id_object", ObjectsContainer.return_movie_list_id_object) movie_list_object_schema = api.schema("movie_list_object", ObjectsContainer.movie_list_object) list_object_schema = api.schema("list_object", ObjectsContainer.list_object) return_lists_schema = api.schema("return_lists", ObjectsContainer.return_lists) return_movies_schema = api.schema("return_movies", ObjectsContainer.return_movies) new_list_schema = api.schema("new_list", ObjectsContainer.list_input) identifiers_schema = api.schema("movie_list.identifiers", ObjectsContainer.return_identifiers) movie_list_parser = api.parser() movie_list_parser.add_argument("name", help="Filter results by list name") @movie_list_api.route("/") class MovieListAPI(APIResource): @etag @api.response(200, model=return_lists_schema) @api.doc(parser=movie_list_parser) def get(self, session=None): """ Gets movies lists """ args = movie_list_parser.parse_args() name = args.get("name") movie_lists = [movie_list.to_dict() for movie_list in ml.get_movie_lists(name=name, session=session)] return jsonify(movie_lists)
movie_return_object['properties']['trailer'] = {'type': 'string'} default_error_object = { 'type': 'object', 'properties': { 'status': {'type': 'string'}, 'message': {'type': 'string'} } } default_error_schema = api.schema('default_error_schema', objects_container.default_error_object) series_return_schema = api.schema('series_return_schema', objects_container.series_return_object) movie_return_schema = api.schema('movie_return_schema', objects_container.movie_return_object) lookup_parser = api.parser() lookup_parser.add_argument('year', type=int, help='Lookup year') lookup_parser.add_argument('trakt_id', type=int, help='Trakt ID') lookup_parser.add_argument('trakt_slug', help='Trakt slug') lookup_parser.add_argument('tmdb_id', type=int, help='TMDB ID') lookup_parser.add_argument('imdb_id', help='IMDB ID') lookup_parser.add_argument('tvdb_id', type=int, help='TVDB ID') lookup_parser.add_argument('tvrage_id', type=int, help='TVRage ID') lookup_parser.add_argument('include_actors', type=inputs.boolean, help='Include actors in response') lookup_parser.add_argument('include_translations', type=inputs.boolean, help='Include translations in response') @trakt_api.route('/series/<string:title>/') @api.doc(params={'title': 'Series name'}) class TraktSeriesSearchApi(APIResource): @api.response(200, 'Successfully found show', series_return_schema)
}, 'required': ['operation'], 'additionalProperties': False } pending_lists_entries_return_object = {'type': 'array', 'items': pending_list_entry_base_object} pending_list_object_schema = api.schema_model('pending_list.return_list', ObjectsContainer.pending_list_base_object) pending_list_input_object_schema = api.schema_model('pending_list.input_list', ObjectsContainer.pending_list_input_object) pending_list_return_lists_schema = api.schema_model('pending_list.return_lists', ObjectsContainer.pending_list_return_lists) pending_list_operation_schema = api.schema_model('pending_list.operation_schema', ObjectsContainer.operation_object) list_parser = api.parser() list_parser.add_argument('name', help='Filter results by list name') @pending_list_api.route('/') class PendingListListsAPI(APIResource): @etag @api.doc(parser=list_parser) @api.response(200, 'Successfully retrieved pending lists', pending_list_return_lists_schema) def get(self, session=None): """ Get pending lists """ args = list_parser.parse_args() name = args.get('name') pending_lists = [pending_list.to_dict() for pending_list in get_pending_lists(name=name, session=session)] return jsonify(pending_lists)