Esempio n. 1
0
    def notify(self,
               title,
               message,
               sender,
               password,
               recipients,
               url=None,
               **kwargs):
        try:
            import sleekxmpp  # noqa
        except ImportError as e:
            log.debug('Error importing SleekXMPP: %s', e)
            raise DependencyError(
                __name__, 'sleekxmpp',
                'SleekXMPP module required. ImportError: %s', e)
        try:
            import dns  # noqa
        except ImportError:
            try:
                import dnspython  # noqa
            except ImportError as e:
                log.debug('Error importing dnspython: %s', e)
                raise DependencyError(
                    __name__, 'dnspython',
                    'dnspython module required. ImportError: %s' % e)

        class SendMsgBot(sleekxmpp.ClientXMPP):
            def __init__(self, jid, password, recipients, message):
                sleekxmpp.ClientXMPP.__init__(self, jid, password)
                self.recipients = recipients
                self.msg = message
                self.add_event_handler("session_start",
                                       self.start,
                                       threaded=True)
                self.register_plugin('xep_0030')  # Service Discovery
                self.register_plugin('xep_0199')  # XMPP Ping

            def start(self, xmpp_event):
                for recipient in self.recipients:
                    self.send_presence(pto=recipient)
                    self.send_message(mto=recipient,
                                      mbody=self.msg,
                                      mtype='chat')
                self.disconnect(wait=True)

        message = '%s\n%s' % (title, message)
        log.debug('Sending XMPP notification about: %s', message)
        logging.getLogger('sleekxmpp').setLevel(logging.CRITICAL)

        if not isinstance(recipients, list):
            recipients = [recipients]

        xmpp = SendMsgBot(sender, password, recipients, message)
        if xmpp.connect():
            xmpp.process(block=True)
Esempio n. 2
0
 def on_process_start(self, task, config):
     """Raise a DependencyError if our dependencies aren't available"""
     # This is overridden by OutputDeluge to add deluge 1.1 support
     try:
         from deluge.ui.client import client
     except ImportError as e:
         log.debug('Error importing deluge: %s' % e)
         raise DependencyError('output_deluge', 'deluge',
                               'Deluge module and it\'s dependencies required. ImportError: %s' % e, log)
     try:
         from twisted.internet import reactor
     except:
         raise DependencyError('output_deluge', 'twisted.internet', 'Twisted.internet package required', log)
     log.debug('Using deluge 1.2 api')
Esempio n. 3
0
    def notify(self, title, message, timeout, **kwargs):
        """
        Send a notification to NotifyOSD

        :param str title: Notification title
        :param message: Notification message
        :param timeout: Notification timeout
        """
        try:
            from gi.repository import Notify
        except ImportError as e:
            log.debug('Error importing Notify: %s', e)
            raise DependencyError(
                __name__, 'gi.repository',
                'Notify module required. ImportError: %s' % e)

        if not Notify.init("Flexget"):
            raise PluginWarning('Unable to init libnotify.')

        n = Notify.Notification.new(title, message, None)
        timeout = (timeout * 1000)
        n.set_timeout(timeout)

        if not n.show():
            raise PluginWarning('Unable to send notification for %s' % title)
Esempio n. 4
0
    def mac_notify(self, title, message, config):
        config = self.prepare_config(config)
        try:
            from pync import Notifier
        except ImportError as e:
            logger.debug('Error importing pync: {}', e)
            raise DependencyError(plugin_name, 'pync',
                                  'pync module required. ImportError: %s' % e)

        icon_path = None
        try:
            import flexget.ui

            icon_path = os.path.join(flexget.ui.__path__[0], 'src',
                                     'favicon.ico')
        except Exception as e:
            logger.debug(
                'Error trying to get flexget icon from webui folder: {}', e)

        try:
            Notifier.notify(
                message,
                subtitle=title,
                title='FlexGet Notification',
                appIcon=icon_path,
                timeout=config['timeout'],
                open=config.get('url'),
            )
        except Exception as e:
            raise PluginWarning('Cannot send a notification: %s' % e)
