Example #1
0
from __future__ import unicode_literals, division, absolute_import
from flask import render_template, Blueprint
from flexget.ui.webui import register_plugin

home = Blueprint('home', __name__)


@home.route('/')
def index():
    return render_template('home/home.html')


register_plugin(home, menu='Home', order=0, home=True)
Example #2
0

@schedule.route('/delete/<task>')
def delete_schedule(task):
    db_session.query(Schedule).filter(Schedule.task == task).delete()
    db_session.commit()
    stop_empty_timers()
    return redirect(url_for('.index'))


@schedule.route('/add/<task>')
def add_schedule(task):
    schedule = db_session.query(Schedule).filter(Schedule.task == task).first()
    if not schedule:
        schedule = Schedule(task, DEFAULT_INTERVAL)
        db_session.add(schedule)
        db_session.commit()
    start_timer(DEFAULT_INTERVAL)
    return redirect(url_for('.index'))


def get_all_tasks():
    return [task for task in manager.config.get('tasks', {}).keys() if not task.startswith('_')]


def get_scheduled_tasks():
    return [item.task for item in db_session.query(Schedule).all()]


register_plugin(schedule, menu='Schedule')
Example #3
0
            item = func(item)
            if set is not None:
                obj[item] = set
            return obj[item]
        except (TypeError, LookupError, ValueError):
            pass
    raise LookupError('%s not in config' % item)


@config.route('/<path:path>', methods=['GET', 'POST'])
def with_path(path):
    path = path.split('/')
    result = manager.config
    try:
        for elem in path[:-1]:
            result = getset_item(result, elem)
        elem = path[-1]
        if request.method == 'POST':
            getset_item(result, elem, set=json.loads(request.data))
        result = jsonify(getset_item(result, elem))
    except LookupError as e:
        return unicode(e), 404
    # TODO: This should not be hard coded
    if len(path) == 2 and path[0] in ['tasks', 'presets']:
        result.headers[
            b'Content-Type'] += '; profile=/schema/plugins?context=task'
    return result


register_plugin(config)
Example #4
0
    db_session.commit()
    return redirect('/series')


@outputs_module.route('/forget/<int:rel_id>', methods=['POST', 'GET'])
def forget_episode(rel_id):
    """
    Executes a --series-forget statement for an episode.
    Redirects back to the series index.
    """
    release = db_session.query(Release).get(rel_id)

    context = {'release': release, 'command': 'series forget "%s" %s' % (
        release.episode.series.name, release.episode.identifier)}

    if request.method == 'POST':
        if request.form.get('really', False):
            try:
                forget_series_episode(release.episode.series.name, release.episode.identifier)
                flash('Forgot %s %s.' % (
                    release.episode.series.name, release.episode.identifier), 'delete')
            except ValueError as e:
                flash(e.message, 'error')

        return redirect(url_for('.index'))

    return render_template('series/forget.html', **context)


register_plugin(outputs_module, menu='Outputs')
Example #5
0
import logging
from sqlalchemy import desc
from flexget.ui.webui import register_plugin, db_session
from flask import render_template, Module
from flexget.plugin import DependencyError

try:
    from flexget.plugins.output.history import History
except ImportError:
    raise DependencyError(issued_by='ui.history', missing='history')

log = logging.getLogger('ui.history')
history = Module(__name__)


@history.route('/')
def index():
    context = {
        'items':
        db_session.query(History).order_by(desc(History.time)).limit(50).all()
    }
    return render_template('history/history.html', **context)


register_plugin(history, menu='History')
Example #6
0
    global timers
    if timers.get(interval):
        timers[interval].cancel()
        del timers[interval]


def stop_empty_timers():
    """Stops timers that don't have any more feeds using them."""
    current_intervals = set([i.interval for i in db_session.query(Schedule).all()])
    for interval in timers.keys():
        if interval not in current_intervals:
            stop_timer(interval)


@event("webui.start")
def on_webui_start():
    # Start timers for all schedules
    for interval in set([item.interval for item in db_session.query(Schedule).all()]):
        start_timer(interval)


@event("webui.stop")
def on_webui_stop():
    log.info("Terminating")
    # Stop all running timers
    for interval in timers.keys():
        stop_timer(interval)


