flexget.plugins.plugin_archive
Covered: 139 lines
Missed: 30 lines
Skipped 61 lines
Percent: 82 %
  1
import logging
  2
from flexget.event import event
  3
from flexget.manager import Base
  4
from flexget.entry import Entry
  5
from flexget.plugin import priority, register_parser_option, register_plugin, PluginError
  6
from flexget.utils.tools import console
  7
from sqlalchemy import Column, Integer, DateTime, Unicode, Index, or_
  8
from datetime import datetime
  9
from flexget.manager import Session
 10
from optparse import SUPPRESS_HELP
 12
log = logging.getLogger('archive')
 15
class ArchiveEntry(Base):
 17
    __tablename__ = 'archive_entry'
 19
    id = Column(Integer, primary_key=True)
 20
    title = Column(Unicode, index=True)
 21
    url = Column(Unicode, index=True)
 22
    description = Column(Unicode)
 23
    feed = Column(Unicode)
 24
    added = Column(DateTime, index=True)
 26
    def __init__(self):
 27
        self.added = datetime.now()
 29
    def __str__(self):
 30
        return '<ArchiveEntry(title=%s,url=%s,feed=%s)>' % (self.title, self.url, self.feed)
 33
columns = Base.metadata.tables['archive_entry'].c
 34
Index('archive_feed_title', columns.feed, columns.title)
 37
def search(session, text):
 38
    """Search by :text: from archive"""
 39
    keyword = unicode(text).replace(' ', '%')
 40
    return session.query(ArchiveEntry).filter(or_(ArchiveEntry.title.like('%' + keyword + '%'),
 41
        ArchiveEntry.feed == keyword)).all()
 44
class ArchiveSearch(object):
 46
    def on_process_start(self, feed):
 47
        if not feed.manager.options.archive_search:
 48
            return
 50
        from flexget.utils.tools import strip_html
 52
        feed.manager.disable_feeds()
 54
        def print_ae(ae):
 55
            diff = datetime.now() - ae.added
 57
            console('ID: %-6s | Feed: %-10s | Title: %s\nAdded: %s (%d days ago)\nURL: %s' % \
 58
                (ae.id, ae.feed, ae.title, ae.added, diff.days, ae.url))
 59
            if ae.description:
 60
                console('Description: %s' % strip_html(ae.description))
 61
            console('---')
 63
        session = Session()
 64
        try:
 65
            console('Searching ...')
 66
            for ae in search(session, feed.manager.options.archive_search):
 67
                print_ae(ae)
 68
        finally:
 69
            session.close()
 72
@event('manager.execute.started')
 73
def reset_archive_inject(manager):
 74
    log.debug('reseting injection')
 75
    ArchiveInject.inject_entries = []
 78
class ArchiveInject(object):
 80
    inject_entries = []
 82
    @priority(512)
 83
    def on_process_start(self, feed):
 84
        inject_ids = feed.manager.options.archive_inject_id
 85
        if not inject_ids:
 86
            return
 89
        if not self.inject_entries:
 90
            session = Session()
 91
            try:
 92
                for id_str in inject_ids.split(','):
 93
                    try:
 94
                        id = int(id_str.strip())
 95
                    except ValueError:
 96
                        raise PluginError('Given ID `%s` is not a valid number' % id_str.strip())
 97
                    archive_entry = session.query(ArchiveEntry).filter(ArchiveEntry.id == id).first()
100
                    if not archive_entry:
101
                        log.critical('There\'s no archive with ID `%s`' % id)
102
                        continue
105
                    if archive_entry.feed not in feed.manager.feeds:
106
                        log.critical('Feed `%s` does not seem to exists anymore, cannot inject from archive' % archive_entry.feed)
107
                        continue
109
                    self.inject_entries.append(archive_entry)
110
            finally:
111
                session.close()
114
        injecting_into = [x.feed for x in self.inject_entries]
115
        log.debug('injecting_into=%s' % injecting_into)
116
        if feed.name not in injecting_into:
117
            log.debug('not injecting to %s, aborting, disabling' % feed.name)
118
            feed.enabled = False
119
            feed.abort(silent=True)
120
        else:
121
            log.debug('injecting to %s, keeping it' % feed.name)
123
    @priority(255)
124
    def on_feed_input(self, feed):
125
        if not feed.manager.options.archive_inject_id:
126
            return
129
        log.info('Disabling all other inputs in the feed.')
130
        feed.disable_phase('input')
132
        for inject_entry in self.inject_entries:
133
            if inject_entry.feed != feed.name:
135
                continue
136
            log.info('Injecting from archive `%s`' % inject_entry.title)
137
            entry = Entry(inject_entry.title, inject_entry.url)
138
            if inject_entry.description:
139
                entry['description'] = inject_entry.description
140
            if feed.manager.options.archive_inject_immortal:
141
                log.debug('Injecting as immortal')
142
                entry['immortal'] = True
143
            feed.entries.append(entry)
144
            feed.accept(entry, '--archive-inject')
147
class Archive(object):
148
    """
149
    Archives all seen items into database where they can be later searched and injected.
150
    """
152
    def validator(self):
153
        from flexget import validator
154
        return validator.factory('boolean')
156
    @priority(-255)
157
    def on_feed_input(self, feed):
158
        """Add new entries into archive"""
159
        for entry in feed.entries:
160
            if feed.session.query(ArchiveEntry).\
161
               filter(ArchiveEntry.title == entry['title']).\
162
               filter(ArchiveEntry.feed == feed.name).first():
163
                log.debug('Entry `%s` already archived' % entry['title'])
164
                continue
165
            ae = ArchiveEntry()
166
            ae.title = entry['title']
167
            ae.url = entry['url']
168
            if 'description' in entry:
169
                ae.description = entry['description']
170
            ae.feed = feed.name
171
            log.debug('Adding `%s` to archive' % ae)
172
            feed.session.add(ae)
175
class UrlrewriteArchive(object):
177
    entry_map = {'title': 'title',
178
                 'url': 'url',
179
                 'description': 'description'}
181
    def search(self, query, comparator, config=None):
182
        """Search plugin API method"""
184
        session = Session()
185
        log.debug('looking for %s' % query)
186
        results = search(session, query)
189
        log.debug('found %s' % len(results))
190
        entries = []
191
        for result in results:
192
            entry = Entry()
193
            entry.update_using_map(self.entry_map, result)
194
            if entry.isvalid():
195
                entries.append(entry)
196
        return entries
199
def archive_inject(option, opt, value, parser):
200
    """Option parser function"""
202
    if not parser.rargs:
203
        console('Usage: --archive-inject ID [IMMORTAL]')
204
        import sys
205
        sys.exit(1)
207
    parser.values.archive_inject_id = parser.rargs[0]
209
    if len(parser.rargs) >= 2:
210
        from flexget.utils.tools import str_to_boolean
211
        parser.values.archive_inject_immortal = str_to_boolean(parser.rargs[1])
214
register_plugin(Archive, 'archive')
215
register_plugin(UrlrewriteArchive, 'flexget_archive', groups=['search'])
216
register_plugin(ArchiveSearch, '--archive-search', builtin=True)
217
register_plugin(ArchiveInject, '--archive-inject', builtin=True)
219
register_parser_option('--archive-search', action='store', dest='archive_search', default=False,
220
                       metavar='TXT', help='Search from the archive.')
221
register_parser_option('--archive-inject', action='callback', callback=archive_inject,
222
                       metavar='ID(s)',
223
                       help='Inject entries from the archive into a feed where it was archived from. Usage: ID[,ID] [FORCE]')
226
register_parser_option('--archive-inject-id', action='store', dest='archive_inject_id', default=False,
227
                       help=SUPPRESS_HELP)
228
register_parser_option('--archive-inject-immortal', action='store', dest='archive_inject_immortal', default=False,
229
                       help=SUPPRESS_HELP)