Esempio n. 5
0
class DelugePlugin(object):
    """Base class for deluge plugins, contains settings and methods for connecting to a deluge daemon."""
    def validate_connection_info(self, dict_validator):
        dict_validator.accept('text', key='host')
        dict_validator.accept('integer', key='port')
        dict_validator.accept('text', key='user')
        dict_validator.accept('text', key='pass')

    def prepare_connection_info(self, config):
        config.setdefault('host', 'localhost')
        config.setdefault('port', 58846)
        config.setdefault('user', '')
        config.setdefault('pass', '')

    def on_process_start(self, task, config):
        """Raise a DependencyError if our dependencies aren't available"""
        # This is overridden by OutputDeluge to add deluge 1.1 support
        try:
            from deluge.ui.client import client
        except ImportError, e:
            log.debug('Error importing deluge: %s' % e)
            raise DependencyError(
                'output_deluge', 'deluge',
                'Deluge module and it\'s dependencies required. ImportError: %s'
                % e, log)
        try:
            from twisted.internet import reactor
        except:
            raise DependencyError('output_deluge', 'twisted.internet',
                                  'Twisted.internet package required', log)
        log.debug('Using deluge 1.2 api')
Esempio n. 6
0
 def on_task_start(self, task, config):
     try:
         from gi.repository import Notify
     except ImportError as e:
         log.debug('Error importing Notify: %s' % e)
         raise DependencyError(
             'notify_osd', 'gi.repository',
             'Notify module required. ImportError: %s' % e)
Esempio n. 7
0
 def on_process_start(self, task, config):
     """Raise a DependencyError if our dependencies aren't available"""
     # This is overridden by OutputDeluge to add deluge 1.1 support
     try:
         from deluge.ui.client import client
     except ImportError, e:
         log.debug('Error importing deluge: %s' % e)
         raise DependencyError('output_deluge', 'deluge', 'Deluge module and it\'s dependencies required. ImportError: %s' % e, log)
Esempio n. 8
0
    def windows_notify(self, title, message, config):
        config = self.prepare_config(config)
        try:
            from win32api import GetModuleHandle, PostQuitMessage
            from win32con import (CW_USEDEFAULT, IMAGE_ICON, IDI_APPLICATION,
                                  LR_DEFAULTSIZE, LR_LOADFROMFILE, WM_DESTROY,
                                  WS_OVERLAPPED, WS_SYSMENU, WM_USER)
            from win32gui import (CreateWindow, DestroyWindow, LoadIcon,
                                  LoadImage, NIF_ICON, NIF_INFO, NIF_MESSAGE,
                                  NIF_TIP, NIM_ADD, NIM_DELETE, NIM_MODIFY,
                                  RegisterClass, Shell_NotifyIcon,
                                  UpdateWindow, WNDCLASS)
        except ImportError:
            raise DependencyError(
                __name__, 'pypiwin32',
                'pywin32 module is required for desktop notifications on '
                'windows. You can install it with `pip install pypiwin32`')

        # Register the window class.
        wc = WNDCLASS()
        hinst = wc.hInstance = GetModuleHandle(None)
        wc.lpszClassName = "FlexGetTaskbar"
        if not self.windows_classAtom:
            self.windows_classAtom = RegisterClass(wc)
        style = WS_OVERLAPPED | WS_SYSMENU
        hwnd = CreateWindow(self.windows_classAtom, "Taskbar", style, 0, 0,
                            CW_USEDEFAULT, CW_USEDEFAULT, 0, 0, hinst, None)
        UpdateWindow(hwnd)

        hicon = LoadIcon(0, IDI_APPLICATION)
        # Hackily grab the icon from the webui if possible
        icon_flags = LR_LOADFROMFILE | LR_DEFAULTSIZE
        try:
            import flexget.ui
            icon_path = os.path.join(flexget.ui.__path__[0], 'src',
                                     'favicon.ico')
            hicon = LoadImage(hinst, icon_path, IMAGE_ICON, 0, 0, icon_flags)
        except Exception as e:
            log.debug('Error trying to get flexget icon from webui folder: %s',
                      e)

        # Taskbar icon
        flags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO
        nid = (hwnd, 0, flags, WM_USER + 20, hicon, "FlexGet Notification",
               message, config['timeout'] * 1000, title)
        Shell_NotifyIcon(NIM_ADD, nid)