register_plugin(schedule, menu="Schedule")
Example #7
0
    return render_template('inject/inject.html')


@inject.route('/do', methods=['POST', 'GET'])
def do_inject():
    fields = {}
    # Requests is a special dict, and cannot be passed as keyword arguments, make it into a normal dict.
    for key, value in request.values.iteritems():
        # Translate on and off to True and False
        if value == 'on':
            fields[key] = True
        elif value == 'off':
            fields[key] = False
        else:
            fields[key] = value
    # If we only got a url, make a title from the url filename
    fields['title'] = fields.get('title') or posixpath.basename(urlparse.urlsplit(fields.get('url', '')).path)

    if fields.get('title') and fields.get('url'):
        # Create the entry for injection
        entry = Entry(**fields)
        executor.execute(options={'dump_entries': True}, entries=[entry])
        flash('Scheduled execution for entry `%s`' % entry['title'], 'success')
    else:
        flash('Title and URL required for inject.', 'error')

    return redirect(url_for('index'))


register_plugin(inject)
Example #8
0
        query = query.filter(LogEntry.execution == execution)
    count = query.count()
    # Use a trick to do ceiling division
    total_pages = 0 - ((0 - count) / limit)
    if page > total_pages:
        page = total_pages
    start = limit * page - limit
    json = {'total': total_pages, 'page': page, 'records': count, 'rows': []}
    result = query.order_by(sord(sidx))[start:start + limit]
    for entry in result:
        json['rows'].append({
            'id': entry.id,
            'created': entry.created.strftime('%Y-%m-%d %H:%M'),
            'levelno': logging.getLevelName(entry.levelno),
            'logger': entry.logger,
            'task': entry.task,
            'message': entry.message
        })
    return jsonify(json)


@event('webui.start')
def initialize():
    # Register db handler with base logger
    logger = logging.getLogger()
    handler = DBLogHandler()
    logger.addHandler(handler)


register_plugin(log_viewer, menu='Log', order=256)
Example #9
0
        elif len(text) < 5:
            flash('Search text is too short, use at least 5 characters', 'error')
        else:
            results = search(db_session, text)
            if not results:
                flash('No results', 'info')
            else:
                # not sure if this len check is a good idea, I think it forces to load all items from db ?
                if len(results) > 500:
                    flash('Too many results, displaying first 500', 'error')
                    results = results[0:500]
                context['results'] = results
    return render_template('archive/archive.html', **context)


@archive.route('/count')
def count():
    log.debug('getting count for archive')
    return str(db_session.query(ArchiveEntry).count())


@archive.route('/inject/<id>')
def inject(id):
    options = {'archive_inject_id': id, 'archive_inject_immortal': True}
    executor.execute(options=options)
    flash('Queued execution, see log for results', 'info')
    return render_template('archive/archive.html')


register_plugin(archive, menu='Archive')
Example #10
0
        query = query.filter(LogEntry.execution == execution)
    count = query.count()
    # Use a trick to do ceiling division
    total_pages = 0 - ((0 - count) / limit)
    if page > total_pages:
        page = total_pages
    start = limit * page - limit
    json = {'total': total_pages, 'page': page, 'records': count, 'rows': []}
    result = query.order_by(sord(sidx))[start:start + limit]
    for entry in result:
        json['rows'].append({
            'id': entry.id,
            'created': entry.created.strftime('%Y-%m-%d %H:%M'),
            'levelno': logging.getLevelName(entry.levelno),
            'logger': entry.logger,
            'task': entry.task,
            'message': entry.message
        })
    return jsonify(json)


@event('webui.start')
def initialize():
    # Register db handler with base logger
    logger = logging.getLogger()
    handler = DBLogHandler()
    logger.addHandler(handler)


register_plugin(log_viewer, url_prefix='/log', menu='Log', order=256)
Example #11
0
        try:
            item = func(item)
            if set is not None:
                obj[item] = set
            return obj[item]
        except (TypeError, LookupError, ValueError):
            pass
    raise LookupError("%s not in config" % item)


