'operation': { 'type': 'string', 'enum': ['approve', 'reject'] } }, '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)
'type': 'string' }, }, } connection = { 'type': 'object', 'patternProperties': { r'\w': connection_object } } return_response = {'type': 'array', 'items': connection} return_schema = api.schema_model('irc.connections', ObjectsContainer.return_response) @irc_api.route('/connections/') @api.doc(parser=irc_parser) class IRCStatus(APIResource): @api.response(200, model=return_schema) @api.response(NotFoundError) @api.response(BadRequest) def get(self, session=None): """Returns status of IRC connections""" from .irc import irc_manager if irc_manager is None: raise BadRequest('IRC daemon does not appear to be running')
format_checker_input = { 'type': 'object', 'properties': { 'quality': {'type': 'string', 'format': 'quality'}, 'quality_requirements': {'type': 'string', 'format': 'quality_requirements'}, 'time': {'type': 'string', 'format': 'time'}, 'interval': {'type': 'string', 'format': 'interval'}, 'size': {'type': 'string', 'format': 'size'}, 'percent': {'type': 'string', 'format': 'percent'}, 'regex': {'type': 'string', 'format': 'regex'}, 'file': {'type': 'string', 'format': 'file'}, 'path': {'type': 'string', 'format': 'path'}, 'url': {'type': 'string', 'format': 'url'}, 'episode_identifier': {'type': 'string', 'format': 'episode_identifier'}, 'episode_or_season_id': {'type': 'string', 'format': 'episode_or_season_id'}, }, } format_checker_schema = api.schema_model('format_checker', ObjectContainer.format_checker_input) @schema_api.route('/', doc=False) class SchemaTest(APIResource): @api.validate(format_checker_schema) @api.response(200, model=base_message_schema) def post(self, session=None): """ Validate flexget custom schema""" # If validation passed, all is well return success_response('payload is valid')
'type': 'object', 'properties': { 'id': {'type': 'integer'}, '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('/')
}, 'required': ['password'], 'additionalProperties': False, } user_token_response = { 'type': 'object', 'properties': { 'token': { 'type': 'string' } } } user_password_input_schema = api.schema_model( 'user_password_input', ObjectsContainer.user_password_input) user_token_response_schema = api.schema_model( 'user_token_response', ObjectsContainer.user_token_response) @user_api.route('/') @api.doc('Change user password') class UserManagementAPI(APIResource): @api.validate(model=user_password_input_schema, description='Password change schema') @api.response(BadRequest) @api.response(200, 'Success', model=base_message_schema) @api.doc( description='Change user password. A score of at least 3 is needed.' 'See https://github.com/dropbox/zxcvbn for details') def put(self, session: Session = None) -> Response:
'format': 'path' }, 'url': { 'type': 'string', 'format': 'url' }, 'episode_identifier': { 'type': 'string', 'format': 'episode_identifier' }, 'episode_or_season_id': { 'type': 'string', 'format': 'episode_or_season_id' }, }, } format_checker_schema = api.schema_model('format_checker', ObjectContainer.format_checker_input) @schema_api.route('/', doc=False) class SchemaTest(APIResource): @api.validate(format_checker_schema) @api.response(200, model=base_message_schema) def post(self, session=None): """ Validate flexget custom schema""" # If validation passed, all is well return success_response('payload is valid')
'type': 'object', 'properties': { 'id': {'type': 'integer'}, 'name': {'type': 'string'}, 'added_on': {'type': 'string'}, 'title': {'type': 'string'}, 'original_url': {'type': 'string'}, 'entry': base_entry_object, } } entry_lists_entries_return_object = {'type': 'array', 'items': entry_list_entry_base_object} entry_list_object_schema = api.schema_model('entry_list_object_schema', ObjectsContainer.entry_list_base_object) entry_list_input_object_schema = api.schema_model('entry_list_input_object_schema', ObjectsContainer.entry_list_input_object) entry_list_return_lists_schema = api.schema_model('entry_list_return_lists_schema', ObjectsContainer.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): @etag @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()
from flexget.api import api, APIResource from flexget.api.app import NotFoundError, APIError, base_message_schema, success_response, etag, Conflict schedule_api = api.namespace('schedules', description='Task Scheduler') class ObjectsContainer(object): # SwaggerUI does not yet support anyOf or oneOf schedule_object = copy.deepcopy(schedule_schema) schedule_object['properties']['id'] = {'type': 'integer'} schedule_object['maxProperties'] += 1 schedules_list = {'type': 'array', 'items': schedule_object} base_schedule_schema = api.schema_model('schedules.base', schedule_schema) api_schedule_schema = api.schema_model('schedules.schedule', ObjectsContainer.schedule_object) api_schedules_list_schema = api.schema_model('schedules.list', ObjectsContainer.schedules_list) def _schedule_by_id(schedule_id, schedules): for idx, schedule in enumerate(schedules): if schedule and id(schedule) == schedule_id: schedule = schedule.copy() schedule['id'] = schedule_id return schedule, idx return None, None schedule_desc = "Schedule ID changes upon daemon restart. The schedules object supports either interval or schedule" \ " (cron) objects, see the model definition for details. Tasks also support string or list " \
'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_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')
user_api = api.namespace('user', description='Manage user login credentials') class ObjectsContainer(object): user_password_input = { 'type': 'object', 'properties': {'password': {'type': 'string'}}, 'required': ['password'], 'additionalProperties': False, } user_token_response = {'type': 'object', 'properties': {'token': {'type': 'string'}}} user_password_input_schema = api.schema_model( 'user_password_input', ObjectsContainer.user_password_input ) user_token_response_schema = api.schema_model( 'user_token_response', ObjectsContainer.user_token_response ) @user_api.route('/') @api.doc('Change user password') class UserManagementAPI(APIResource): @api.validate(model=user_password_input_schema, description='Password change schema') @api.response(BadRequest) @api.response(200, 'Success', model=base_message_schema) @api.doc( description='Change user password. A score of at least 3 is needed.' 'See https://github.com/dropbox/zxcvbn for details'
'posters': {'type': 'array', 'items': poster_object}, 'backdrops': {'type': 'array', 'items': poster_object}, 'genres': {'type': 'array', 'items': {'type': 'string'}}, 'updated': {'type': 'string', 'format': 'date-time'}, 'lookup_language': {'type': ['string', 'null']} }, 'required': ['id', 'name', '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_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, help='Include backdrops 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)
'additionalProperties': False, } crash_logs = { 'type': 'array', 'items': { 'type': 'object', 'properties': { 'name': {'type': 'string'}, 'content': {'type': 'array', 'items': {'type': 'string'}}, }, }, } yaml_error_schema = api.schema_model('yaml_error_schema', ObjectsContainer.yaml_error_response) config_validation_schema = api.schema_model( 'config_validation_schema', ObjectsContainer.config_validation_error ) pid_schema = api.schema_model('server.pid', ObjectsContainer.pid_object) raw_config_schema = api.schema_model('raw_config', ObjectsContainer.raw_config_object) version_schema = api.schema_model('server.version', ObjectsContainer.version_object) dump_threads_schema = api.schema_model('server.dump_threads', ObjectsContainer.dump_threads_object) server_manage_schema = api.schema_model('server.manage', ObjectsContainer.server_manage) crash_logs_schema = api.schema_model('server.crash_logs', ObjectsContainer.crash_logs) @server_api.route('/manage/') class ServerReloadAPI(APIResource): @api.validate(server_manage_schema) @api.response(501, model=yaml_error_schema, description='YAML syntax error')
} } operation_object = { 'type': 'object', 'properties': { 'operation': {'type': 'string', 'enum': ['approve', 'reject']} }, '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)
'name': {'type': 'string'} } } list_input = copy.deepcopy(list_object) del list_input['properties']['id'] del list_input['properties']['added_on'] return_movies = {'type': 'array', 'items': movie_list_object} return_lists = {'type': 'array', 'items': list_object} return_identifiers = {'type': 'array', 'items': {'type': 'string'}} input_movie_entry_schema = api.schema_model('input_movie_entry', ObjectsContainer.input_movie_entry) input_movie_list_id_schema = api.schema_model('input_movie_list_id_object', ObjectsContainer.input_movie_list_id_object) movie_list_id_object_schema = api.schema_model('movie_list_id_object', ObjectsContainer.return_movie_list_id_object) movie_list_object_schema = api.schema_model('movie_list_object', ObjectsContainer.movie_list_object) list_object_schema = api.schema_model('list_object', ObjectsContainer.list_object) return_lists_schema = api.schema_model('return_lists', ObjectsContainer.return_lists) return_movies_schema = api.schema_model('return_movies', ObjectsContainer.return_movies) new_list_schema = api.schema_model('new_list', ObjectsContainer.list_input) identifiers_schema = api.schema_model('movie_list.identifiers', ObjectsContainer.return_identifiers) movie_list_parser = api.parser() movie_list_parser.add_argument('name', help='Filter results by list name')
'type': 'array', 'items': { 'type': 'string' } }, '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,
from flexget.api import api, APIResource from flexget.api.app import NotFoundError, APIError, base_message_schema, success_response, etag, Conflict schedule_api = api.namespace('schedules', description='Task Scheduler') class ObjectsContainer(object): # SwaggerUI does not yet support anyOf or oneOf schedule_object = copy.deepcopy(schedule_schema) schedule_object['properties']['id'] = {'type': 'integer'} schedule_object['maxProperties'] += 1 schedules_list = {'type': 'array', 'items': schedule_object} base_schedule_schema = api.schema_model('schedules.base', schedule_schema) api_schedule_schema = api.schema_model('schedules.schedule', ObjectsContainer.schedule_object) api_schedules_list_schema = api.schema_model('schedules.list', ObjectsContainer.schedules_list) def _schedule_by_id(schedule_id, schedules): for idx, schedule in enumerate(schedules): if schedule and id(schedule) == schedule_id: schedule = schedule.copy() schedule['id'] = schedule_id return schedule, idx return None, None
'string', 'description': 'Specify log level', 'enum': [ 'critical', 'error', 'warning', 'info', 'verbose', 'debug', 'trace' ], }, }, 'required': ['tasks'], } params_return_schema = {'type': 'array', 'items': {'type': 'object'}} tasks_list_schema = api.schema_model('tasks.list', ObjectsContainer.tasks_list_object) task_input_schema = api.schema_model('tasks.task', ObjectsContainer.task_input_object) 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'
'properties': { 'name': {'type': 'string'}, 'api_ver': {'type': 'integer'}, 'builtin': {'type': 'boolean'}, 'category': {'type': ['string', 'null']}, 'contexts': {'type': 'array', 'items': {'type': 'string'}}, 'debug': {'type': 'boolean'}, 'interfaces': {'type': 'array', 'items': {'type': 'string'}}, '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(
'network', 'country', 'status', 'timezone', 'number_of_aired_episodes', ] movie_return_object = copy.deepcopy(base_return_object) movie_return_object['properties']['tagline'] = {'type': 'string'} movie_return_object['properties']['released'] = {'type': 'string'} movie_return_object['properties']['trailer'] = {'type': ['string', 'null']} movie_return_object['required'] += ['tagline', 'released', 'trailer'] series_return_schema = api.schema_model( 'series_return_schema', ObjectsContainer.series_return_object ) movie_return_schema = api.schema_model('movie_return_schema', ObjectsContainer.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(
'details': {'type': 'string'}, 'filename': {'type': 'string'}, 'id': {'type': 'integer'}, 'task': {'type': 'string'}, 'time': {'type': 'string', 'format': 'date-time'}, 'title': {'type': 'string'}, 'url': {'type': 'string'}, }, 'required': ['details', 'filename', 'id', 'task', 'time', 'title', 'url'], 'additionalProperties': False, } history_list_object = {'type': 'array', 'items': base_history_object} history_list_schema = api.schema_model('history.list', ObjectsContainer.history_list_object) sort_choices = ('id', 'task', 'filename', 'url', 'title', 'time', 'details') # Create pagination parser history_parser = api.pagination_parser(sort_choices=sort_choices, default='time') history_parser.add_argument('task', help='Filter by task name') @history_api.route('/') @api.doc(parser=history_parser) class HistoryAPI(APIResource): @etag @api.response(NotFoundError) @api.response(200, model=history_list_schema) def get(self, session=None):
'alternate_names': {'type': 'array', 'items': {'type': 'string'}} }, 'anyOf': [ {'required': ['begin_episode']}, {'required': ['alternate_names']} ], 'additionalProperties:': False } series_input_object = copy.deepcopy(series_edit_object) series_input_object['properties']['name'] = {'type': 'string'} 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')
}, 'uniqueItems': True, 'minItems': 1 } batch_remove_object = { 'type': 'object', 'properties': { 'ids': batch_ids }, 'required': ['ids'], 'additionalProperties': False, } entry_list_object_schema = api.schema_model( 'entry_list_object_schema', ObjectsContainer.entry_list_base_object) entry_list_input_object_schema = api.schema_model( 'entry_list_input_object_schema', ObjectsContainer.entry_list_input_object) entry_list_return_lists_schema = api.schema_model( 'entry_list_return_lists_schema', ObjectsContainer.entry_list_return_lists) entry_list_batch_remove_schema = api.schema_model( 'entry_list.batch_remove_object', ObjectsContainer.batch_remove_object) entry_list_parser = api.parser() entry_list_parser.add_argument('name', help='Filter results by list name') @entry_list_api.route('/') class EntryListListsAPI(APIResource): @etag @api.doc(parser=entry_list_parser)
'rejected_by': { 'type': 'string' }, }, 'required': ['id', 'title', 'url', 'added', 'reason', 'expires', 'rejected_by'], 'additionalProperties': False, } rejected_entries_list_object = { 'type': 'array', 'items': rejected_entry_object } rejected_entry_schema = api.schema_model( 'rejected_failed_entry_schema', ObjectsContainer.rejected_entry_object) rejected_entries_list_schema = api.schema_model( 'rejected_entries_list_schema', ObjectsContainer.rejected_entries_list_object) sort_choices = ('added', 'id', 'title', 'url', 'expires', 'rejected_by', 'reason') rejected_parser = api.pagination_parser(sort_choices=sort_choices) @rejected_api.route('/') class Rejected(APIResource): @etag @api.response(NotFoundError) @api.response(200, model=rejected_entries_list_schema) @api.doc(parser=rejected_parser)
'airdate': {'type': 'string', 'format': 'date-time'}, 'url': {'type': 'string'}, 'original_image': {'type': ['string', 'null']}, 'medium_image': {'type': ['string', 'null']}, 'airstamp': {'type': 'string', 'format': 'date-time'}, 'runtime': {'type': 'integer'}, 'summary': {'type': 'string'}, 'last_update': {'type': 'string', 'format': 'date-time'} }, 'required': ['tvmaze_id', 'series_id', 'number', 'season_number', 'title', 'airdate', 'url', 'original_image', 'medium_image', 'airstamp', 'runtime', 'summary', 'last_update'], 'additionalProperties': False } tvmaze_series_schema = api.schema_model('tvmaze_series_schema', ObjectsContainer.tvmaze_series_object) tvmaze_episode_schema = api.schema_model('tvmaze_episode_schema', ObjectsContainer.tvmaze_episode_object) @tvmaze_api.route('/series/<string:title>/') @api.doc(params={'title': 'TV Show name or TVMaze ID'}) class TVDBSeriesSearchApi(APIResource): @etag @api.response(200, 'Successfully found show', model=tvmaze_series_schema) @api.response(NotFoundError) def get(self, title, session=None): """TVMaze series lookup""" try: tvmaze_id = int(title) except ValueError: tvmaze_id = None
'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)
from flask import Response, jsonify, request from jsonschema import RefResolutionError from sqlalchemy.orm import Session from flexget.api import APIResource, api from flexget.api.app import NotFoundError from flexget.config_schema import resolve_ref, schema_paths schema_api = api.namespace('schema', description='Config and plugin schemas') schema_api_list = api.schema_model( 'schema.list', {'type': 'object', 'properties': {'schemas': {'type': 'array', 'items': {'type': 'object'}}}}, ) def rewrite_ref(identifier: str, base_url: str) -> str: """ The refs in the schemas are arbitrary identifiers, and cannot be used as-is as real network locations. This rewrites any of those arbitrary refs to be real urls servable by this endpoint. """ if not base_url.endswith('/'): base_url += '/' if identifier.startswith('/schema/'): return base_url + identifier[1:] return identifier def rewrite_refs(schema, base_url: str): """Make sure any $refs in the schema point properly back to this endpoint.""" if isinstance(schema, dict):
series_return_object['properties']['network'] = {'type': ['string', 'null']} series_return_object['properties']['country'] = {'type': ['string', 'null']} series_return_object['properties']['status'] = {'type': 'string'} series_return_object['properties']['timezone'] = {'type': ['string', 'null']} series_return_object['properties']['number_of_aired_episodes'] = {'type': ['integer', 'null']} series_return_object['required'] += ['tvdb_id', 'tvrage_id', 'first_aired', 'air_day', 'air_time', 'certification', 'network', 'country', 'status', 'timezone', 'number_of_aired_episodes'] movie_return_object = copy.deepcopy(base_return_object) movie_return_object['properties']['tagline'] = {'type': 'string'} movie_return_object['properties']['released'] = {'type': 'string'} movie_return_object['properties']['trailer'] = {'type': ['string', 'null']} movie_return_object['required'] += ['tagline', 'released', 'trailer'] series_return_schema = api.schema_model('series_return_schema', ObjectsContainer.series_return_object) movie_return_schema = api.schema_model('movie_return_schema', ObjectsContainer.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>/')
'items': inject_input, 'description': 'A List of entry objects', }, 'loglevel': { 'type': 'string', 'description': 'Specify log level', 'enum': ['critical', 'error', 'warning', 'info', 'verbose', 'debug', 'trace'], }, }, 'required': ['tasks'], } params_return_schema = {'type': 'array', 'items': {'type': 'object'}} tasks_list_schema = api.schema_model('tasks.list', ObjectsContainer.tasks_list_object) task_input_schema = api.schema_model('tasks.task', ObjectsContainer.task_input_object) 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'
}, }, } list_input = copy.deepcopy(list_object) del list_input['properties']['id'] del list_input['properties']['added_on'] return_movies = {'type': 'array', 'items': movie_list_object} return_lists = {'type': 'array', 'items': list_object} return_identifiers = {'type': 'array', 'items': {'type': 'string'}} input_movie_entry_schema = api.schema_model('input_movie_entry', ObjectsContainer.input_movie_entry) input_movie_list_id_schema = api.schema_model( 'input_movie_list_id_object', ObjectsContainer.input_movie_list_id_object) movie_list_id_object_schema = api.schema_model( 'movie_list_id_object', ObjectsContainer.return_movie_list_id_object) movie_list_object_schema = api.schema_model('movie_list_object', ObjectsContainer.movie_list_object) list_object_schema = api.schema_model('list_object', ObjectsContainer.list_object) return_lists_schema = api.schema_model('return_lists', ObjectsContainer.return_lists) return_movies_schema = api.schema_model('return_movies', ObjectsContainer.return_movies) new_list_schema = api.schema_model('new_list', ObjectsContainer.list_input)
'title': { 'type': 'string' }, 'url': { 'type': 'string' }, }, 'required': ['details', 'filename', 'id', 'task', 'time', 'title', 'url'], 'additionalProperties': False, } history_list_object = {'type': 'array', 'items': base_history_object} history_list_schema = api.schema_model('history.list', ObjectsContainer.history_list_object) sort_choices = ('id', 'task', 'filename', 'url', 'title', 'time', 'details') # Create pagination parser history_parser = api.pagination_parser(sort_choices=sort_choices, default='time') history_parser.add_argument('task', help='Filter by task name') @history_api.route('/') @api.doc(parser=history_parser) class HistoryAPI(APIResource): @etag @api.response(NotFoundError) @api.response(200, model=history_list_schema)
'approved': {'type': 'boolean'}, 'added': {'type': 'string', 'format': 'date-time'}, }, } pending_entry_list = {'type': 'array', 'items': pending_entry_object} 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')
}, 'year': { 'type': 'number' }, 'thumbnail': { 'type': 'string' }, }, 'required': ['imdb_id', 'match', 'name', 'url', 'year'], 'additionalProperties': False, } return_object = {'type': 'array', 'items': movie_object} return_schema = api.schema_model('imdb_search_schema', ObjectsContainer.return_object) @imdb_api.route('/search/<string:title>/') @api.doc(params={'title': 'Movie name or IMDB ID'}) class IMDBMovieSearch(APIResource): # noinspection PyUnusedLocal @etag @api.response(200, model=return_schema) def get(self, title, session=None): """ Get a list of IMDB search result by name or ID""" raw_movies = ImdbSearch().smart_match(title, single_match=False) if not raw_movies: return jsonify([]) # Convert single movie to list to preserve consistent reply if not isinstance(raw_movies, list):
'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_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',
'port': {'type': 'integer'}, 'server': {'type': 'string'} } } connection = { 'type': 'object', 'patternProperties': { '\w': connection_object } } return_response = {'type': 'array', 'items': connection} return_schema = api.schema_model('irc.connections', ObjectsContainer.return_response) @irc_api.route('/connections/') @api.doc(parser=irc_parser) class IRCStatus(APIResource): @api.response(200, model=return_schema) @api.response(NotFoundError) @api.response(BadRequest) def get(self, session=None): """Returns status of IRC connections""" from flexget.plugins.daemon.irc import irc_manager if irc_manager is None: raise BadRequest('IRC daemon does not appear to be running') args = irc_parser.parse_args()
'title', 'airdate', 'url', 'original_image', 'medium_image', 'airstamp', 'runtime', 'summary', 'last_update', ], 'additionalProperties': False, } tvmaze_series_schema = api.schema_model('tvmaze_series_schema', ObjectsContainer.tvmaze_series_object) tvmaze_episode_schema = api.schema_model( 'tvmaze_episode_schema', ObjectsContainer.tvmaze_episode_object) @tvmaze_api.route('/series/<string:title>/') @api.doc(params={'title': 'TV Show name or TVMaze ID'}) class TVDBSeriesSearchApi(APIResource): @etag(cache_age=3600) @api.response(200, 'Successfully found show', model=tvmaze_series_schema) @api.response(NotFoundError) def get(self, title, session=None): """TVMaze series lookup""" try: tvmaze_id = int(title) except ValueError:
'properties': { 'name': { 'type': 'string' }, 'content': { 'type': 'array', 'items': { 'type': 'string' } }, }, }, } yaml_error_schema = api.schema_model('yaml_error_schema', ObjectsContainer.yaml_error_response) config_validation_schema = api.schema_model( 'config_validation_schema', ObjectsContainer.config_validation_error) pid_schema = api.schema_model('server.pid', ObjectsContainer.pid_object) raw_config_schema = api.schema_model('raw_config', ObjectsContainer.raw_config_object) version_schema = api.schema_model('server.version', ObjectsContainer.version_object) dump_threads_schema = api.schema_model('server.dump_threads', ObjectsContainer.dump_threads_object) server_manage_schema = api.schema_model('server.manage', ObjectsContainer.server_manage) crash_logs_schema = api.schema_model('server.crash_logs', ObjectsContainer.crash_logs)
'properties': { 'id': {'type': 'integer'}, 'title': {'type': 'string'}, 'url': {'type': 'string'}, 'added_at': {'type': 'string', 'format': 'date-time'}, 'reason': {'type': 'string'}, 'count': {'type': 'integer'}, 'retry_time': {'type': ['string', 'null'], 'format': 'date-time'} }, 'required': ['id', 'title', 'url', 'added_at', 'reason', 'count', 'retry_time'], 'additionalProperties': False } retry_entries_list_object = {'type': 'array', 'items': retry_failed_entry_object} retry_failed_entry_schema = api.schema_model('retry_failed_entry_schema', ObjectsContainer.retry_failed_entry_object) retry_entries_list_schema = api.schema_model('retry_entries_list_schema', ObjectsContainer.retry_entries_list_object) sort_choices = ('failure_time', 'id', 'title', 'url', 'reason', 'count', 'retry_time') failed_parser = api.pagination_parser(sort_choices=sort_choices) @retry_failed_api.route('/') class RetryFailed(APIResource): @etag @api.response(NotFoundError) @api.response(200, model=retry_entries_list_schema) @api.doc(parser=failed_parser) def get(self, session=None): """ List all failed entries """ args = failed_parser.parse_args()
'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_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' )
class ObjectsContainer(object): plugin_list = {'type': 'array', 'items': {'type': 'string'}} database_input_object = { 'type': 'object', 'properties': { 'operation': {'type': 'string', 'enum': ['cleanup', 'vacuum', 'plugin_reset']}, 'plugin_name': {'type': 'string'}, }, 'required': ['operation'], 'additionalProperties': False, } plugins_schema = api.schema_model('plugins_list', ObjectsContainer.plugin_list) input_schema = api.schema_model('db_schema', ObjectsContainer.database_input_object) @db_api.route('/') class DBOperation(APIResource): @api.validate(input_schema) @api.response(200, model=base_message_schema) def post(self, session=None): """Perform DB operations""" data = request.json operation = data['operation'] if operation == 'cleanup': self.manager.db_cleanup(force=True) msg = 'DB Cleanup finished' elif operation == 'vacuum':
from flask import jsonify from flexget.db_schema import reset_schema, plugin_schemas from flexget.api import api, APIResource from flexget.api.app import base_message_schema, success_response, BadRequest, etag log = logging.getLogger('database') db_api = api.namespace('database', description='Manage Flexget DB') class ObjectsContainer(object): plugin_list = {'type': 'array', 'items': {'type': 'string'}} plugins_schema = api.schema_model('plugins_list', ObjectsContainer.plugin_list) @db_api.route('/cleanup/') class DBCleanup(APIResource): @etag @api.response(200, model=base_message_schema) def get(self, session=None): """ Make all plugins clean un-needed data from the database """ self.manager.db_cleanup(force=True) return success_response('DB Cleanup finished') @db_api.route('/vacuum/') class DBVacuum(APIResource): @etag