flexget.plugins.output_subtitles
Covered: 42 lines
Missed: 70 lines
Skipped 61 lines
Percent: 37 %
  1
from xmlrpclib import ServerProxy
  2
import re
  3
import difflib
  4
import os.path
  5
import sys
  6
import logging
  8
from flexget.manager import Session, Base
  9
from flexget.plugin import register_plugin
 10
from sqlalchemy import Column, Integer, String, DateTime, PickleType
 11
from datetime import datetime, timedelta
 12
from flexget.utils.tools import urlopener
 14
"""
 16
DRAFT
 18
class SubtitleQueue(Base):
 20
    __tablename__ = 'subtitle_queue'
 22
    id = Column(Integer, primary_key=True)
 23
    feed = Column(String)
 24
    imdb_id = Column(String)
 25
    added = Column(DateTime)
 27
    def __init__(self, feed, imdb_id):
 28
        self.feed = feed
 29
        self.imdb_id = imdb_id
 30
        self.added = datetime.now()
 32
    def __str__(self):
 33
        return '<SubtitleQueue(%s=%s)>' % (self.feed, self.imdb_id)
 35
TODO:
 37
 * add new option, retry: [n] days
 38
 * add everything into queue using above class
 39
 * consume queue (look up by feed name), configuration is available from feed
 40
 * remove successful downloads
 41
 * remove queue items that are part retry: n days
 43
"""
 45
log = logging.getLogger('subtitles')
 54
class Subtitles(object):
 55
    """
 56
    Fetch subtitles from opensubtitles.org
 57
    """
 59
    def validator(self):
 60
        from flexget import validator
 61
        subs = validator.factory('dict')
 62
        langs = subs.accept('list', key='languages')
 63
        langs.accept('text')
 64
        subs.accept('number', key='min_sub_rating')
 65
        subs.accept('number', key='match_limit')
 66
        subs.accept('path', key='output')
 67
        return subs
 69
    def get_config(self, feed):
 70
        config = feed.config['subtitles']
 71
        if not isinstance(config, dict):
 72
            config = {}
 73
        config.setdefault('output', feed.manager.config_base)
 74
        config.setdefault('languages', ['eng'])
 75
        config.setdefault('min_sub_rating', 0.0)
 76
        config.setdefault('match_limit', 0.8)
 77
        config['output'] = os.path.expanduser(config['output'])
 78
        return config
 80
    def on_feed_download(self, feed):
 83
        try:
 84
            entries = filter(lambda x: x['imdb_url'] is not None, feed.accepted)
 85
        except KeyError:
 88
            return
 90
        try:
 91
            s = ServerProxy("http://api.opensubtitles.org/xml-rpc")
 92
            res = s.LogIn("", "", "en", "FlexGet")
 93
        except:
 94
            log.warning('Error connecting to opensubtitles.org')
 95
            return
 97
        if res['status'] != '200 OK':
 98
            raise Exception("Login to opensubtitles.org XML-RPC interface failed")
100
        config = self.get_config(feed)
102
        token = res['token']
105
        languages = config['languages']
106
        min_sub_rating = config['min_sub_rating']
107
        match_limit = config['match_limit'] # no need to change this, but it should be configurable
110
        for entry in entries:
112
            m = re.search("tt(\d+)/$", entry['imdb_url'])
113
            if not m:
114
                log.debug("no match for %s" % entry['imdb_url'])
115
                continue
117
            imdbid = m.group(1)
119
            query = []
120
            for language in languages:
121
                query.append({'sublanguageid': language, 'imdbid': imdbid})
123
            subtitles = s.SearchSubtitles(token, query)
124
            subtitles = subtitles['data']
127
            if not subtitles:
128
                continue
131
            subtitles = filter(lambda x: x['SubBad'] == '0', subtitles)
133
            subtitles = filter(lambda x: float(x['SubRating']) >= min_sub_rating or float(x['SubRating']) == 0.0, subtitles)
135
            filtered_subs = []
138
            for language in languages:
139
                langsubs = filter(lambda x: x['SubLanguageID'] == language, subtitles)
142
                if langsubs:
144
                    def seqmatch(subfile):
145
                        s = difflib.SequenceMatcher(lambda x: x in " ._", entry['title'], subfile)
147
                        return s.ratio() > match_limit
150
                    langsubs = filter(lambda x: seqmatch(x['MovieReleaseName']), subtitles)
152
                    if langsubs:
154
                        langsubs.sort(key=lambda x: float(x['SubRating']))
155
                        langsubs.reverse()
156
                        filtered_subs.append(langsubs[0])
159
            for sub in filtered_subs:
160
                log.debug('SUBS FOUND: ', sub['MovieReleaseName'], sub['SubRating'], sub['SubLanguageID'])
162
                f = urlopener(sub['ZipDownloadLink'], log)
163
                subfilename = re.match('^attachment; filename="(.*)"$', f.info()['content-disposition']).group(1)
164
                outfile = os.path.join(config['output'], subfilename)
165
                fp = file(outfile, 'w')
166
                fp.write(f.read())
167
                fp.close()
168
                f.close()
170
        s.LogOut(token)
172
register_plugin(Subtitles, 'subtitles')