@config.route("/<path:path>", methods=["GET", "POST"])
def with_path(path):
    path = path.split("/")
    result = manager.config
    try:
        for elem in path[:-1]:
            result = getset_item(result, elem)
        elem = path[-1]
        if request.method == "POST":
            getset_item(result, elem, set=json.loads(request.data))
        result = jsonify(getset_item(result, elem))
    except LookupError as e:
        return unicode(e), 404
    # TODO: This should not be hard coded
    if len(path) == 2 and path[0] in ["tasks", "presets"]:
        result.headers[b"Content-Type"] += "; profile=/schema/plugins?context=task"
    return result


register_plugin(config)
Example #12
0
        query = query.filter(LogEntry.execution == execution)
    count = query.count()
    # Use a trick to do ceiling division
    total_pages = 0 - ((0 - count) / limit)
    if page > total_pages:
        page = total_pages
    start = limit * page - limit
    json = {'total': total_pages,
            'page': page,
            'records': count,
            'rows': []}
    result = query.order_by(sord(sidx))[start:start + limit]
    for entry in result:
        json['rows'].append({'id': entry.id,
                             'created': entry.created.strftime('%Y-%m-%d %H:%M'),
                             'levelno': logging.getLevelName(entry.levelno),
                             'logger': entry.logger,
                             'task': entry.task,
                             'message': entry.message})
    return jsonify(json)


@event('webui.start')
def initialize():
    # Register db handler with base logger
    logger = logging.getLogger()
    handler = DBLogHandler()
    logger.addHandler(handler)

register_plugin(log_viewer, menu='Log', order=256)
Example #13
0
from flexget.ui.webui import register_plugin, manager
from flexget.plugin import plugins
from flask import render_template, Module

plugins_module = Module(__name__, url_prefix='/plugins')


@plugins_module.route('/')
def index():
    context = {'plugins': plugins}
    return render_template('plugins/plugins.html', **context)


if manager.options.debug:
    register_plugin(plugins_module, menu='Plugins (DEV)')
Example #14
0
from __future__ import unicode_literals, division, absolute_import
from flask import render_template, Blueprint
from flexget.ui.webui import register_plugin

home = Blueprint("home", __name__)


@home.route("/")
def index():
    return render_template("home/home.html")


register_plugin(home, menu="Home", order=0, home=True)
Example #15
0
def edit(root, name):
    context = {'name': name}
    context['config'] = manager.config[root][name]
    return render_template('configure/edit.html', **context)


@app.template_filter('other_type')
def other_type(root):
    if root == 'tasks':
        return 'presets'
    return 'tasks'


def get_related(root, name):
    """Returns a list of related tasks/presets for a given preset/task"""
    if root == 'tasks':
        presets = manager.config[root][name].get('preset', [])
        if isinstance(presets, basestring):
            presets = [presets]
        return presets
    elif root == 'presets':
        tasks = []
        for task, config in manager.config['tasks'].iteritems():
            if config.get('preset'):
                if name == config['preset'] or name in config['preset']:
                    tasks.append(task)
        return tasks


register_plugin(configure, menu='Configure', order=10)
Example #16
0
@event('webui.start')
def enable_authentication():
    if manager.options.webui.no_auth:
        return
    global credentials
    credentials = db_session.query(AuthCredentials).first()
    if not credentials:
        credentials = AuthCredentials('flexget', 'flexget')
        db_session.add(credentials)

    if manager.options.webui.username:
        credentials.username = manager.options.username
    if manager.options.webui.password:
        credentials.password = manager.options.webui.password
    db_session.commit()

    app.before_request(check_authenticated)


def check_authenticated():
    # TODO: Is this a big security hole? Maybe figure out a better way to authenticate for local IPC
    if manager.options.webui.no_local_auth and request.remote_addr == '127.0.0.1':
        return
    auth = request.authorization
    if not auth or not check_auth(auth.username, auth.password):
        return authenticate()


