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)
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')
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)
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)
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')
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)
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)
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)
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)
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'])
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):
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
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}
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()
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,
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
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:
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):
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()))
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):
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')
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
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)
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()
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
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()):
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',
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()