Esempio n. 9
0
    def linux_notify(self, title, message, config):
        config = self.prepare_config(config)
        try:
            from gi.repository import Notify
        except ImportError as e:
            logger.debug('Error importing Notify: {}', e)
            raise DependencyError(
                plugin_name, 'gi.repository',
                'Notify module required. ImportError: %s' % e)

        if not Notify.init("Flexget"):
            raise PluginWarning('Unable to init libnotify.')

        n = Notify.Notification.new(title, message, None)
        timeout = config['timeout'] * 1000
        n.set_timeout(timeout)

        if not n.show():
            raise PluginWarning('Unable to send notification for %s' % title)
Esempio n. 10
0
    def on_task_modify(self, task):
        """
        The downloaded file is accessible in modify phase
        """
        try:
            from pynzb import nzb_parser
        except ImportError:
            # TODO: remove builtin status so this won't get repeated on every task execution
            # TODO: this will get loaded even without any need for nzb
            raise DependencyError(issued_by='nzb_size', missing='lib pynzb')

        for entry in task.accepted:
            if entry.get('mime-type', None) in [u'text/nzb', u'application/x-nzb'] or \
                    entry.get('filename', '').endswith('.nzb'):

                if 'file' not in entry:
                    log.warning(
                        '`%s` does not have a `file` that could be used to get size information'
                        % entry['title'])
                    continue

                filename = entry['file']
                log.debug('reading %s' % filename)
                xmldata = file(filename).read()

                try:
                    nzbfiles = nzb_parser.parse(xmldata)
                except:
                    log.debug('%s is not a valid nzb' % entry['title'])
                    continue

                size = 0
                for nzbfile in nzbfiles:
                    for segment in nzbfile.segments:
                        size += segment.bytes

                size_mb = size / 1024 / 1024
                log.debug('%s content size: %s MB' % (entry['title'], size_mb))
                entry['content_size'] = size_mb
            else:
                log.trace('%s does not seem to be nzb' % entry['title'])
Esempio n. 11
0
    def on_task_input(self, task, config):
        if not imported:
            raise DependencyError('ftp_list', 'ftp_list',
                                  'ftputil is required for this plugin')
        config = self.prepare_config(config)

        self.username = config.get('username')
        self.password = config.get('password')
        self.host = config.get('host')
        self.port = config.get('port')

        directories = config.get('dirs')
        recursion = config.get('recursion')
        content_types = config.get('retrieve')
        recursion_depth = -1 if recursion else 0

        base_class = ftplib.FTP_TLS if config.get('ssl') else ftplib.FTP
        session_factory = ftputil.session.session_factory(
            port=self.port, base_class=base_class)
        try:
            logger.verbose(
                'trying to establish connection to FTP: {}:<HIDDEN>@{}:{}',
                self.username,
                self.host,
                self.port,
            )
            self.FTP = ftputil.FTPHost(self.host,
                                       self.username,
                                       self.password,
                                       session_factory=session_factory)
        except FTPOSError as e:
            raise PluginError('Could not connect to FTP: {}'.format(e.args[0]))

        entries = []
        for d in directories:
            for content in self.get_content(d, recursion, recursion_depth,
                                            content_types):
                entries.append(self._to_entry(content))
        return entries
from __future__ import unicode_literals, division, absolute_import
import logging
from flexget.plugin import register_plugin, DependencyError, PluginError
from flexget.utils import imdb
from flexget.utils.log import log_once

try:
    from flexget.plugins.api_rottentomatoes import lookup_movie
except ImportError:
    raise DependencyError(
        issued_by='rottentomatoes_lookup',
        missing='api_rottentomatoes',
        message='rottentomatoes_lookup requires the `api_rottentomatoes` plugin'
    )