register_plugin(auth)
Example #17
0
    Redirects back to the series index.
    """
    release = db_session.query(Release).get(rel_id)

    context = {
        'release':
        release,
        'command':
        'series forget "%s" %s' %
        (release.episode.series.name, release.episode.identifier)
    }

    if request.method == 'POST':
        if request.form.get('really', False):
            try:
                forget_series_episode(release.episode.series.name,
                                      release.episode.identifier)
                flash(
                    'Forgot %s %s.' %
                    (release.episode.series.name, release.episode.identifier),
                    'delete')
            except ValueError as e:
                flash(e.message, 'error')

        return redirect(url_for('.index'))

    return render_template('series/forget.html', **context)


register_plugin(outputs_module, menu='Outputs')
Example #18
0
        query = query.filter(LogEntry.execution == execution)
    count = query.count()
    # Use a trick to do ceiling division
    total_pages = 0 - ((0 - count) / limit)
    if page > total_pages:
        page = total_pages
    start = limit * page - limit
    json = {'total': total_pages,
            'page': page,
            'records': count,
            'rows': []}
    result = query.order_by(sord(sidx))[start:start + limit]
    for entry in result:
        json['rows'].append({'id': entry.id,
                             'created': entry.created.strftime('%Y-%m-%d %H:%M'),
                             'levelno': logging.getLevelName(entry.levelno),
                             'logger': entry.logger,
                             'task': entry.task,
                             'message': entry.message})
    return jsonify(json)


@event('webui.start')
def initialize():
    # Register db handler with base logger
    logger = logging.getLogger()
    handler = DBLogHandler()
    logger.addHandler(handler)

register_plugin(log_viewer, url_prefix='/log', menu='Log', order=256)
Example #19
0
    db_session.commit()
    return redirect('/series')


@series_module.route('/forget/<int:rel_id>', methods=['POST', 'GET'])
def forget_episode(rel_id):
    '''
    Executes a --series-forget statement for an episode.
    Redirects back to the series index.
    '''
    release = db_session.query(Release).get(rel_id)

    context = {'release': release, 'command': '--series-forget "%s" %s' % (
        release.episode.series.name, release.episode.identifier)}

    if request.method == 'POST':
        if request.form.get('really', False):
            try:
                forget_series_episode(release.episode.series.name, release.episode.identifier)
                flash('Forgot %s %s.' % (
                    release.episode.series.name, release.episode.identifier), 'delete')
            except ValueError, e:
                flash(e.message, 'error')

        return redirect(url_for('index'))

    return render_template('series/forget.html', **context)


register_plugin(series_module, menu='Series')
Example #20
0
from __future__ import unicode_literals, division, absolute_import

from flask import Module, jsonify, request
from jsonschema import RefResolutionError

from flexget.config_schema import resolve_ref
from flexget.ui.webui import register_plugin

schema = Module(__name__)


@schema.route('/', defaults={'path': ''})
@schema.route('/<path:path>')
def get_schema(path):
    refpath = '/schema/' + path
    if request.query_string:
        refpath += '?' + request.query_string
    try:
        return jsonify(resolve_ref(refpath))
    except RefResolutionError:
        return 'Schema not found', 404


register_plugin(schema)
Example #21
0
    'You have to login with proper credentials', 401,
    {'WWW-Authenticate': 'Basic realm="Login Required"'})


@event('webui.start')
def enable_authentication():
    if manager.options.no_auth:
        return
    global credentials
    credentials = db_session.query(AuthCredentials).first()
    if not credentials:
        credentials = AuthCredentials('flexget', 'flexget')
        db_session.add(credentials)

    if manager.options.username:
        credentials.username = manager.options.username
    if manager.options.password:
        credentials.password = manager.options.password
    db_session.commit()

    app.before_request(check_authenticated)


def check_authenticated():
    auth = request.authorization
    if not auth or not check_auth(auth.username, auth.password):
        return authenticate()


register_plugin(auth)
Example #22
0
from __future__ import unicode_literals, division, absolute_import
import logging
from sqlalchemy import desc
from flexget.ui.webui import register_plugin, db_session
from flask import render_template, Module
from flexget.plugin import DependencyError

try:
    from flexget.plugins.output.history import History
except ImportError:
    raise DependencyError(issued_by='ui.history', missing='history')

log = logging.getLogger('ui.history')
history = Module(__name__)


@history.route('/')
def index():
    context = {'items': db_session.query(History).order_by(desc(History.time)).limit(50).all()}
    return render_template('history/history.html', **context)

register_plugin(history, menu='History')
Example #23
0
@plugins_module.route('/context/<context>')
def plugins_by_context(context):
    return jsonify(plugins=plugin_infos(get_plugins(context=context)))


@plugins_module.route('/categories')
def categories():
    # TODO: Should this only return the list of categories that actually have plugins?
    return jsonify(categories=task_phases)


@plugins_module.route('/category/<category>')
def plugins_by_category(category):
    return jsonify(plugins=plugin_infos(get_plugins(category=category)))


@plugins_module.route('/schema/<name>')
def plugin_schema(name):
    try:
        plugin = get_plugin_by_name(name).instance
    except DependencyError:
        return 'Plugin %s does not exist' % name, 404
    try:
        validator = plugin.validator()
    except AttributeError:
        return 'Plugin %s does not have a schema' % name, 404
    return jsonify(validator.schema())


register_plugin(plugins_module)
Example #24
0
from __future__ import unicode_literals, division, absolute_import
from flexget.ui.webui import register_plugin, stop_server
from flask import render_template, Module

import logging

shutdown = Module(__name__, url_prefix='/shutdown')

log = logging.getLogger('shutdown')


@shutdown.route('/')
def index():
    return render_template('shutdown/shutdown.html')


@shutdown.route('/now')
def now():
    stop_server()
    return 'Shutdown Complete'


register_plugin(shutdown, menu='Shutdown', order=512)
Example #25
0
@plugins_module.route('/context/<context>')
def plugins_by_context(context):
    return jsonify(plugins=plugin_infos(get_plugins(context=context)))


@plugins_module.route('/categories')
def categories():
    # TODO: Should this only return the list of categories that actually have plugins?
    return jsonify(categories=task_phases)


@plugins_module.route('/category/<category>')
def plugins_by_category(category):
    return jsonify(plugins=plugin_infos(get_plugins(category=category)))


@plugins_module.route('/schema/<name>')
def plugin_schema(name):
    try:
        plugin = get_plugin_by_name(name).instance
    except DependencyError:
        return 'Plugin %s does not exist' % name, 404
    try:
        validator = plugin.validator()
    except AttributeError:
        return 'Plugin %s does not have a schema' % name, 404
    return jsonify(validator.schema())


register_plugin(plugins_module)
Example #26
0
    # Use a trick to do ceiling division
    total_pages = 0 - ((0 - count) / limit)
    if page > total_pages:
        page = total_pages
    start = limit * page - limit
    json = {"total": total_pages, "page": page, "records": count, "rows": []}
    result = query.order_by(sord(sidx))[start : start + limit]
    for entry in result:
        json["rows"].append(
            {
                "id": entry.id,
                "created": entry.created.strftime("%Y-%m-%d %H:%M"),
                "levelno": logging.getLevelName(entry.levelno),
                "logger": entry.logger,
                "feed": entry.feed,
                "message": entry.message,
            }
        )
    return jsonify(json)


@event("webui.start")
def initialize():
    # Register db handler with base logger
    logger = logging.getLogger()
    handler = DBLogHandler()
    logger.addHandler(handler)


register_plugin(log_viewer, url_prefix="/log", menu="Log", order=256)
Example #27
0
def cover(imdb_id):
    import os

    # TODO: return '' should be replaced with something sane, http error 404 ?

    tmdb_lookup = get_plugin_by_name('api_tmdb').instance.lookup
    try:
        movie = tmdb_lookup(imdb_id=imdb_id)
    except LookupError:
        log.error('No cached data for %s' % imdb_id)
        return ''

    filepath = None
    for poster in movie.posters:
        if poster.size == 'thumb':
            filepath = os.path.join(manager.config_base, 'userstatic', *poster.get_file())
            break

    if filepath is None:
        log.error('No cover for %s' % imdb_id)
        return ''
    elif not os.path.exists(filepath):
        log.error('File %s does not exist' % filepath)
        return ''

    log.debug('sending thumb file %s' % filepath)
    return send_file(filepath, mimetype='image/png')


register_plugin(movies_module, menu='Movies')
Example #28
0
from __future__ import unicode_literals, division, absolute_import
from flask import render_template, Module
from flexget.ui.webui import register_plugin

home = Module(__name__, url_prefix='/home')


@home.route('/')
def index():
    return render_template('home/home.html')

register_plugin(home, menu='Home', order=0, home=True)
Example #29
0
            context['options'] = request.form['options']
        else:
            manager.execute(options=options.execute, output=bufferqueue)
            context['execute_progress'] = True
            context['progress'] = progress(as_list=True)

    return render_template('execute/execute.html', **context)


@execute.route('/progress.json')
def progress(as_list=False):
    """
    Gets messages from the queue and exports them to JSON.
    """
    result = {'items': []}
    try:
        while True:
            item = bufferqueue.get_nowait()
            result['items'].append(item)
            bufferqueue.task_done()
    except Empty:
        pass

    if as_list:
        return result['items']

    return jsonify(result)


register_plugin(execute, menu='Execute')
Example #30
0
    global timers
    if timers.get(interval):
        timers[interval].cancel()
        del timers[interval]


def stop_empty_timers():
    """Stops timers that don't have any more tasks using them."""
    current_intervals = set([i.interval for i in db_session.query(Schedule).all()])
    for interval in timers.keys():
        if interval not in current_intervals:
            stop_timer(interval)


