Source code for flexget.plugins.filter.timeframe

from datetime import datetime

from loguru import logger
from sqlalchemy import Column, DateTime, Integer, String, Unicode

from flexget import db_schema, plugin
from flexget.db_schema import Session
from flexget.entry import Entry
from flexget.event import event
from flexget.utils import qualities
from flexget.utils.database import quality_property
from flexget.utils.tools import group_entries, parse_timedelta

logger = logger.bind(name='timeframe')

Base = db_schema.versioned_base('upgrade', 0)

entry_actions = {'accept': Entry.accept, 'reject': Entry.reject}


[docs] class EntryTimeFrame(Base): __tablename__ = 'timeframe' id = Column(Unicode, primary_key=True, index=True) status = Column(Unicode) title = Column(Unicode) _quality = Column('quality', String) quality = quality_property('_quality') first_seen = Column(DateTime, default=datetime.now()) proper_count = Column(Integer, default=0) def __str__(self): return f'<Timeframe(id={self.id},added={self.added},quality={self.quality})>'
[docs] class FilterTimeFrame: schema = { 'type': 'object', 'properties': { 'identified_by': {'type': 'string', 'default': 'auto'}, 'target': {'type': 'string', 'format': 'quality_requirements'}, 'wait': {'type': 'string', 'format': 'interval'}, 'on_waiting': { 'type': 'string', 'enum': ['accept', 'reject', 'do_nothing'], 'default': 'reject', }, 'on_reached': { 'type': 'string', 'enum': ['accept', 'reject', 'do_nothing'], 'default': 'do_nothing', }, }, 'required': ['target', 'wait'], 'additionalProperties': False, } # Run last so we work on only accepted entries
[docs] @plugin.priority(plugin.PRIORITY_LAST) def on_task_filter(self, task, config): if not config: return identified_by = ( '{{ media_id }}' if config['identified_by'] == 'auto' else config['identified_by'] ) grouped_entries = group_entries(task.accepted, identified_by) if not grouped_entries: return action_on_waiting = ( entry_actions[config['on_waiting']] if config['on_waiting'] != 'do_nothing' else None ) action_on_reached = ( entry_actions[config['on_reached']] if config['on_reached'] != 'do_nothing' else None ) with Session() as session: # Prefetch Data existing_ids = ( session .query(EntryTimeFrame) .filter(EntryTimeFrame.id.in_(grouped_entries.keys())) .all() ) existing_ids = {e.id: e for e in existing_ids} for identifier, entries in grouped_entries.items(): if not entries: continue id_timeframe = existing_ids.get(identifier) if not id_timeframe: id_timeframe = EntryTimeFrame() id_timeframe.id = identifier id_timeframe.status = 'waiting' id_timeframe.first_seen = datetime.now() session.add(id_timeframe) if id_timeframe.status == 'accepted': logger.debug( 'Previously accepted {} with {} skipping', identifier, id_timeframe.title ) continue # Sort entities in order of quality and best proper entries.sort(key=lambda e: (e['quality'], e.get('proper_count', 0)), reverse=True) best_entry = entries[0] logger.debug( 'Current best for identifier {} is {}', identifier, best_entry['title'] ) id_timeframe.title = best_entry['title'] id_timeframe.quality = best_entry['quality'] id_timeframe.proper_count = best_entry.get('proper_count', 0) # Check we hit target or better target_requirement = qualities.Requirements(config['target']) target_quality = qualities.Quality(config['target']) if ( target_requirement.allows(best_entry['quality']) or best_entry['quality'] >= target_quality ): logger.debug( 'timeframe reach target quality {} or higher for {}', target_quality, identifier, ) if action_on_reached: action_on_reached(best_entry, 'timeframe reached target quality or higher') continue # Check if passed wait time expires = id_timeframe.first_seen + parse_timedelta(config['wait']) if expires <= datetime.now(): logger.debug( 'timeframe expired, releasing quality restriction for {}', identifier ) if action_on_reached: action_on_reached(best_entry, 'timeframe wait expired') continue # Verbose waiting, add to backlog if action_on_waiting: for entry in entries: action_on_waiting(entry, 'timeframe waiting') diff = expires - datetime.now() hours, remainder = divmod(diff.seconds, 3600) hours += diff.days * 24 minutes, _ = divmod(remainder, 60) logger.info( '`{}`: timeframe waiting for {:02d}h:{:02d}min. Currently best is `{}`.', identifier, hours, minutes, best_entry['title'], ) # add best entry to backlog (backlog is able to handle duplicate adds) plugin.get('backlog', self).add_backlog(task, best_entry, session=session)
[docs] def on_task_learn(self, task, config): if not config: return identified_by = ( '{{ media_id }}' if config['identified_by'] == 'auto' else config['identified_by'] ) grouped_entries = group_entries(task.accepted, identified_by) if not grouped_entries: return with Session() as session: # Prefetch Data existing_ids = ( session .query(EntryTimeFrame) .filter(EntryTimeFrame.id.in_(grouped_entries.keys())) .all() ) existing_ids = {e.id: e for e in existing_ids} for identifier, entries in grouped_entries.items(): if not entries: continue id_timeframe = existing_ids.get(identifier) if not id_timeframe: continue # Sort entities in order of quality entries.sort(key=lambda e: e['quality'], reverse=True) # First entry will be the best quality best_entry = entries[0] id_timeframe.quality = best_entry['quality'] id_timeframe.title = best_entry['title'] id_timeframe.proper_count = best_entry.get('proper_count', 0) id_timeframe.status = 'accepted'
[docs] @event('plugin.register') def register_plugin(): plugin.register(FilterTimeFrame, 'timeframe', api_ver=2)