log = logging.getLogger('rottentomatoes_lookup')


def get_imdb_id(movie):
    for alt_id in movie.alternate_ids:
        if alt_id.name == 'imdb':
            return 'tt' + alt_id.id


def get_rt_url(movie):
    for link in movie.links:
        if link.name == 'alternate':
            return link.url


class PluginRottenTomatoesLookup(object):
Esempio n. 13
0
from __future__ import unicode_literals, division, absolute_import
import logging
from flexget.plugin import register_plugin, DependencyError, priority

try:
    from flexget.plugins.api_tvdb import lookup_series, lookup_episode, get_mirror
except ImportError:
    raise DependencyError(issued_by='thetvdb_lookup', missing='api_tvdb',
                          message='thetvdb_lookup requires the `api_tvdb` plugin')

log = logging.getLogger('thetvdb_lookup')


class PluginThetvdbLookup(object):
    """Retrieves TheTVDB information for entries. Uses series_name,
    series_season, series_episode from series plugin.

    Example:

    thetvdb_lookup: yes

    Primarily used for passing thetvdb information to other plugins.
    Among these is the IMDB url for the series.

    This information is provided (via entry):
    series info:
      series_name_thetvdb
      series_rating
      series_status (Continuing or Ended)
      series_runtime (show runtime in minutes)
      series_first_air_date
Esempio n. 14
0
from __future__ import unicode_literals, division, absolute_import
import logging
import re
from urllib2 import HTTPError
from flexget.entry import Entry
from flexget.plugin import priority, register_plugin, get_plugin_by_name, DependencyError
from flexget.utils.cached_input import cached
from flexget.utils.tools import urlopener
from flexget.utils.soup import get_soup
try:
    from flexget.plugins.input.rss import InputRSS
except ImportError:
    raise DependencyError(issued_by='apple_trailers', missing='rss')

log = logging.getLogger('apple_trailers')


class AppleTrailers(InputRSS):
    """
        Adds support for Apple.com movie trailers.

        apple_trailers: 480p

        Choice of quality is one of: ipod, '320', '480', 640w, 480p, 720p, 1080p
    """

    rss_url = 'http://trailers.apple.com/trailers/home/rss/newtrailers.rss'
    qualities = ['ipod', 320, '320', 480, '480', '640w', '480p', '720p', '1080p']

    schema = {"enum": qualities}
Esempio n. 15
0
    def notify(self, title, message, config):
        """
        Publish to an MQTT topic
        """
        try:
            import paho.mqtt.client as mqtt

        except ImportError as e:
            logger.verbose('Error importing paho.mqtt.client: {}', e)
            raise DependencyError(
                plugin_name, 'paho.mqtt.client',
                'paho-mqtt python module is required for MQTT notify plugin. ImportError: %s'
                % e)

        def on_log_cb(client, userdata, level, buff):
            logger.verbose(str(buff))

        def on_publish_cb(client, userdata, mid):
            logger.verbose(
                'MQTT on_publish callback -  message was successfully published to broker as messageID={}',
                str(mid))
            client.disconnect()

        def on_disconnect_cb(client, userdata, rc):
            logger.verbose(
                'MQTT on_disconnect callback - disconnected with result code {} [{}]',
                str(rc), conn_rc_description_map.get(rc), 'Unknown')
            client.loop_stop()

        config['title'] = title
        config['message'] = message
        config['payload'] = '{} - {}'.format(config.get('title'),
                                             config.get('message'))

        conn_rc_description_map = {
            0:
            'Connection Accepted',
            1:
            'Connection Refused, unacceptable protocol version - The Server does not support the level of the MQTT protocol requested by the Client',
            2:
            'Connection Refused, identifier rejected - The Client identifier is correct UTF-8 but not allowed by the Server',
            3:
            'Connection Refused, Server unavailable - The Network Connection has been made but the MQTT service is unavailable',
            4:
            'Connection Refused, bad user name or password - The data in the user name or password is malformed',
            5:
            'Connection Refused, not authorized - The Client is not authorized to connect'
        }

        MQTT_proto_map = {'MQTTv31': mqtt.MQTTv311, 'MQTTv311': mqtt.MQTTv31}

        logger.trace('MQTT notify config={}', str(config))

        client = mqtt.Client(protocol=MQTT_proto_map.get(
            config.get('broker_protocol', mqtt.MQTTv311)),
                             transport=config.get('broker_transport', 'tcp'))

        client.enable_logger(logger=logger)

        client.on_log = on_log_cb
        client.on_publish = on_publish_cb
        client.on_disconnect = on_disconnect_cb

        #Handle SSL/TLS communication w/out certificate authentication
        if not config.get('certificates', {}).get(
                'client_cert', False) and config.get(
                    'enable_encrypted_communication', False):
            client.tls_set(ca_certs=certs.get('broker_ca_cert'),
                           certfile=None,
                           keyfile=None,
                           cert_reqs=ssl.CERT_NONE)

            client.tls_insecure_set(True)

            logger.verbose('Basic SSL/TLS encrypted communications enabled')
            logger.verbose(
                'TLS insecure cert mode enabled. Broker cert will not be validated'
            )

        #Handle SSL/TLS communication with certificate authentication
        if config.get('certificates', False):
            certs = config.get('certificates', {})
            logger.debug('TLS certificate config: {}', str(certs))

            tls_version_map = {
                'tlsv1.2': ssl.PROTOCOL_TLSv1_2,
                'tlsv1.1': ssl.PROTOCOL_TLSv1_1,
                'tlsv1': ssl.PROTOCOL_TLSv1,
                '': None
            }
            tls_version = tls_version_map.get(certs.get('tls_version'),
                                              ssl.PROTOCOL_TLSv1_2)
            logger.verbose('TLS version is {}', str(tls_version))

            cert_required = ssl.CERT_REQUIRED if certs.get(
                'validate_broker_cert', True) else ssl.CERT_NONE

            client.tls_set(ca_certs=certs.get('broker_ca_cert'),
                           certfile=certs.get('client_cert'),
                           keyfile=certs.get('client_key'),
                           cert_reqs=cert_required,
                           tls_version=tls_version)

            if not certs.get('validate_broker_cert'):
                client.tls_insecure_set(True)
                logger.debug(
                    'TLS insecure cert mode enabled. Broker cert will not be validated'
                )
            else:
                logger.debug(
                    'TLS secure cert mode enabled. Broker cert will be validated'
                )

        #Handle user/pass authentication
        if config.get('username', False) or config.get('password', False):
            logger.debug(
                'Credential passwords s are redacted to protect the innocent...'
            )
            logger.debug(
                'Auth credentials: username=[{}] password sha256 hash is "{}"',
                config.get('username'),
                sha256(str(
                    config.get('password')).encode('utf-8')).hexdigest())
            logger.debug(
                'You can validate them yourself by calculating the sha256 hex digest of your password string (google is your friend if you do not know how to do this)'
            )
            logger.debug(
                'Note: a password that is not provided (i.e. None) will hash to "{}"',
                sha256(str(None).encode('utf-8')).hexdigest())

            client.username_pw_set = (config.get('username'),
                                      config.get('password'))

        try:
            logger.verbose("Connecting to {}:{}", config.get('broker_address'),
                           str(config.get('broker_port')))
            client.connect(config.get('broker_address'),
                           config.get('broker_port'),
                           config.get('broker_timeout'))
            logger.verbose("Connected to MQTT broker")
        except Exception as e:
            raise PluginWarning('Error connecting to MQTT broker:  %s' % e)

        try:
            logger.verbose('Publishing message [{}] to topic [{}] ',
                           config.get('payload'), config.get('topic'))
            publish_info = client.publish(config.get('topic'),
                                          config.get('payload'),
                                          qos=config.get('qos'),
                                          retain=config.get('retain'))
            logger.verbose(
                "Notification sent to broker, waiting for callback response to confirm publishing success - rc={}",
                publish_info)
        except Exception as e:
            raise PluginWarning('Error publishing to MQTT broker:  %s' % e)

        client.loop(timeout=config.get('broker_timeout'))
        client.loop_start()
Esempio n. 16
0
if os.name != 'nt':
    raise EnvironmentError('win32 only')

try:
    import win32api
    import win32con
    import win32gui_struct

    try:
        import winxpgui as win32gui
    except ImportError:
        import win32gui
except ImportError:
    raise DependencyError(issued_by='ui.win32tray',
                          missing='win32 extensions',
                          message='Task tray icon requires win32 extensions')


class SysTrayIcon(object):
    '''TODO'''
    QUIT = 'QUIT'
    SPECIAL_ACTIONS = [QUIT]

    FIRST_ID = 1023

    def __init__(
        self,
        icon,
        hover_text,
        menu_options,
Esempio n. 17
0
from argparse import ArgumentParser

from sqlalchemy.orm.exc import NoResultFound

from flexget import options
from flexget.event import event
from flexget.logger import console
from flexget.plugin import DependencyError
from flexget.utils.database import with_session
from flexget.utils.tools import split_title_year

try:
    from flexget.plugins.list.movie_list import get_list_by_exact_name, get_movie_lists, get_movies_by_list_id, \
        get_movie_by_title, MovieListMovie, get_db_movie_identifiers, MovieListList
except ImportError:
    raise DependencyError(issued_by='cli_movie_list', missing='movie_list')


def parse_identifier(identifier_string):
    if identifier_string.count('=') != 1:
        return
    name, value = identifier_string.split('=', 2)
    return {name: value}


def do_cli(manager, options):
    """Handle movie-list subcommand"""
    if options.list_action == 'all':
        movie_list_lists(options)
        return
Esempio n. 18
0
from __future__ import unicode_literals, division, absolute_import
import datetime

from flexget.plugin import DependencyError

try:
    import simplejson as json
except ImportError:
    try:
        import json
    except ImportError:
        try:
            # Google Appengine offers simplejson via django
            from django.utils import simplejson as json
        except ImportError:
            raise DependencyError(missing='simplejson')

DATE_FMT = '%Y-%m-%d'
ISO8601_FMT = '%Y-%m-%dT%H:%M:%SZ'


class DTDecoder(json.JSONDecoder):
    def decode(self, obj, **kwargs):
        # The built-in `json` library will `unicode` strings, except for empty strings. patch this for
        # consistency so that `unicode` is always returned.
        if obj == b'':
            return ''

        if isinstance(obj, basestring):
            dt_str = obj.strip('"')
            try:
Esempio n. 19
0
import urllib
import urllib2
import re
import cookielib
from datetime import datetime

from sqlalchemy import Column, Integer, String, DateTime

from flexget import db_schema
from flexget.plugin import register_plugin, DependencyError, PluginWarning

try:
    from flexget.plugins.api_tvdb import lookup_series
except ImportError:
    raise DependencyError(issued_by='myepisodes',
                          missing='api_tvdb',
                          message='myepisodes requires the `api_tvdb` plugin')

log = logging.getLogger('myepisodes')
Base = db_schema.versioned_base('myepisodes', 0)


class MyEpisodesInfo(Base):
    __tablename__ = 'myepisodes'

    id = Column(Integer, primary_key=True)
    series_name = Column(String, unique=True)
    myepisodes_id = Column(Integer, unique=True)
    updated = Column(DateTime)

    def __init__(self, series_name, myepisodes_id):
Esempio n. 20
0
from __future__ import unicode_literals, division, absolute_import
import time
import logging
import posixpath
from flask import render_template, Blueprint, request, redirect, flash, send_file
from flask.helpers import url_for
from flexget.plugin import DependencyError, get_plugin_by_name
from flexget.ui.webui import register_plugin, app, manager
from flexget.utils import qualities

try:
    from flexget.plugins.filter.movie_queue import QueueError, queue_get, queue_add, queue_del, queue_edit
except ImportError:
    raise DependencyError(issued_by='ui.movies', missing='movie_queue')


movies_module = Blueprint('movies', __name__)
log = logging.getLogger('ui.movies')


# TODO: refactor this filter to some globally usable place (webui.py?)
#       also flexget/plugins/ui/utils.py needs to be removed
#       ... mainly because we have flexget/utils for that :)


@app.template_filter('pretty_age')
def pretty_age_filter(value):
    from flexget.ui.utils import pretty_date
    return pretty_date(time.mktime(value.timetuple()))

Esempio n. 21
0
from __future__ import unicode_literals, division, absolute_import
from flask import redirect, render_template, Module, request, flash, url_for
from sqlalchemy.sql.expression import desc, asc

from flexget.plugin import DependencyError
from flexget.ui.webui import register_plugin, db_session, app

import time
import logging

from flexget.ui.utils import pretty_date

try:
    from flexget.plugins.filter.series import Series, Episode, Release, forget_series, forget_series_episode
except ImportError:
    raise DependencyError(issued_by='ui.series', missing='series')

series_module = Module(__name__, url_prefix='/series')
log = logging.getLogger('ui.series')

# TODO: refactor this filter to some globally usable place (webui.py?)
#       also flexget/plugins/ui/utils.py needs to be removed
#       ... mainly because we have flexget/utils for that :)
#
# Josh  Changing the package layout to use 'flexget.ui.utils' instead
# says  seems to illeviated the need to do this no? I don't think this
#       will be of use for anything but UI related functions.


@app.template_filter('pretty_age')
def pretty_age_filter(value):
Esempio n. 22
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')
Esempio n. 23
0
from __future__ import unicode_literals, division, absolute_import
from argparse import ArgumentParser

from sqlalchemy.exc import OperationalError

from flexget import options
from flexget.event import event
from flexget.logger import console
from flexget.plugin import DependencyError
from flexget.utils import qualities

try:
    from flexget.plugins.filter.movie_queue import QueueError, queue_add, queue_del, queue_get, queue_forget, parse_what
except ImportError:
    raise DependencyError(issued_by='cli_movie_queue', missing='movie_queue')


def do_cli(manager, options):
    """Handle movie-queue subcommand"""

    if options.queue_action == 'list':
        queue_list(options)
        return

    # If the action affects make sure all entries are processed again next run.
    manager.config_changed()

    if options.queue_action == 'clear':
        clear()
        return
Esempio n. 24
0
from __future__ import unicode_literals, division, absolute_import
import logging
from flexget.ui.webui import db_session, app, executor
from flask import request, render_template, flash, Module
from flexget.plugin import DependencyError

try:
    from flexget.plugins.generic.archive import ArchiveEntry, search
except ImportError:
    raise DependencyError(issued_by='ui.archive', missing='archive')

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

# TODO: refactor this filter to some globally usable place (webui.py?)
#       also flexget/plugins/ui/utils.py needs to be removed
#       ... mainly because we have flexget/utils for that :)


@app.template_filter('pretty_age')
def pretty_age_filter(value):
    import time
    from flexget.ui.utils import pretty_date
    return pretty_date(time.mktime(value.timetuple()))


@archive.route('/', methods=['POST', 'GET'])
def index():
    context = {}
    if request.method == 'POST':
        text = request.form.get('keyword', None)
Esempio n. 25
0
from datetime import datetime, timedelta
from string import capwords
from sqlalchemy import desc
from flexget.manager import Session
from flexget.plugin import register_plugin, register_parser_option, DependencyError

try:
    from flexget.plugins.filter.series import SeriesDatabase, Series, Episode, Release, forget_series, forget_series_episode
except ImportError:
    raise DependencyError(issued_by='cli_series', missing='series', message='Series commandline interface not loaded')


class SeriesReport(SeriesDatabase):

    """Produces --series report"""

    def on_process_start(self, task):
        if task.manager.options.series:
            task.manager.disable_tasks()

            if isinstance(task.manager.options.series, bool):
                self.display_summary()
            else:
                self.display_details(task.manager.options.series)

    def display_details(self, name):
        """Display detailed series information, ie. --series NAME"""

        from flexget.manager import Session
        session = Session()
Esempio n. 26
0
from __future__ import unicode_literals, division, absolute_import
import logging
from flexget.entry import Entry
from flexget.plugin import register_plugin, DependencyError

log = logging.getLogger('emit_series')

try:
    from flexget.plugins.filter.series import Series, SeriesDatabase
except ImportError as e:
    log.error(e.message)
    raise DependencyError(issued_by='emit_series', missing='series')


class EmitSeries(SeriesDatabase):
    """
    Emit next episode number from all known series.

    Supports only series enumerated by season, episode.
    """
    def validator(self):
        from flexget import validator
        return validator.factory('boolean')

    def on_task_input(self, task, config):
        entries = []
        for series in task.session.query(Series).all():
            latest = self.get_latest_info(series)
            if not latest:
                # no latest known episode, skip
                continue
Esempio n. 27
0
import logging
from sqlalchemy import Column, Integer, String, ForeignKey, or_, and_, select, update
from flexget import schema
from flexget.manager import Session
from flexget.utils import qualities
from flexget.utils.imdb import extract_id
from flexget.utils.database import quality_requirement_property, with_session
from flexget.utils.sqlalchemy_utils import table_exists, table_schema
from flexget.plugin import DependencyError, get_plugin_by_name, register_plugin
from flexget.event import event

try:
    from flexget.plugins.filter import queue_base
except ImportError:
    raise DependencyError(issued_by='movie_queue',
                          missing='queue_base',
                          message='movie_queue requires the queue_base plugin')

log = logging.getLogger('movie_queue')
Base = schema.versioned_base('movie_queue', 2)


@event('manager.startup')
def migrate_imdb_queue(manager):
    """If imdb_queue table is found, migrate the data to movie_queue"""
    session = Session()
    try:
        if table_exists('imdb_queue', session):
            log.info('Migrating imdb_queue items to movie_queue')
            old_table = table_schema('imdb_queue', session)
            for row in session.execute(old_table.select()):
Esempio n. 28
0
import logging
from flexget.plugin import register_plugin, DependencyError
from flexget.utils import imdb

try:
    # TODO: Fix this after api_tmdb has module level functions
    from flexget.plugins.api_tmdb import ApiTmdb
    lookup = ApiTmdb.lookup
except ImportError:
    raise DependencyError(issued_by='tmdb_lookup', missing='api_tmdb')

log = logging.getLogger('tmdb_lookup')


class PluginTmdbLookup(object):
    """Retrieves tmdb information for entries.

    Example:
        tmdb_lookup: yes
    """

    field_map = {
        'tmdb_name': 'name',
        'tmdb_id': 'id',
        'imdb_id': 'imdb_id',
        'tmdb_year': 'year',
        'tmdb_popularity': 'popularity',
        'tmdb_rating': 'rating',
        'tmdb_genres': lambda movie: [genre.name for genre in movie.genres],
        'tmdb_released': 'released',
        'tmdb_votes': 'votes',
Esempio n. 29
0
from __future__ import unicode_literals, division, absolute_import
from flexget.plugin import DependencyError

try:
    from guppy import hpy
except ImportError:
    # this will leave the plugin unloaded
    raise DependencyError(issued_by='memusage',
                          missing='ext lib `guppy`',
                          silent=True)

from flexget.plugin import register_plugin, register_parser_option
import logging

log = logging.getLogger('mem_usage')
"""
http://blog.mfabrik.com/2008/03/07/debugging-django-memory-leak-with-trackrefs-and-guppy/

# Print memory statistics
def update():
    print heapy.heap()

# Print relative memory consumption since last sycle
def update():
    print heapy.heap()
    heapy.setref()

# Print relative memory consumption w/heap traversing
def update()
    print heapy.heap().get_rp(40)
    heapy.setref()