@event('webui.start')
def on_webui_start():
    # Start timers for all schedules
    for interval in set([item.interval for item in db_session.query(Schedule).all()]):
        start_timer(interval)


@event('webui.stop')
def on_webui_stop():
    log.info('Terminating')
    # Stop all running timers
    for interval in timers.keys():
        stop_timer(interval)


register_plugin(schedule, menu='Schedule')
Example #31
0
@configure.route('/jsonary')
def jsonary():
    return render_template('configure/edit_jsonary.html')


@app.template_filter('other_type')
def other_type(root):
    if root == 'tasks':
        return 'presets'
    return 'tasks'


def get_related(root, name):
    """Returns a list of related tasks/presets for a given preset/task"""
    if root == 'tasks':
        presets = manager.config[root][name].get('preset', [])
        if isinstance(presets, basestring):
            presets = [presets]
        return presets
    elif root == 'presets':
        tasks = []
        for task, config in manager.config['tasks'].iteritems():
            if config.get('preset'):
                if name == config['preset'] or name in config['preset']:
                    tasks.append(task)
        return tasks


register_plugin(configure, menu='Configure', order=10)
Example #32
0
    Redirects back to the series index.
    '''
    release = db_session.query(Release).get(rel_id)

    context = {
        'release':
        release,
        'command':
        '--series-forget "%s" %s' %
        (release.episode.series.name, release.episode.identifier)
    }

    if request.method == 'POST':
        if request.form.get('really', False):
            try:
                forget_series_episode(release.episode.series.name,
                                      release.episode.identifier)
                flash(
                    'Forgot %s %s.' %
                    (release.episode.series.name, release.episode.identifier),
                    'delete')
            except ValueError as e:
                flash(e.message, 'error')

        return redirect(url_for('index'))

    return render_template('series/forget.html', **context)


register_plugin(series_module, menu='Series')
Example #33
0
        else:
            manager.scheduler.execute(options=options.execute,
                                      output=bufferqueue)
            context['execute_progress'] = True
            context['progress'] = progress(as_list=True)

    return render_template('execute/execute.html', **context)


@execute.route('/progress.json')
def progress(as_list=False):
    """
    Gets messages from the queue and exports them to JSON.
    """
    result = {'items': []}
    try:
        while True:
            item = bufferqueue.get_nowait()
            result['items'].append(item)
            bufferqueue.task_done()
    except Empty:
        pass

    if as_list:
        return result['items']

    return jsonify(result)


register_plugin(execute, menu='Execute')
Example #34
0
    return redirect("/series")


@series_module.route("/forget/<int:rel_id>", methods=["POST", "GET"])
def forget_episode(rel_id):
    """
    Executes a --series-forget statement for an episode.
    Redirects back to the series index.
    """
    release = db_session.query(Release).get(rel_id)

    context = {
        "release": release,
        "command": '--series-forget "%s" %s' % (release.episode.series.name, release.episode.identifier),
    }

    if request.method == "POST":
        if request.form.get("really", False):
            try:
                forget_series_episode(release.episode.series.name, release.episode.identifier)
                flash("Forgot %s %s." % (release.episode.series.name, release.episode.identifier), "delete")
            except ValueError as e:
                flash(e.message, "error")

        return redirect(url_for("index"))

    return render_template("series/forget.html", **context)


register_plugin(series_module, menu="Series")