Exemplo n.º 1
0
    def doReplace(self, string, replacements, remove_multiple = False, use_separator = True):
        '''
        replace confignames with the real thing
        '''

        replacements = replacements.copy()
        if remove_multiple:
            replacements['cd'] = ''
            replacements['cd_nr'] = ''

        replaced = toUnicode(string)
        for x, r in replacements.iteritems():
            if r is not None:
                replaced = replaced.replace(u'<%s>' % toUnicode(x), toUnicode(r))
            else:
                #If information is not available, we don't want the tag in the filename
                replaced = replaced.replace('<' + x + '>', '')

        replaced = re.sub(r"[\x00:\*\?\"<>\|]", '', replaced)

        sep = ' '
        if use_separator:
            sep = self.conf('separator')

        return self.replaceDoubles(replaced).replace(' ', sep)
Exemplo n.º 2
0
    def add(self, path = '', part = 1, type_tuple = (), available = 1, properties = None):
        if not properties: properties = {}

        try:
            db = get_session()
            type_id = self.getType(type_tuple).get('id')

            f = db.query(File).filter(File.path == toUnicode(path)).first()
            if not f:
                f = File()
                db.add(f)

            f.path = toUnicode(path)
            f.part = part
            f.available = available
            f.type_id = type_id

            db.commit()

            file_dict = f.to_dict()

            return file_dict
        except:
            log.error('Failed adding file: %s, %s', (path, traceback.format_exc()))
            db.rollback()
        finally:
            db.close()
Exemplo n.º 3
0
def getParams():

    params = url_decode(getattr(flask.request, 'environ').get('QUERY_STRING', ''))
    reg = re.compile('^[a-z0-9_\.]+$')

    current = temp = {}
    for param, value in sorted(params.iteritems()):

        nest = re.split("([\[\]]+)", param)
        if len(nest) > 1:
            nested = []
            for key in nest:
                if reg.match(key):
                    nested.append(key)

            current = temp

            for item in nested:
                if item is nested[-1]:
                    current[item] = toUnicode(unquote(value))
                else:
                    try:
                        current[item]
                    except:
                        current[item] = {}

                    current = current[item]
        else:
            temp[param] = toUnicode(unquote(value))

    return dictToList(temp)
Exemplo n.º 4
0
    def notify(self, message = '', data = None, listener = None):
        if not data: data = {}

        # Get all the device IDs linked to this user
        devices = self.getDevices() or []
        successful = 0
        for device in devices:
            response = self.request(
                'pushes',
                cache = False,
                device_iden = device,
                type = 'note',
                title = self.default_title,
                body = toUnicode(message)
            )

            if response:
                successful += 1
            else:
                log.error('Unable to push notification to Pushbullet device with ID %s' % device)

        for channel in self.getChannels():
            response = self.request(
                'pushes',
                cache = False,
                channel_tag = channel,
                type = 'note',
                title = self.default_title,
                body = toUnicode(message)
            )

        return successful == len(devices)
Exemplo n.º 5
0
 def createNzbName(self, data, media):
     tag = self.cpTag(media)
     split_string = scanPassword(data.get('name'))
     if split_string[1] != None:
         return '%s%s{{%s}}' % (toSafeString(toUnicode(split_string[0])[:123 - len(tag) - len(split_string[1])]), tag, split_string[1])
     else:
         return '%s%s' % (toSafeString(toUnicode(data.get('name'))[:127 - len(tag)]), tag)
Exemplo n.º 6
0
    def parseMovie(self, movie):

        year = str(movie.get('released', 'none'))[:4]

        # Poster url
        poster = self.getImage(movie, type = 'poster')
        backdrop = self.getImage(movie, type = 'backdrop')

        # 1900 is the same as None
        if year == '1900' or year.lower() == 'none':
            year = None

        movie_data = {
            'id': int(movie.get('id', 0)),
            'titles': [toUnicode(movie.get('name'))],
            'images': {
                'posters': [poster],
                'backdrops': [backdrop],
            },
            'imdb': movie.get('imdb_id'),
            'year': year,
            'plot': movie.get('overview', ''),
            'tagline': '',
        }

        # Add alternative names
        for alt in ['original_name', 'alternative_name']:
            alt_name = toUnicode(movie.get(alt))
            if alt_name and not alt_name in movie_data['titles'] and alt_name.lower() != 'none' and alt_name != None:
                movie_data['titles'].append(alt_name)

        return movie_data
Exemplo n.º 7
0
    def add(self, attrs={}, update_after=True):

        db = get_session()

        l = db.query(Library).filter_by(identifier=attrs.get("identifier")).first()
        if not l:
            status = fireEvent("status.get", "needs_update", single=True)
            l = Library(
                year=attrs.get("year"),
                identifier=attrs.get("identifier"),
                plot=toUnicode(attrs.get("plot")),
                tagline=toUnicode(attrs.get("tagline")),
                status_id=status.get("id"),
            )

            title = LibraryTitle(
                title=toUnicode(attrs.get("title")), simple_title=self.simplifyTitle(attrs.get("title"))
            )

            l.titles.append(title)

            db.add(l)
            db.commit()

        # Update library info
        if update_after is not False:
            handle = fireEventAsync if update_after is "async" else fireEvent
            handle("library.update", identifier=l.identifier, default_title=attrs.get("title", ""))

        return l.to_dict(self.default_dict)
Exemplo n.º 8
0
    def notify(self, message = '', data = None, listener = None):
        if not data: data = {}

        api_data = {
            'user': self.conf('user_key'),
            'token': self.conf('api_token'),
            'message': toUnicode(message),
            'priority': self.conf('priority'),
            'sound': self.conf('sound'),
        }

        if data and getIdentifier(data):
            api_data.update({
                'url': toUnicode('http://www.imdb.com/title/%s/' % getIdentifier(data)),
                'url_title': toUnicode('%s on IMDb' % getTitle(data)),
            })

        try:
            data = self.urlopen('%s/%s' % (self.api_url, '1/messages.json'),
                headers = {'Content-type': 'application/x-www-form-urlencoded'},
                data = api_data)
            log.info2('Pushover responded with: %s', data)
            return True
        except:
            return False
Exemplo n.º 9
0
    def notify(self, message = '', data = None, listener = None):
        if not data: data = {}

        try:
            message = message.strip()

            long_message = ''
            if listener == 'test':
                long_message = 'This is a test message'
            elif data.get('identifier'):
                long_message = 'More movie info <a href="http://www.imdb.com/title/%s/">on IMDB</a>' % data['identifier']

            data = {
                'user_credentials': self.conf('token'),
                'notification[title]': toUnicode('%s - %s' % (self.default_title, message)),
                'notification[long_message]': toUnicode(long_message),
            }

            self.urlopen(self.url, data = data)
        except:
            log.error('Make sure the token provided is for the correct device')
            return False

        log.info('Boxcar notification successful.')
        return True
Exemplo n.º 10
0
def getParams(params):

    reg = re.compile('^[a-z0-9_\.]+$')

    current = temp = {}
    for param, value in sorted(params.iteritems()):

        nest = re.split("([\[\]]+)", param)
        if len(nest) > 1:
            nested = []
            for key in nest:
                if reg.match(key):
                    nested.append(key)

            current = temp

            for item in nested:
                if item is nested[-1]:
                    current[item] = toUnicode(unquote(value))
                else:
                    try:
                        current[item]
                    except:
                        current[item] = {}

                    current = current[item]
        else:
            temp[param] = toUnicode(unquote(value))

    return dictToList(temp)
Exemplo n.º 11
0
    def calculate(self, nzb, movie):
        ''' Calculate the score of a NZB, used for sorting later '''

        score = nameScore(toUnicode(nzb['name']), movie['library']['year'])

        for movie_title in movie['library']['titles']:
            score += nameRatioScore(toUnicode(nzb['name']), toUnicode(movie_title['title']))

        score += sizeScore(nzb['size'])

        # Torrents only
        if nzb.get('seeds'):
            try:
                score += nzb.get('seeds') / 5
                score += nzb.get('leechers') / 10
            except:
                pass

        # Provider score
        score += providerScore(nzb['provider'])

        # Duplicates in name
        score += duplicateScore(nzb['name'], movie['library']['titles'][0]['title'])

        return score
Exemplo n.º 12
0
    def notify(self, message = '', data = {}, listener = None):

        http_handler = HTTPSConnection("api.pushover.net:443")

        api_data = {
            'user': self.conf('user_key'),
            'token': self.app_token,
            'message': toUnicode(message),
            'priority': self.conf('priority'),
        }

        if data and data.get('library'):
            api_data.extend({
                'url': toUnicode('http://www.imdb.com/title/%s/' % data['library']['identifier']),
                'url_title': toUnicode('%s on IMDb' % getTitle(data['library'])),
            })

        http_handler.request('POST',
            "/1/messages.json",
            headers = {'Content-type': 'application/x-www-form-urlencoded'},
            body = tryUrlencode(api_data)
        )

        response = http_handler.getresponse()
        request_status = response.status

        if request_status == 200:
            log.info('Pushover notifications sent.')
            return True
        elif request_status == 401:
            log.error('Pushover auth failed: %s', response.reason)
            return False
        else:
            log.error('Pushover notification failed.')
            return False
Exemplo n.º 13
0
    def add(self, attrs = {}, update_after = True):

        db = get_session()

        l = db.query(Library).filter_by(identifier = attrs.get('identifier')).first()
        if not l:
            status = fireEvent('status.get', 'needs_update', single = True)
            l = Library(
                year = attrs.get('year'),
                identifier = attrs.get('identifier'),
                plot = toUnicode(attrs.get('plot')),
                tagline = toUnicode(attrs.get('tagline')),
                status_id = status.get('id')
            )

            title = LibraryTitle(
                title = toUnicode(attrs.get('title')),
                simple_title = self.simplifyTitle(attrs.get('title')),
            )

            l.titles.append(title)

            db.add(l)
            db.commit()

        # Update library info
        if update_after is not False:
            handle = fireEventAsync if update_after is 'async' else fireEvent
            handle('library.update', identifier = l.identifier, default_title = toUnicode(attrs.get('title', '')))

        library_dict = l.to_dict(self.default_dict)

        return library_dict
Exemplo n.º 14
0
    def fill(self):

        try:
            db = get_session()

            order = 0
            for q in self.qualities:

                # Create quality
                qual = db.query(Quality).filter_by(identifier = q.get('identifier')).first()

                if not qual:
                    log.info('Creating quality: %s', q.get('label'))
                    qual = Quality()
                    qual.order = order
                    qual.identifier = q.get('identifier')
                    qual.label = toUnicode(q.get('label'))
                    qual.size_min, qual.size_max = q.get('size')

                    db.add(qual)

                # Create single quality profile
                prof = db.query(Profile).filter(
                    Profile.core == True
                ).filter(
                    Profile.types.any(quality = qual)
                ).all()

                if not prof:
                    log.info('Creating profile: %s', q.get('label'))
                    prof = Profile(
                        core = True,
                        label = toUnicode(qual.label),
                        order = order
                    )
                    db.add(prof)

                    profile_type = ProfileType(
                        quality = qual,
                        profile = prof,
                        finish = True,
                        order = 0
                    )
                    prof.types.append(profile_type)

                order += 1

            db.commit()

            time.sleep(0.3) # Wait a moment

            return True
        except:
            log.error('Failed: %s', traceback.format_exc())
            db.rollback()
        finally:
            db.close()

        return False
Exemplo n.º 15
0
 def process_bind_param(self, value, dialect):
     try:
         return toUnicode(json.dumps(value, cls = SetEncoder))
     except:
         try:
             return toUnicode(json.dumps(value, cls = SetEncoder, encoding = 'latin-1'))
         except:
             raise
Exemplo n.º 16
0
    def list(self, status = ['active'], limit_offset = None, starts_with = None, search = None):

        db = get_session()

        # Make a list from string
        if not isinstance(status, (list, tuple)):
            status = [status]


        q = db.query(Movie) \
            .join(Movie.library, Library.titles) \
            .options(joinedload_all('releases.status')) \
            .options(joinedload_all('releases.quality')) \
            .options(joinedload_all('releases.files')) \
            .options(joinedload_all('releases.info')) \
            .options(joinedload_all('library.titles')) \
            .options(joinedload_all('library.files')) \
            .options(joinedload_all('status')) \
            .options(joinedload_all('files')) \
            .filter(LibraryTitle.default == True) \
            .filter(or_(*[Movie.status.has(identifier = s) for s in status]))

        filter_or = []
        if starts_with:
            starts_with = toUnicode(starts_with.lower())
            if starts_with in ascii_lowercase:
                filter_or.append(LibraryTitle.simple_title.startswith(starts_with))
            else:
                ignore = []
                for letter in ascii_lowercase:
                    ignore.append(LibraryTitle.simple_title.startswith(toUnicode(letter)))
                filter_or.append(not_(or_(*ignore)))

        if search:
            filter_or.append(LibraryTitle.simple_title.like('%%' + search + '%%'))

        if filter_or:
            q = q.filter(or_(*filter_or))

        q = q.order_by(asc(LibraryTitle.simple_title))

        if limit_offset:
            splt = limit_offset.split(',')
            limit = splt[0]
            offset = 0 if len(splt) is 1 else splt[1]
            q = q.limit(limit).offset(offset)

        results = q.all()

        movies = []
        for movie in results:
            temp = movie.to_dict(self.default_dict)
            movies.append(temp)

        return movies
Exemplo n.º 17
0
    def setProperty(self, identifier, value=""):
        from couchpotato import get_db

        db = get_db()

        try:
            p = db.get("property", identifier, with_doc=True)
            p["doc"].update({"identifier": identifier, "value": toUnicode(value)})
            db.update(p["doc"])
        except:
            db.insert({"_t": "property", "identifier": identifier, "value": toUnicode(value)})
Exemplo n.º 18
0
    def getNfo(self, data):
        nfoxml = Element('movie')

        types = ['rating', 'year', 'votes', 'rating', 'mpaa', 'originaltitle:original_title', 'outline:plot', 'premiered:released']

        # Title
        try:
            el = SubElement(nfoxml, 'title')
            el.text = toUnicode(data['library']['titles'][0]['title'])
        except:
            pass

        # IMDB id
        try:
            el = SubElement(nfoxml, 'id')
            el.text = toUnicode(data['library']['identifier'])
        except:
            pass

        # Runtime
        try:
            runtime = SubElement(nfoxml, 'runtime')
            runtime.text = '%s min' % data['library']['runtime']
        except:
            pass

        # Other values
        for type in types:

            if ':' in type:
                name, type = type.split(':')
            else:
                name = type

            try:
                if data['library'].get(type):
                    el = SubElement(nfoxml, name)
                    el.text = toUnicode(data['library'].get(type, ''))
            except:
                pass

        # Genre
        for genre in data['library'].get('genres', []):
            genres = SubElement(nfoxml, 'genre')
            genres.text = genre.get('name')


        # Clean up the xml and return it
        nfoxml = xml.dom.minidom.parseString(tostring(nfoxml))
        xml_string = nfoxml.toprettyxml(indent = '  ')
        text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
        xml_string = text_re.sub('>\g<1></', xml_string)

        return xml_string.encode('utf-8')
Exemplo n.º 19
0
    def notify(self, message = '', data = None, listener = None):
        if not data: data = {}

        # Extract all the settings from settings
        from_address = self.conf('from')
        to_address = self.conf('to')
        ssl = self.conf('ssl')
        smtp_server = self.conf('smtp_server')
        smtp_user = self.conf('smtp_user')
        smtp_pass = self.conf('smtp_pass')
        smtp_port = self.conf('smtp_port')
        starttls = self.conf('starttls')

        # Make the basic message
        email = MIMEText(toUnicode(message), _charset = Env.get('encoding'))
        email['Subject'] = '%s: %s' % (self.default_title, toUnicode(message))
        email['From'] = from_address
        email['To'] = to_address
        email['Date'] = formatdate(localtime = 1)
        email['Message-ID'] = make_msgid()

        try:
            # Open the SMTP connection, via SSL if requested
            log.debug("Connecting to host %s on port %s" % (smtp_server, smtp_port))
            log.debug("SMTP over SSL %s", ("enabled" if ssl == 1 else "disabled"))
            mailserver = smtplib.SMTP_SSL(smtp_server, smtp_port) if ssl == 1 else smtplib.SMTP(smtp_server, smtp_port)

            if starttls:
                log.debug("Using StartTLS to initiate the connection with the SMTP server")
                mailserver.starttls()

            # Say hello to the server
            mailserver.ehlo()

            # Check too see if an login attempt should be attempted
            if len(smtp_user) > 0:
                log.debug("Logging on to SMTP server using username \'%s\'%s", (smtp_user, " and a password" if len(smtp_pass) > 0 else ""))
                mailserver.login(smtp_user.encode('utf-8'), smtp_pass.encode('utf-8'))

            # Send the e-mail
            log.debug("Sending the email")
            mailserver.sendmail(from_address, splitString(to_address), email.as_string())

            # Close the SMTP connection
            mailserver.quit()

            log.info('Email notification sent')

            return True
        except:
            log.error('E-mail failed: %s', traceback.format_exc())

        return False
Exemplo n.º 20
0
    def createMetaName(self, basename, name, root):
        detected = detect(root)
        if detected.get('encoding') == 'ISO-8859-2':
          root = toUnicode(root);
          log.info('encoding root: %s %s', (root, detected.get('encoding')))

        detected = detect(name)
        if detected.get('encoding') == 'ISO-8859-2':
          name = toUnicode(name);
          log.info('encoding name: %s %s', (name, detected.get('encoding')))
    
        return os.path.join(root, basename.replace('%s', name))
Exemplo n.º 21
0
    def fill(self):

        db = get_session()

        for identifier, label in self.statuses.iteritems():
            s = db.query(Status).filter_by(identifier=identifier).first()
            if not s:
                log.info("Creating status: %s", label)
                s = Status(identifier=identifier, label=toUnicode(label))
                db.add(s)

            s.label = toUnicode(label)
            db.commit()
Exemplo n.º 22
0
    def calculate(self, nzb, movie):
        """ Calculate the score of a NZB, used for sorting later """

        # Merge global and category
        preferred_words = splitString(Env.setting('preferred_words', section = 'searcher').lower())
        try: preferred_words = list(set(preferred_words + splitString(movie['category']['preferred'].lower())))
        except: pass

        score = nameScore(toUnicode(nzb['name']), movie['library']['year'], preferred_words)

        for movie_title in movie['library']['titles']:
            score += nameRatioScore(toUnicode(nzb['name']), toUnicode(movie_title['title']))
            score += namePositionScore(toUnicode(nzb['name']), toUnicode(movie_title['title']))

        score += sizeScore(nzb['size'])

        # Torrents only
        if nzb.get('seeders'):
            try:
                score += nzb.get('seeders') * 100 / 15
                score += nzb.get('leechers') * 100 / 30
            except:
                pass

        # Provider score
        score += providerScore(nzb['provider'])

        # Duplicates in name
        score += duplicateScore(nzb['name'], getTitle(movie['library']))

        # Merge global and category
        ignored_words = splitString(Env.setting('ignored_words', section = 'searcher').lower())
        try: ignored_words = list(set(ignored_words + splitString(movie['category']['ignored'].lower())))
        except: pass

        # Partial ignored words
        score += partialIgnoredScore(nzb['name'], getTitle(movie['library']), ignored_words)

        # Ignore single downloads from multipart
        score += halfMultipartScore(nzb['name'])

        # Extra provider specific check
        extra_score = nzb.get('extra_score')
        if extra_score:
            score += extra_score(nzb)

        # Scene / Nuke scoring
        score += sceneScore(nzb['name'])

        return score
Exemplo n.º 23
0
    def fill(self):

        db = get_session();

        order = 0
        for q in self.qualities:

            # Create quality
            quality = db.query(Quality).filter_by(identifier = q.get('identifier')).first()

            if not quality:
                log.info('Creating quality: %s', q.get('label'))
                quality = Quality()
                db.add(quality)

            quality.order = order
            quality.identifier = q.get('identifier')
            quality.label = toUnicode(q.get('label'))
            quality.size_min, quality.size_max = q.get('size')

            # Create single quality profile
            profile = db.query(Profile).filter(
                    Profile.core == True
                ).filter(
                    Profile.types.any(quality = quality)
                ).all()

            if not profile:
                log.info('Creating profile: %s', q.get('label'))
                profile = Profile(
                    core = True,
                    label = toUnicode(quality.label),
                    order = order
                )
                db.add(profile)

                profile_type = ProfileType(
                    quality = quality,
                    profile = profile,
                    finish = True,
                    order = 0
                )
                profile.types.append(profile_type)

            order += 1
            db.commit()

        #db.close()
        return True
Exemplo n.º 24
0
    def getType(self, type):

        db = get_session()
        type, identifier = type

        ft = db.query(FileType).filter_by(identifier=identifier).first()
        if not ft:
            ft = FileType(
                type=toUnicode(type), identifier=identifier, name=toUnicode(identifier[0].capitalize() + identifier[1:])
            )

            db.add(ft)
            db.commit()

        return ft
Exemplo n.º 25
0
    def safeMessage(self, msg, replace_tuple = ()):

        from couchpotato.core.helpers.encoding import ss, toUnicode

        msg = ss(msg)

        try:
            if isinstance(replace_tuple, tuple):
                msg = msg % tuple([ss(x) if not isinstance(x, (int, float)) else x for x in list(replace_tuple)])
            elif isinstance(replace_tuple, dict):
                msg = msg % dict((k, ss(v)) for k, v in replace_tuple.iteritems())
            else:
                msg = msg % ss(replace_tuple)
        except Exception as e:
            self.logger.error('Failed encoding stuff to log "%s": %s' % (msg, e))

        self.setup()
        if not self.is_develop:

            for replace in self.replace_private:
                msg = re.sub('(\?%s=)[^\&]+' % replace, '?%s=xxx' % replace, msg)
                msg = re.sub('(&%s=)[^\&]+' % replace, '&%s=xxx' % replace, msg)

            # Replace api key
            try:
                api_key = self.Env.setting('api_key')
                if api_key:
                    msg = msg.replace(api_key, 'API_KEY')
            except:
                pass

        return toUnicode(msg)
Exemplo n.º 26
0
    def registerStatic(self, plugin_file, add_to_head = True):

        # Register plugin path
        self.plugin_path = os.path.dirname(plugin_file)
        static_folder = toUnicode(os.path.join(self.plugin_path, 'static'))

        if not os.path.isdir(static_folder):
            return

        # Get plugin_name from PluginName
        s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', self.__class__.__name__)
        class_name = re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower()

        # View path
        path = 'static/plugin/%s/' % class_name

        # Add handler to Tornado
        Env.get('app').add_handlers(".*$", [(Env.get('web_base') + path + '(.*)', StaticFileHandler, {'path': static_folder})])

        # Register for HTML <HEAD>
        if add_to_head:
            for f in glob.glob(os.path.join(self.plugin_path, 'static', '*')):
                ext = getExt(f)
                if ext in ['js', 'css']:
                    fireEvent('register_%s' % ('script' if ext in 'js' else 'style'), path + os.path.basename(f), f)
Exemplo n.º 27
0
    def notify(self, message = '', data = {}, listener = None):
        if self.isDisabled(): return

        try:
            params = {
                'label': self.default_title,
                'msg': toUnicode(message),
            }

            headers = {
                'Authorization': "Basic %s" % base64.encodestring('%s:%s' % (self.conf('username'), self.conf('api_key')))[:-1]
            }

            handle = self.urlopen(self.url, params = params, headers = headers)
            result = json.loads(handle)

            if result['status'] != 'success' or result['response_message'] != 'OK':
                raise Exception

        except:
            log.error('Notification failed: %s', traceback.format_exc())
            return False

        log.info('Notifo notification successful.')
        return True
Exemplo n.º 28
0
    def _searchOnTitle(self, title, movie, quality, results):

        q = '%s %s' % (title, movie['library']['year'])
        params = tryUrlencode({
            'search': q,
            'catid': ','.join([str(x) for x in self.getCatId(quality['identifier'])]),
            'user': self.conf('username', default = ''),
            'api': self.conf('api_key', default = ''),
        })

        nzbs = self.getRSSData(self.urls['search'] % params)

        for nzb in nzbs:

            enclosure = self.getElement(nzb, 'enclosure').attrib
            nzb_id = parse_qs(urlparse(self.getTextElement(nzb, 'link')).query).get('id')[0]

            results.append({
                'id': nzb_id,
                'name': toUnicode(self.getTextElement(nzb, 'title')),
                'age': self.calculateAge(int(time.mktime(parse(self.getTextElement(nzb, 'pubDate')).timetuple()))),
                'size': tryInt(enclosure['length']) / 1024 / 1024,
                'url': enclosure['url'],
                'detail_url': self.urls['detail_url'] % nzb_id,
                'description': self.getTextElement(nzb, 'description')
            })
Exemplo n.º 29
0
    def get(self, identifiers):

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

        db = get_session()
        return_list = []

        for identifier in identifiers:

            if self.status_cached.get(identifier):
                return_list.append(self.status_cached.get(identifier))
                continue

            s = db.query(Status).filter_by(identifier=identifier).first()
            if not s:
                s = Status(identifier=identifier, label=toUnicode(identifier.capitalize()))
                db.add(s)
                db.commit()

            status_dict = s.to_dict()

            self.status_cached[identifier] = status_dict
            return_list.append(status_dict)

        return return_list if len(identifiers) > 1 else return_list[0]
Exemplo n.º 30
0
    def _searchOnHost(self, host, media, quality, results):

        torrents = self.getJsonData(self.buildUrl(media, host), cache_timeout = 1800)

        if torrents:
            try:
                if torrents.get('error'):
                    log.error('%s: %s', (torrents.get('error'), host['host']))
                elif torrents.get('results'):
                    for torrent in torrents.get('results', []):
                        results.append({
                            'id': torrent.get('torrent_id'),
                            'protocol': 'torrent' if re.match('^(http|https|ftp)://.*$', torrent.get('download_url')) else 'torrent_magnet',
                            'provider_extra': urlparse(host['host']).hostname or host['host'],
                            'name': toUnicode(torrent.get('release_name')),
                            'url': torrent.get('download_url'),
                            'detail_url': torrent.get('details_url'),
                            'size': torrent.get('size'),
                            'score': host['extra_score'],
                            'seeders': torrent.get('seeders'),
                            'leechers': torrent.get('leechers'),
                            'seed_ratio': host['seed_ratio'],
                            'seed_time': host['seed_time'],
                        })

            except:
                log.error('Failed getting results from %s: %s', (host['host'], traceback.format_exc()))
Exemplo n.º 31
0
    def cleanup(self):

        # Wait a bit after starting before cleanup
        time.sleep(3)
        log.debug('Cleaning up unused files')

        python_cache = Env.get('cache')._path
        try:
            db = get_session()
            for root, dirs, walk_files in os.walk(Env.get('cache_dir')):
                for filename in walk_files:
                    if os.path.splitext(filename)[1] in [
                            '.png', '.jpg', '.jpeg'
                    ]:
                        file_path = os.path.join(root, filename)
                        f = db.query(File).filter(
                            File.path == toUnicode(file_path)).first()
                        if not f:
                            os.remove(file_path)
        except:
            log.error('Failed removing unused file: %s',
                      traceback.format_exc())
Exemplo n.º 32
0
    def getSubtitleLanguage(self, group):
        detected_languages = {}

        # Subliminal scanner
        try:
            paths = group['files']['movie']
            scan_result = []
            for p in paths:
                if not group['is_dvd']:
                    video = Video.from_path(toUnicode(p))
                    video_result = [(video, video.scan())]
                    scan_result.extend(video_result)

            for video, detected_subtitles in scan_result:
                for s in detected_subtitles:
                    if s.language and s.path not in paths:
                        detected_languages[s.path] = [s.language]
        except:
            log.debug('Failed parsing subtitle languages for %s: %s',
                      (paths, traceback.format_exc()))

        # IDX
        for extra in group['files']['subtitle_extra']:
            try:
                if os.path.isfile(extra):
                    output = open(extra, 'r')
                    txt = output.read()
                    output.close()

                    idx_langs = re.findall('\nid: (\w+)', txt)

                    sub_file = '%s.sub' % os.path.splitext(extra)[0]
                    if len(idx_langs) > 0 and os.path.isfile(sub_file):
                        detected_languages[sub_file] = idx_langs
            except:
                log.error('Failed parsing subtitle idx for %s: %s',
                          (extra, traceback.format_exc()))

        return detected_languages
Exemplo n.º 33
0
    def notify(self, message='', data={}, listener=None):

        data = {
            'apikey': self.conf('api_key'),
            'application': self.default_title,
            'description': toUnicode(message),
            'priority': self.conf('priority'),
        }
        headers = {'Content-type': 'application/x-www-form-urlencoded'}

        try:
            self.urlopen(self.urls['api'],
                         headers=headers,
                         params=data,
                         multipart=True,
                         show_error=False)
            log.info('Prowl notifications sent.')
            return True
        except:
            log.error('Prowl failed: %s', traceback.format_exc())

        return False
Exemplo n.º 34
0
    def edit(self):

        params = getParams()
        db = get_session()

        available_status = fireEvent('status.get', 'available', single = True)

        ids = [x.strip() for x in params.get('id').split(',')]
        for movie_id in ids:

            m = db.query(Movie).filter_by(id = movie_id).first()
            if not m:
                continue

            m.profile_id = params.get('profile_id')

            # Remove releases
            for rel in m.releases:
                if rel.status_id is available_status.get('id'):
                    db.delete(rel)
                    db.commit()

            # Default title
            if params.get('default_title'):
                for title in m.library.titles:
                    title.default = toUnicode(params.get('default_title', '')).lower() == toUnicode(title.title).lower()

            db.commit()

            fireEvent('movie.restatus', m.id)

            movie_dict = m.to_dict(self.default_dict)
            fireEventAsync('searcher.single', movie_dict, on_complete = self.createNotifyFront(movie_id))

        #db.close()
        return jsonified({
            'success': True,
        })
Exemplo n.º 35
0
    def save(self):

        params = getParams()

        db = get_session()

        p = db.query(Profile).filter_by(id = params.get('id')).first()
        if not p:
            p = Profile()
            db.add(p)

        p.label = toUnicode(params.get('label'))
        p.order = params.get('order', p.order if p.order else 0)
        p.core = params.get('core', False)

        #delete old types
        [db.delete(t) for t in p.types]

        order = 0
        for type in params.get('types', []):
            t = ProfileType(
                order = order,
                finish = type.get('finish') if order > 0 else 1,
                wait_for = params.get('wait_for'),
                quality_id = type.get('quality_id')
            )
            p.types.append(t)

            order += 1

        db.commit()

        profile_dict = p.to_dict(self.to_dict)

        return jsonified({
            'success': True,
            'profile': profile_dict
        })
Exemplo n.º 36
0
    def partial(self):

        log_type = getParam('type', 'all')
        total_lines = tryInt(getParam('lines', 30))

        log_lines = []

        for x in range(0, 50):

            path = '%s%s' % (Env.get('log_path'), '.%s' % x if x > 0 else '')

            # Check see if the log exists
            if not os.path.isfile(path):
                break

            reversed_lines = []
            f = open(path, 'r')
            reversed_lines = toUnicode(f.read()).split('[0m\n')
            reversed_lines.reverse()

            brk = False
            for line in reversed_lines:

                if log_type == 'all' or '%s ' % log_type.upper() in line:
                    log_lines.append(line)

                if len(log_lines) >= total_lines:
                    brk = True
                    break

            if brk:
                break

        log_lines.reverse()
        return jsonified({
            'success': True,
            'log': '[0m\n'.join(log_lines),
        })
Exemplo n.º 37
0
    def searchSingle(self, group):

        if self.isDisabled(): return

        try:
            available_languages = sum(group['subtitle_language'].itervalues(),
                                      [])
            downloaded = []
            files = [toUnicode(x) for x in group['files']['movie']]
            log.debug('Searching for subtitles for: %s', files)

            for lang in self.getLanguages():
                if lang not in available_languages:
                    download = subliminal.download_subtitles(
                        files,
                        multi=True,
                        force=False,
                        languages=[lang],
                        services=self.services,
                        cache_dir=Env.get('cache_dir'))
                    for subtitle in download:
                        downloaded.extend(download[subtitle])

            for d_sub in downloaded:
                log.info('Found subtitle (%s): %s',
                         (d_sub.language.alpha2, files))
                group['files']['subtitle'].append(d_sub.path)
                group['subtitle_language'][d_sub.path] = [
                    d_sub.language.alpha2
                ]

            return True

        except:
            log.error('Failed searching for subtitle: %s',
                      (traceback.format_exc()))

        return False
Exemplo n.º 38
0
    def _searchOnTitle(self, title, movie, quality, results):

        q = '%s %s' % (title, movie['info']['year'])
        params = tryUrlencode({
            'search':
            q,
            'catid':
            ','.join([str(x) for x in self.getCatId(quality)]),
            'user':
            self.conf('username', default=''),
            'api':
            self.conf('api_key', default=''),
        })

        if len(self.conf('custom_tag')) > 0:
            params = '%s&%s' % (params, self.conf('custom_tag'))

        nzbs = self.getJsonData(self.urls['search'] % params)

        if isinstance(nzbs, list):
            for nzb in nzbs:

                results.append({
                    'id':
                    nzb.get('nzbid'),
                    'name':
                    toUnicode(nzb.get('release')),
                    'age':
                    self.calculateAge(tryInt(nzb.get('usenetage'))),
                    'size':
                    tryInt(nzb.get('sizebytes')) / 1024 / 1024,
                    'url':
                    nzb.get('getnzb'),
                    'detail_url':
                    nzb.get('details'),
                    'description':
                    nzb.get('weblink')
                })
Exemplo n.º 39
0
    def cleanup(self):

        # Wait a bit after starting before cleanup
        log.debug('Cleaning up unused files')

        try:
            db = get_db()
            cache_dir = Env.get('cache_dir')
            medias = db.all('media', with_doc = True)

            files = []
            for media in medias:
                file_dict = media['doc'].get('files', {})
                for x in file_dict.keys():
                    files.extend(file_dict[x])

            for f in os.listdir(cache_dir):
                if os.path.splitext(f)[1] in ['.png', '.jpg', '.jpeg']:
                    file_path = os.path.join(cache_dir, f)
                    if toUnicode(file_path) not in files:
                        os.remove(file_path)
        except:
            log.error('Failed removing unused file: %s', traceback.format_exc())
Exemplo n.º 40
0
    def notify(self, message = '', data = None, listener = None):
        if not data: data = {}

        data = {
            'action': "send",
            'uri': "",
            'title': self.default_title,
            'message': toUnicode(message),
            'broadcast': self.conf('broadcast'),
            'username': self.conf('username'),
        }

        headers = {
            'Content-type': 'application/x-www-form-urlencoded'
        }

        try:
            self.urlopen(self.conf('url'), headers = headers, data = data, show_error = False)
            return True
        except:
            log.error('AndroidPN failed: %s', traceback.format_exc())

        return False
Exemplo n.º 41
0
    def edit(self, id = '', **kwargs):

        db = get_session()

        available_status = fireEvent('status.get', 'available', single = True)

        ids = splitString(id)
        for movie_id in ids:

            m = db.query(Movie).filter_by(id = movie_id).first()
            if not m:
                continue

            m.profile_id = kwargs.get('profile_id')

            # Remove releases
            for rel in m.releases:
                if rel.status_id is available_status.get('id'):
                    db.delete(rel)
                    db.commit()

            # Default title
            if kwargs.get('default_title'):
                for title in m.library.titles:
                    title.default = toUnicode(kwargs.get('default_title', '')).lower() == toUnicode(title.title).lower()

            db.commit()

            fireEvent('movie.restatus', m.id)

            movie_dict = m.to_dict(self.default_dict)
            fireEventAsync('searcher.single', movie_dict, on_complete = self.createNotifyFront(movie_id))

        db.expire_all()
        return {
            'success': True,
        }
Exemplo n.º 42
0
    def notify(self, message='', data=None, listener=None):
        if not data: data = {}

        try:
            db = get_session()

            data['notification_type'] = listener if listener else 'unknown'

            n = Notif(message=toUnicode(message), data=data)
            db.add(n)
            db.commit()

            ndict = n.to_dict()
            ndict['type'] = 'notification'
            ndict['time'] = time.time()

            self.frontend(type=listener, data=data)

            return True
        except:
            log.error('Failed notify: %s', traceback.format_exc())
            db.rollback()
        finally:
            db.close()
Exemplo n.º 43
0
    def partial(self, type='all', lines=30, **kwargs):

        total_lines = tryInt(lines)

        log_lines = []

        for x in range(0, 50):

            path = '%s%s' % (Env.get('log_path'), '.%s' % x if x > 0 else '')

            # Check see if the log exists
            if not os.path.isfile(path):
                break

            f = open(path, 'r')
            reversed_lines = toUnicode(f.read()).split('[0m\n')
            reversed_lines.reverse()

            brk = False
            for line in reversed_lines:

                if type == 'all' or '%s ' % type.upper() in line:
                    log_lines.append(line)

                if len(log_lines) >= total_lines:
                    brk = True
                    break

            if brk:
                break

        log_lines.reverse()
        return {
            'success': True,
            'log': '[0m\n'.join(log_lines),
        }
Exemplo n.º 44
0
    def safeMessage(self, msg, replace_tuple=()):

        from couchpotato.core.helpers.encoding import ss, toUnicode

        msg = ss(msg)

        try:
            msg = msg % replace_tuple
        except:
            try:
                if isinstance(replace_tuple, tuple):
                    msg = msg % tuple([ss(x) for x in list(replace_tuple)])
                else:
                    msg = msg % ss(replace_tuple)
            except Exception as e:
                self.logger.error('Failed encoding stuff to log "%s": %s' %
                                  (msg, e))

        self.setup()
        if not self.is_develop:

            for replace in self.replace_private:
                msg = re.sub('(\?%s=)[^\&]+' % replace, '?%s=xxx' % replace,
                             msg)
                msg = re.sub('(&%s=)[^\&]+' % replace, '&%s=xxx' % replace,
                             msg)

            # Replace api key
            try:
                api_key = self.Env.setting('api_key')
                if api_key:
                    msg = msg.replace(api_key, 'API_KEY')
            except:
                pass

        return toUnicode(msg)
Exemplo n.º 45
0
    def notify(self, message='', data=None, listener=None):
        if not data: data = {}

        url = self.conf('url')

        if not url:
            log.error('Please provide the URL')
            return False

        post_data = {
            'type': listener,
            'movie': getTitle(data)
            if listener != 'test' else 'Test Movie Title (2016)',
            'message': toUnicode(message)
        }

        try:
            self.urlopen(url, data=post_data, show_error=False)
            return True
        except:
            log.error('Webhook notification failed: %s',
                      traceback.format_exc())

        return False
Exemplo n.º 46
0
    def save(self, **kwargs):

        db = get_session()

        c = db.query(Category).filter_by(id=kwargs.get('id')).first()
        if not c:
            c = Category()
            db.add(c)

        c.order = kwargs.get('order', c.order if c.order else 0)
        c.label = toUnicode(kwargs.get('label'))
        c.path = toUnicode(kwargs.get('path'))
        c.ignored = toUnicode(kwargs.get('ignored'))
        c.preferred = toUnicode(kwargs.get('preferred'))
        c.required = toUnicode(kwargs.get('required'))
        c.destination = toUnicode(kwargs.get('destination'))

        db.commit()

        category_dict = c.to_dict()

        return {'success': True, 'category': category_dict}
Exemplo n.º 47
0
    def getDefaultTitle(
        self,
        info,
    ):

        # Set default title
        default_title = toUnicode(info.get('title'))
        titles = info.get('titles', [])
        counter = 0
        def_title = None
        for title in titles:
            if (len(default_title) == 0 and counter
                    == 0) or len(titles) == 1 or title.lower() == toUnicode(
                        default_title.lower()) or (
                            toUnicode(default_title) == six.u('')
                            and toUnicode(titles[0]) == title):
                def_title = toUnicode(title)
                break
            counter += 1

        if not def_title:
            def_title = toUnicode(titles[0])

        return def_title or 'UNKNOWN'
Exemplo n.º 48
0
 def createNzbName(self, data, movie):
     tag = self.cpTag(movie)
     return '%s%s' % (toSafeString(
         toUnicode(data.get('name'))[:127 - len(tag)]), tag)
Exemplo n.º 49
0
    def calculate(self, nzb, movie):
        """ Calculate the score of a NZB, used for sorting later """

        # Merge global and category
        preferred_words = splitString(
            Env.setting('preferred_words', section='searcher').lower())
        try:
            preferred_words = list(
                set(preferred_words +
                    splitString(movie['category']['preferred'].lower())))
        except:
            pass

        score = nameScore(toUnicode(nzb['name']), movie['library']['year'],
                          preferred_words)

        for movie_title in movie['library']['titles']:
            score += nameRatioScore(toUnicode(nzb['name']),
                                    toUnicode(movie_title['title']))
            score += namePositionScore(toUnicode(nzb['name']),
                                       toUnicode(movie_title['title']))

        score += sizeScore(nzb['size'])

        # Torrents only
        if nzb.get('seeders'):
            try:
                score += nzb.get('seeders') * 100 / 15
                score += nzb.get('leechers') * 100 / 30
            except:
                pass

        # Provider score
        score += providerScore(nzb['provider'])

        # Duplicates in name
        score += duplicateScore(nzb['name'], getTitle(movie['library']))

        # Merge global and category
        ignored_words = splitString(
            Env.setting('ignored_words', section='searcher').lower())
        try:
            ignored_words = list(
                set(ignored_words +
                    splitString(movie['category']['ignored'].lower())))
        except:
            pass

        # Partial ignored words
        score += partialIgnoredScore(nzb['name'], getTitle(movie['library']),
                                     ignored_words)

        # Ignore single downloads from multipart
        score += halfMultipartScore(nzb['name'])

        # Extra provider specific check
        extra_score = nzb.get('extra_score')
        if extra_score:
            score += extra_score(nzb)

        # Scene / Nuke scoring
        score += sceneScore(nzb['name'])

        return score
Exemplo n.º 50
0
    def parseMovie(self, movie, extended=True):

        # Do request, append other items
        movie = self.request(
            'movie/%s' % movie.get('id'), {
                'append_to_response':
                'alternative_titles' + (',images,casts' if extended else '')
            })
        if not movie:
            return

        # Images
        poster = self.getImage(movie, type='poster', size='w154')
        poster_original = self.getImage(movie, type='poster', size='original')
        backdrop_original = self.getImage(movie,
                                          type='backdrop',
                                          size='original')
        extra_thumbs = self.getMultImages(
            movie, type='backdrops', size='original') if extended else []

        images = {
            'poster': [poster] if poster else [],
            #'backdrop': [backdrop] if backdrop else [],
            'poster_original': [poster_original] if poster_original else [],
            'backdrop_original':
            [backdrop_original] if backdrop_original else [],
            'actors': {},
            'extra_thumbs': extra_thumbs
        }

        # Genres
        try:
            genres = [genre.get('name') for genre in movie.get('genres', [])]
        except:
            genres = []

        # 1900 is the same as None
        year = str(movie.get('release_date') or '')[:4]
        if not movie.get('release_date') or year == '1900' or year.lower(
        ) == 'none':
            year = None

        # Gather actors data
        actors = {}
        if extended:

            # Full data
            cast = movie.get('casts', {}).get('cast', [])

            for cast_item in cast:
                try:
                    actors[toUnicode(cast_item.get('name'))] = toUnicode(
                        cast_item.get('character'))
                    images['actors'][toUnicode(
                        cast_item.get('name'))] = self.getImage(
                            cast_item, type='profile', size='original')
                except:
                    log.debug('Error getting cast info for %s: %s',
                              (cast_item, traceback.format_exc()))

        movie_data = {
            'type': 'movie',
            'via_tmdb': True,
            'tmdb_id': movie.get('id'),
            'titles': [toUnicode(movie.get('title'))],
            'original_title': movie.get('original_title'),
            'images': images,
            'imdb': movie.get('imdb_id'),
            'runtime': movie.get('runtime'),
            'released': str(movie.get('release_date')),
            'year': tryInt(year, None),
            'plot': movie.get('overview'),
            'genres': genres,
            'collection': getattr(movie.get('belongs_to_collection'), 'name',
                                  None),
            'actor_roles': actors
        }

        movie_data = dict((k, v) for k, v in movie_data.items() if v)

        # Add alternative names
        if movie_data['original_title'] and movie_data[
                'original_title'] not in movie_data['titles']:
            movie_data['titles'].append(movie_data['original_title'])

        # Add alternative titles
        alternate_titles = movie.get('alternative_titles',
                                     {}).get('titles', [])

        for alt in alternate_titles:
            alt_name = alt.get('title')
            if alt_name and alt_name not in movie_data[
                    'titles'] and alt_name.lower(
                    ) != 'none' and alt_name is not None:
                movie_data['titles'].append(alt_name)

        return movie_data
Exemplo n.º 51
0
 def getUnicode(self, section, option):
     value = self.p.get(section, option).decode('unicode_escape')
     return toUnicode(value).strip()
Exemplo n.º 52
0
    def single(self, movie):

        done_status = fireEvent('status.get', 'done', single=True)

        if not movie['profile'] or movie['status_id'] == done_status.get('id'):
            log.debug(
                'Movie doesn\'t have a profile or already done, assuming in manage tab.'
            )
            return

        db = get_session()

        pre_releases = fireEvent('quality.pre_releases', single=True)
        release_dates = fireEvent('library.update_release_date',
                                  identifier=movie['library']['identifier'],
                                  merge=True)
        available_status = fireEvent('status.get', 'available', single=True)
        ignored_status = fireEvent('status.get', 'ignored', single=True)

        default_title = getTitle(movie['library'])
        if not default_title:
            log.error(
                'No proper info found for movie, removing it from library to cause it from having more issues.'
            )
            fireEvent('movie.delete', movie['id'], single=True)
            return

        fireEvent('notify.frontend',
                  type='searcher.started.%s' % movie['id'],
                  data=True,
                  message='Searching for "%s"' % default_title)

        ret = False
        for quality_type in movie['profile']['types']:
            if not self.couldBeReleased(quality_type['quality']['identifier'],
                                        release_dates, pre_releases):
                log.info(
                    'Too early to search for %s, %s',
                    (quality_type['quality']['identifier'], default_title))
                continue

            has_better_quality = 0

            # See if better quality is available
            for release in movie['releases']:
                if release['quality']['order'] <= quality_type['quality'][
                        'order'] and release['status_id'] not in [
                            available_status.get('id'),
                            ignored_status.get('id')
                        ]:
                    has_better_quality += 1

            # Don't search for quality lower then already available.
            if has_better_quality is 0:

                log.info('Search for %s in %s',
                         (default_title, quality_type['quality']['label']))
                quality = fireEvent(
                    'quality.single',
                    identifier=quality_type['quality']['identifier'],
                    single=True)

                results = fireEvent('yarr.search', movie, quality, merge=True)

                sorted_results = sorted(results,
                                        key=lambda k: k['score'],
                                        reverse=True)
                if len(sorted_results) == 0:
                    log.debug(
                        'Nothing found for %s in %s',
                        (default_title, quality_type['quality']['label']))

                download_preference = self.conf('preferred_method')
                if download_preference != 'both':
                    sorted_results = sorted(
                        sorted_results,
                        key=lambda k: k['type'],
                        reverse=(download_preference == 'torrent'))

                # Check if movie isn't deleted while searching
                if not db.query(Movie).filter_by(id=movie.get('id')).first():
                    break

                # Add them to this movie releases list
                for nzb in sorted_results:

                    rls = db.query(Release).filter_by(
                        identifier=md5(nzb['url'])).first()
                    if not rls:
                        rls = Release(
                            identifier=md5(nzb['url']),
                            movie_id=movie.get('id'),
                            quality_id=quality_type.get('quality_id'),
                            status_id=available_status.get('id'))
                        db.add(rls)
                        db.commit()
                    else:
                        [db.delete(info) for info in rls.info]
                        db.commit()

                    for info in nzb:
                        try:
                            if not isinstance(
                                    nzb[info],
                                (str, unicode, int, long, float)):
                                continue

                            rls_info = ReleaseInfo(identifier=info,
                                                   value=toUnicode(nzb[info]))
                            rls.info.append(rls_info)
                            db.commit()
                        except InterfaceError:
                            log.debug('Couldn\'t add %s to ReleaseInfo: %s',
                                      (info, traceback.format_exc()))

                    nzb['status_id'] = rls.status_id

                for nzb in sorted_results:
                    if nzb['status_id'] == ignored_status.get('id'):
                        log.info('Ignored: %s', nzb['name'])
                        continue

                    if nzb['score'] <= 0:
                        log.info('Ignored, score to low: %s', nzb['name'])
                        continue

                    downloaded = self.download(data=nzb, movie=movie)
                    if downloaded is True:
                        ret = True
                        break
                    elif downloaded != 'try_next':
                        break
            else:
                log.info(
                    'Better quality (%s) already available or snatched for %s',
                    (quality_type['quality']['label'], default_title))
                fireEvent('movie.restatus', movie['id'])
                break

            # Break if CP wants to shut down
            if self.shuttingDown() or ret:
                break

        fireEvent('notify.frontend',
                  type='searcher.ended.%s' % movie['id'],
                  data=True)

        #db.close()
        return ret
Exemplo n.º 53
0
    def getReleaseNameYear(self, release_name, file_name = None):

        release_name = release_name.strip(' .-_')

        # Use guessit first
        guess = {}
        if file_name:
            try:
                guessit = guess_movie_info(toUnicode(file_name))
                if guessit.get('title') and guessit.get('year'):
                    guess = {
                        'name': guessit.get('title'),
                        'year': guessit.get('year'),
                    }
            except:
                log.debug('Could not detect via guessit "%s": %s', (file_name, traceback.format_exc()))

        # Backup to simple
        release_name = os.path.basename(release_name.replace('\\', '/'))
        cleaned = ' '.join(re.split('\W+', simplifyString(release_name)))
        cleaned = re.sub(self.clean, ' ', cleaned)

        year = None
        for year_str in [file_name, release_name, cleaned]:
            if not year_str: continue
            year = self.findYear(year_str)
            if year:
                break

        cp_guess = {}

        if year:  # Split name on year
            try:
                movie_name = cleaned.rsplit(year, 1).pop(0).strip()
                if movie_name:
                    cp_guess = {
                        'name': movie_name,
                        'year': int(year),
                    }
            except:
                pass

        if not cp_guess:  # Split name on multiple spaces
            try:
                movie_name = cleaned.split('  ').pop(0).strip()
                cp_guess = {
                    'name': movie_name,
                    'year': int(year) if movie_name[:4] != year else 0,
                }
            except:
                pass

        if cp_guess.get('year') == guess.get('year') and len(cp_guess.get('name', '')) > len(guess.get('name', '')):
            cp_guess['other'] = guess
            return cp_guess
        elif guess == {}:
            cp_guess['other'] = guess
            return cp_guess

        guess['other'] = cp_guess
        return guess
Exemplo n.º 54
0
    def download(self, data, media, manual=False):

        if not data.get('protocol'):
            data['protocol'] = data['type']
            data['type'] = 'movie'

        # Test to see if any downloaders are enabled for this type
        downloader_enabled = fireEvent('download.enabled',
                                       manual,
                                       data,
                                       single=True)

        if downloader_enabled:
            snatched_status, done_status, active_status = fireEvent(
                'status.get', ['snatched', 'done', 'active'], single=True)

            # Download release to temp
            filedata = None
            if data.get('download') and (ismethod(data.get('download'))
                                         or isfunction(data.get('download'))):
                filedata = data.get('download')(url=data.get('url'),
                                                nzb_id=data.get('id'))
                if filedata == 'try_next':
                    return filedata

            download_result = fireEvent('download',
                                        data=data,
                                        movie=media,
                                        manual=manual,
                                        filedata=filedata,
                                        single=True)
            log.debug('Downloader result: %s', download_result)

            if download_result:
                try:
                    # Mark release as snatched
                    db = get_session()
                    rls = db.query(Relea).filter_by(
                        identifier=md5(data['url'])).first()
                    if rls:
                        renamer_enabled = Env.setting('enabled', 'renamer')

                        # Save download-id info if returned
                        if isinstance(download_result, dict):
                            for key in download_result:
                                rls_info = ReleaseInfo(
                                    identifier='download_%s' % key,
                                    value=toUnicode(download_result.get(key)))
                                rls.info.append(rls_info)
                        db.commit()

                        log_movie = '%s (%s) in %s' % (getTitle(
                            media['library']), media['library']['year'],
                                                       rls.quality.label)
                        snatch_message = 'Snatched "%s": %s' % (
                            data.get('name'), log_movie)
                        log.info(snatch_message)
                        fireEvent('%s.snatched' % data['type'],
                                  message=snatch_message,
                                  data=rls.to_dict())

                        # If renamer isn't used, mark media done
                        if not renamer_enabled:
                            try:
                                if media['status_id'] == active_status.get(
                                        'id'):
                                    for profile_type in media['profile'][
                                            'types']:
                                        if profile_type[
                                                'quality_id'] == rls.quality.id and profile_type[
                                                    'finish']:
                                            log.info(
                                                'Renamer disabled, marking media as finished: %s',
                                                log_movie)

                                            # Mark release done
                                            self.updateStatus(
                                                rls.id, status=done_status)

                                            # Mark media done
                                            mdia = db.query(Media).filter_by(
                                                id=media['id']).first()
                                            mdia.status_id = done_status.get(
                                                'id')
                                            mdia.last_edit = int(time.time())
                                            db.commit()
                            except:
                                log.error(
                                    'Failed marking media finished, renamer disabled: %s',
                                    traceback.format_exc())
                        else:
                            self.updateStatus(rls.id, status=snatched_status)

                except:
                    log.error('Failed marking media finished: %s',
                              traceback.format_exc())

                return True

        log.info(
            'Tried to download, but none of the "%s" downloaders are enabled or gave an error',
            (data.get('protocol')))

        return False
Exemplo n.º 55
0
    def getNfo(self, movie_info=None, data=None, i=0):
        if not data: data = {}
        if not movie_info: movie_info = {}

        nfoxml = Element('details')
        movie_root = SubElement(nfoxml, 'movie')
        movie_root.attrib["isExtra"] = "false"
        movie_root.attrib["isSet"] = "false"
        movie_root.attrib["isTV"] = "false"

        # Title
        try:
            el = SubElement(movie_root, 'title')
            el.text = toUnicode(getTitle(data))
        except:
            pass

        # IMDB id
        try:
            imdb_id = etree.SubElement(movie_root, "id")
            imdb_id.attrib["moviedb"] = "imdb"
            imdb_id.text = myShow['imdb_id']
        except:
            pass

        # Runtime
        try:
            runtime = SubElement(movie_root, 'runtime')
            runtime.text = '%s min' % movie_info.get('runtime')
        except:
            pass

        # Other values
        types = [
            'year', 'mpaa', 'original_title', 'outline', 'plot', 'tagline',
            'releaseDate:released'
        ]
        for type in types:

            if ':' in type:
                name, type = type.split(':')
            else:
                name = type

            try:
                if movie_info.get(type):
                    el = SubElement(movie_root, name)
                    el.text = toUnicode(movie_info.get(type, ''))
            except:
                pass

        # Rating
        for rating_type in ['imdb', 'rotten', 'tmdb']:
            try:
                r, v = movie_info['rating'][rating_type]
                rating = SubElement(movie_root, 'rating')
                rating.text = str(r)
                votes = SubElement(movie_root, 'votes')
                votes.text = str(v)
                break
            except:
                log.debug('Failed adding rating info from %s: %s',
                          (rating_type, traceback.format_exc()))

        # Genre
        Genres = SubElement(movie_root, "genres")
        for genre in movie_info.get('genres', []):
            genres = SubElement(Genres, "Genre")
            genres.text = toUnicode(genre)

        # Actors
        Actors = SubElement(movie_root, "cast")
        for actor_name in movie_info.get('actor_roles', {}):
            actor = SubElement(Actors, 'actor')
            actor.text = toUnicode(actor_name)

        # Directors
        for director_name in movie_info.get('directors', []):
            director = SubElement(movie_root, 'director')
            director.text = toUnicode(director_name)

        # Images / Thumbnail
        for image_url in movie_info['images']['poster_original']:
            image = SubElement(movie_root, 'thumb')
            image.text = toUnicode(image_url)

        # Images / Thumbnail
        for image_url in movie_info['images']['backdrop_original']:
            image = SubElement(movie_root, 'fanart')
            image.text = toUnicode(image_url)

        # Add file metadata
        # Video data
        if data['meta_data'].get('video'):
            vcodec = SubElement(movie_root, 'videoCodec')
            vcodec.text = toUnicode(data['meta_data']['video'])
            resolution = SubElement(movie_root, 'resolution')
            resolution.text = str(
                data['meta_data']['resolution_width']) + "x" + str(
                    data['meta_data']['resolution_height'])

        # Audio data
        if data['meta_data'].get('audio'):
            acodec = SubElement(movie_root, 'audioCodec')
            acodec.text = toUnicode(data['meta_data'].get('audio'))
            channels = SubElement(movie_root, 'audioChannels')
            channels.text = toUnicode(data['meta_data'].get('audio_channels'))

        # Clean up the xml and return it
        nfoxml = xml.dom.minidom.parseString(tostring(nfoxml))
        xml_string = nfoxml.toprettyxml(indent='  ')
        text_re = re.compile('>\n\s+([^<>\s].*?)\n\s+</', re.DOTALL)
        xml_string = text_re.sub('>\g<1></', xml_string)

        return xml_string.encode('utf-8')
Exemplo n.º 56
0
    def notify(self, message='', data=None, listener=None):
        if not data: data = {}

        # Extract all the settings from settings
        from_address = self.conf('from')
        to_address = self.conf('to')
        ssl = self.conf('ssl')
        smtp_server = self.conf('smtp_server')
        smtp_user = self.conf('smtp_user')
        smtp_pass = self.conf('smtp_pass')
        smtp_port = self.conf('smtp_port')
        starttls = self.conf('starttls')

        # Make the basic message
        message = MIMEText(toUnicode(message), _charset=Env.get('encoding'))
        message['Subject'] = self.default_title
        message['From'] = from_address
        message['To'] = to_address
        message['Date'] = formatdate(localtime=1)
        message['Message-ID'] = make_msgid()

        try:
            # Open the SMTP connection, via SSL if requested
            log.debug("Connecting to host %s on port %s" %
                      (smtp_server, smtp_port))
            log.debug("SMTP over SSL %s",
                      ("enabled" if ssl == 1 else "disabled"))
            mailserver = smtplib.SMTP_SSL(
                smtp_server, smtp_port) if ssl == 1 else smtplib.SMTP(
                    smtp_server, smtp_port)

            if starttls:
                log.debug(
                    "Using StartTLS to initiate the connection with the SMTP server"
                )
                mailserver.starttls()

            # Say hello to the server
            mailserver.ehlo()

            # Check too see if an login attempt should be attempted
            if len(smtp_user) > 0:
                log.debug("Logging on to SMTP server using username \'%s\'%s",
                          (smtp_user,
                           " and a password" if len(smtp_pass) > 0 else ""))
                mailserver.login(smtp_user, smtp_pass)

            # Send the e-mail
            log.debug("Sending the email")
            mailserver.sendmail(from_address, splitString(to_address),
                                message.as_string())

            # Close the SMTP connection
            mailserver.quit()

            log.info('Email notification sent')

            return True
        except:
            log.error('E-mail failed: %s', traceback.format_exc())

        return False
Exemplo n.º 57
0
    def _searchOnHost(self, host, media, quality, results):

        query = self.buildUrl(media, host)
        url = '%s%s' % (self.getUrl(host['host']), query)
        nzbs = self.getRSSData(url,
                               cache_timeout=1800,
                               headers={'User-Agent': Env.getIdentifier()})

        for nzb in nzbs:

            date = None
            spotter = None
            for item in nzb:
                if date and spotter:
                    break
                if item.attrib.get('name') == 'usenetdate':
                    date = item.attrib.get('value')
                    break

                # Get the name of the person who posts the spot
                if item.attrib.get('name') == 'poster':
                    if "@spot.net" in item.attrib.get('value'):
                        spotter = item.attrib.get('value').split("@")[0]
                        continue

            if not date:
                date = self.getTextElement(nzb, 'pubDate')

            nzb_id = self.getTextElement(nzb, 'guid').split('/')[-1:].pop()
            name = self.getTextElement(nzb, 'title')

            if not name:
                continue

            name_extra = ''
            if spotter:
                name_extra = spotter

            description = ''
            if "@spot.net" in nzb_id:
                try:
                    # Get details for extended description to retrieve passwords
                    query = self.buildDetailsUrl(nzb_id, host['api_key'])
                    url = '%s%s' % (self.getUrl(host['host']), query)
                    nzb_details = self.getRSSData(
                        url,
                        cache_timeout=1800,
                        headers={'User-Agent': Env.getIdentifier()})[0]

                    description = self.getTextElement(nzb_details,
                                                      'description')

                    # Extract a password from the description
                    password = re.search(
                        '(?:' + self.passwords_regex +
                        ')(?: *)(?:\:|\=)(?: *)(.*?)\<br\>|\n|$',
                        description,
                        flags=re.I).group(1)
                    if password:
                        name += ' {{%s}}' % password.strip()
                except:
                    log.debug('Error getting details of "%s": %s',
                              (name, traceback.format_exc()))

            results.append({
                'id':
                nzb_id,
                'provider_extra':
                urlparse(host['host']).hostname or host['host'],
                'name':
                toUnicode(name),
                'name_extra':
                name_extra,
                'age':
                self.calculateAge(int(time.mktime(parse(date).timetuple()))),
                'size':
                int(self.getElement(nzb, 'enclosure').attrib['length']) /
                1024 / 1024,
                'url': ((self.getUrl(host['host']) + self.urls['download']) %
                        tryUrlencode(nzb_id)) + self.getApiExt(host),
                'detail_url': (cleanHost(host['host']) + self.urls['detail']) %
                tryUrlencode(nzb_id),
                'content':
                self.getTextElement(nzb, 'description'),
                'description':
                description,
                'score':
                host['extra_score'],
            })
Exemplo n.º 58
0
    def scan(self, movie_folder = None, download_info = None):

        if self.isDisabled():
            return

        if self.renaming_started is True:
            log.info('Renamer is already running, if you see this often, check the logs above for errors.')
            return

        # Check to see if the "to" folder is inside the "from" folder.
        if movie_folder and not os.path.isdir(movie_folder) or not os.path.isdir(self.conf('from')) or not os.path.isdir(self.conf('to')):
            l = log.debug if movie_folder else log.error
            l('Both the "To" and "From" have to exist.')
            return
        elif self.conf('from') in self.conf('to'):
            log.error('The "to" can\'t be inside of the "from" folder. You\'ll get an infinite loop.')
            return
        elif (movie_folder and movie_folder in [self.conf('to'), self.conf('from')]):
            log.error('The "to" and "from" folders can\'t be inside of or the same as the provided movie folder.')
            return

        self.renaming_started = True

        # make sure the movie folder name is included in the search
        folder = None
        files = []
        if movie_folder:
            log.info('Scanning movie folder %s...', movie_folder)
            movie_folder = movie_folder.rstrip(os.path.sep)
            folder = os.path.dirname(movie_folder)

            # Get all files from the specified folder
            try:
                for root, folders, names in os.walk(movie_folder):
                    files.extend([os.path.join(root, name) for name in names])
            except:
                log.error('Failed getting files from %s: %s', (movie_folder, traceback.format_exc()))

        db = get_session()

        # Extend the download info with info stored in the downloaded release
        download_info = self.extendDownloadInfo(download_info)

        groups = fireEvent('scanner.scan', folder = folder if folder else self.conf('from'),
                           files = files, download_info = download_info, return_ignored = False, single = True)

        destination = self.conf('to')
        folder_name = self.conf('folder_name')
        file_name = self.conf('file_name')
        trailer_name = self.conf('trailer_name')
        nfo_name = self.conf('nfo_name')
        separator = self.conf('separator')

        # Statusses
        done_status, active_status, downloaded_status, snatched_status = \
            fireEvent('status.get', ['done', 'active', 'downloaded', 'snatched'], single = True)

        for group_identifier in groups:

            group = groups[group_identifier]
            rename_files = {}
            remove_files = []
            remove_releases = []

            movie_title = getTitle(group['library'])

            # Add _UNKNOWN_ if no library item is connected
            if not group['library'] or not movie_title:
                self.tagDir(group, 'unknown')
                continue
            # Rename the files using the library data
            else:
                group['library'] = fireEvent('library.update', identifier = group['library']['identifier'], single = True)
                if not group['library']:
                    log.error('Could not rename, no library item to work with: %s', group_identifier)
                    continue

                library = group['library']
                movie_title = getTitle(library)

                # Find subtitle for renaming
                fireEvent('renamer.before', group)

                # Remove weird chars from moviename
                movie_name = re.sub(r"[\x00\/\\:\*\?\"<>\|]", '', movie_title)

                # Put 'The' at the end
                name_the = movie_name
                if movie_name[:4].lower() == 'the ':
                    name_the = movie_name[4:] + ', The'

                replacements = {
                     'ext': 'mkv',
                     'namethe': name_the.strip(),
                     'thename': movie_name.strip(),
                     'year': library['year'],
                     'first': name_the[0].upper(),
                     'quality': group['meta_data']['quality']['label'],
                     'quality_type': group['meta_data']['quality_type'],
                     'video': group['meta_data'].get('video'),
                     'audio': group['meta_data'].get('audio'),
                     'group': group['meta_data']['group'],
                     'source': group['meta_data']['source'],
                     'resolution_width': group['meta_data'].get('resolution_width'),
                     'resolution_height': group['meta_data'].get('resolution_height'),
                     'imdb_id': library['identifier'],
                     'cd': '',
                     'cd_nr': '',
                }

                for file_type in group['files']:

                    # Move nfo depending on settings
                    if file_type is 'nfo' and not self.conf('rename_nfo'):
                        log.debug('Skipping, renaming of %s disabled', file_type)
                        if self.conf('cleanup'):
                            for current_file in group['files'][file_type]:
                                remove_files.append(current_file)
                        continue

                    # Subtitle extra
                    if file_type is 'subtitle_extra':
                        continue

                    # Move other files
                    multiple = len(group['files'][file_type]) > 1 and not group['is_dvd']
                    cd = 1 if multiple else 0

                    for current_file in sorted(list(group['files'][file_type])):
                        current_file = toUnicode(current_file)

                        # Original filename
                        replacements['original'] = os.path.splitext(os.path.basename(current_file))[0]
                        replacements['original_folder'] = fireEvent('scanner.remove_cptag', group['dirname'], single = True)

                        # Extension
                        replacements['ext'] = getExt(current_file)

                        # cd #
                        replacements['cd'] = ' cd%d' % cd if multiple else ''
                        replacements['cd_nr'] = cd if multiple else ''

                        # Naming
                        final_folder_name = self.doReplace(folder_name, replacements).lstrip('. ')
                        final_file_name = self.doReplace(file_name, replacements).lstrip('. ')
                        replacements['filename'] = final_file_name[:-(len(getExt(final_file_name)) + 1)]

                        # Meta naming
                        if file_type is 'trailer':
                            final_file_name = self.doReplace(trailer_name, replacements, remove_multiple = True).lstrip('. ')
                        elif file_type is 'nfo':
                            final_file_name = self.doReplace(nfo_name, replacements, remove_multiple = True).lstrip('. ')

                        # Seperator replace
                        if separator:
                            final_file_name = final_file_name.replace(' ', separator)

                        # Move DVD files (no structure renaming)
                        if group['is_dvd'] and file_type is 'movie':
                            found = False
                            for top_dir in ['video_ts', 'audio_ts', 'bdmv', 'certificate']:
                                has_string = current_file.lower().find(os.path.sep + top_dir + os.path.sep)
                                if has_string >= 0:
                                    structure_dir = current_file[has_string:].lstrip(os.path.sep)
                                    rename_files[current_file] = os.path.join(destination, final_folder_name, structure_dir)
                                    found = True
                                    break

                            if not found:
                                log.error('Could not determine dvd structure for: %s', current_file)

                        # Do rename others
                        else:
                            if file_type is 'leftover':
                                if self.conf('move_leftover'):
                                    rename_files[current_file] = os.path.join(destination, final_folder_name, os.path.basename(current_file))
                            elif file_type not in ['subtitle']:
                                rename_files[current_file] = os.path.join(destination, final_folder_name, final_file_name)

                        # Check for extra subtitle files
                        if file_type is 'subtitle':

                            remove_multiple = False
                            if len(group['files']['movie']) == 1:
                                remove_multiple = True

                            sub_langs = group['subtitle_language'].get(current_file, [])

                            # rename subtitles with or without language
                            sub_name = self.doReplace(file_name, replacements, remove_multiple = remove_multiple)
                            rename_files[current_file] = os.path.join(destination, final_folder_name, sub_name)

                            rename_extras = self.getRenameExtras(
                                extra_type = 'subtitle_extra',
                                replacements = replacements,
                                folder_name = folder_name,
                                file_name = file_name,
                                destination = destination,
                                group = group,
                                current_file = current_file,
                                remove_multiple = remove_multiple,
                            )

                            # Don't add language if multiple languages in 1 subtitle file
                            if len(sub_langs) == 1:
                                sub_name = final_file_name.replace(replacements['ext'], '%s.%s' % (sub_langs[0], replacements['ext']))
                                rename_files[current_file] = os.path.join(destination, final_folder_name, sub_name)

                            rename_files = mergeDicts(rename_files, rename_extras)

                        # Filename without cd etc
                        elif file_type is 'movie':
                            rename_extras = self.getRenameExtras(
                                extra_type = 'movie_extra',
                                replacements = replacements,
                                folder_name = folder_name,
                                file_name = file_name,
                                destination = destination,
                                group = group,
                                current_file = current_file
                            )
                            rename_files = mergeDicts(rename_files, rename_extras)

                            group['filename'] = self.doReplace(file_name, replacements, remove_multiple = True)[:-(len(getExt(final_file_name)) + 1)]
                            group['destination_dir'] = os.path.join(destination, final_folder_name)

                        if multiple:
                            cd += 1

                # Before renaming, remove the lower quality files
                library = db.query(Library).filter_by(identifier = group['library']['identifier']).first()
                remove_leftovers = True

                # Add it to the wanted list before we continue
                if len(library.movies) == 0:
                    profile = db.query(Profile).filter_by(core = True, label = group['meta_data']['quality']['label']).first()
                    fireEvent('movie.add', params = {'identifier': group['library']['identifier'], 'profile_id': profile.id}, search_after = False)
                    db.expire_all()
                    library = db.query(Library).filter_by(identifier = group['library']['identifier']).first()

                for movie in library.movies:

                    # Mark movie "done" onces it found the quality with the finish check
                    try:
                        if movie.status_id == active_status.get('id') and movie.profile:
                            for profile_type in movie.profile.types:
                                if profile_type.quality_id == group['meta_data']['quality']['id'] and profile_type.finish:
                                    movie.status_id = done_status.get('id')
                                    movie.last_edit = int(time.time())
                                    db.commit()
                    except Exception, e:
                        log.error('Failed marking movie finished: %s %s', (e, traceback.format_exc()))

                    # Go over current movie releases
                    for release in movie.releases:

                        # When a release already exists
                        if release.status_id is done_status.get('id'):

                            # This is where CP removes older, lesser quality releases
                            if release.quality.order > group['meta_data']['quality']['order']:
                                log.info('Removing lesser quality %s for %s.', (movie.library.titles[0].title, release.quality.label))
                                for current_file in release.files:
                                    remove_files.append(current_file)
                                remove_releases.append(release)
                            # Same quality, but still downloaded, so maybe repack/proper/unrated/directors cut etc
                            elif release.quality.order is group['meta_data']['quality']['order']:
                                log.info('Same quality release already exists for %s, with quality %s. Assuming repack.', (movie.library.titles[0].title, release.quality.label))
                                for current_file in release.files:
                                    remove_files.append(current_file)
                                remove_releases.append(release)

                            # Downloaded a lower quality, rename the newly downloaded files/folder to exclude them from scan
                            else:
                                log.info('Better quality release already exists for %s, with quality %s', (movie.library.titles[0].title, release.quality.label))

                                # Add exists tag to the .ignore file
                                self.tagDir(group, 'exists')

                                # Notify on rename fail
                                download_message = 'Renaming of %s (%s) canceled, exists in %s already.' % (movie.library.titles[0].title, group['meta_data']['quality']['label'], release.quality.label)
                                fireEvent('movie.renaming.canceled', message = download_message, data = group)
                                remove_leftovers = False

                                break
                        elif release.status_id is snatched_status.get('id'):
                            if release.quality.id is group['meta_data']['quality']['id']:
                                log.debug('Marking release as downloaded')
                                try:
                                    release.status_id = downloaded_status.get('id')
                                    release.last_edit = int(time.time())
                                except Exception, e:
                                    log.error('Failed marking release as finished: %s %s', (e, traceback.format_exc()))

                                db.commit()

                # Remove leftover files
                if self.conf('cleanup') and not self.conf('move_leftover') and remove_leftovers and \
                        not (self.conf('file_action') != 'move' and self.downloadIsTorrent(download_info)):
                    log.debug('Removing leftover files')
                    for current_file in group['files']['leftover']:
                        remove_files.append(current_file)
                elif not remove_leftovers: # Don't remove anything
                    break
Exemplo n.º 59
0
    def _searchOnTitle(self, title, movie, quality, results):

        page = 0
        total_pages = 1
        cats = self.getCatId(quality)

        while page < total_pages:

            movieTitle = tryUrlencode('"%s" %s' %
                                      (title, movie['info']['year']))
            search_url = self.urls['search'] % (movieTitle, page, cats[0])
            page += 1

            data = self.getHTMLData(search_url)
            if data:
                try:

                    results_table = None

                    data_split = splitString(data, '<table')
                    soup = None
                    for x in data_split:
                        soup = BeautifulSoup(x)
                        results_table = soup.find('table',
                                                  attrs={'class': 'koptekst'})
                        if results_table:
                            break

                    if not results_table:
                        return

                    try:
                        pagelinks = soup.findAll(href=re.compile('page'))
                        page_numbers = [
                            int(
                                re.search('page=(?P<page_number>.+'
                                          ')', i['href']).group('page_number'))
                            for i in pagelinks
                        ]
                        total_pages = max(page_numbers)
                    except:
                        pass

                    entries = results_table.find_all('tr')

                    for result in entries[1:]:
                        prelink = result.find(href=re.compile('details.php'))
                        link = prelink['href']
                        download = result.find(
                            'a', href=re.compile('download.php'))['href']

                        if link and download:

                            def extra_score(item):
                                trusted = (0, 10)[result.find(
                                    'img', alt=re.compile('Trusted'))
                                                  is not None]
                                vip = (0, 20)[result.find(
                                    'img', alt=re.compile('VIP')) is not None]
                                confirmed = (0, 30)[result.find(
                                    'img', alt=re.compile('Helpers'))
                                                    is not None]
                                moderated = (0, 50)[result.find(
                                    'img', alt=re.compile('Moderator'))
                                                    is not None]

                                return confirmed + trusted + vip + moderated

                            id = re.search('id=(?P<id>\d+)&', link).group('id')
                            url = self.urls['download'] % download

                            fileSize = self.parseSize(
                                result.select('td.rowhead')[8].text)
                            results.append({
                                'id':
                                id,
                                'name':
                                toUnicode(prelink.find('b').text),
                                'url':
                                url,
                                'detail_url':
                                self.urls['detail'] % link,
                                'size':
                                fileSize,
                                'seeders':
                                tryInt(result.find_all('td')[2].string),
                                'leechers':
                                tryInt(result.find_all('td')[3].string),
                                'extra_score':
                                extra_score,
                                'get_more_info':
                                self.getMoreInfo
                            })

                except:
                    log.error('Failed getting results from %s: %s',
                              (self.getName(), traceback.format_exc()))
Exemplo n.º 60
0
    def search(self, movie, quality):

        results = []
        if self.isDisabled():
            return results

        q = '"%s %s" %s' % (simplifyString(getTitle(
            movie['library'])), movie['library']['year'],
                            quality.get('identifier'))
        for ignored in Env.setting('ignored_words', 'searcher').split(','):
            q = '%s -%s' % (q, ignored.strip())

        params = {
            'q': q,
            'ig': '1',
            'rpp': 200,
            'st': 1,
            'sp': 1,
            'ns': 1,
        }

        cache_key = 'nzbclub.%s.%s.%s' % (movie['library']['identifier'],
                                          quality.get('identifier'), q)
        data = self.getCache(cache_key,
                             self.urls['search'] % tryUrlencode(params))
        if data:
            try:
                try:
                    data = XMLTree.fromstring(data)
                    nzbs = self.getElements(data, 'channel/item')
                except Exception, e:
                    log.debug('%s, %s', (self.getName(), e))
                    return results

                for nzb in nzbs:

                    nzbclub_id = tryInt(
                        self.getTextElement(
                            nzb, "link").split('/nzb_view/')[1].split('/')[0])
                    enclosure = self.getElement(nzb, "enclosure").attrib
                    size = enclosure['length']
                    date = self.getTextElement(nzb, "pubDate")

                    def extra_check(item):
                        full_description = self.getCache(
                            'nzbclub.%s' % nzbclub_id,
                            item['detail_url'],
                            cache_timeout=25920000)

                        for ignored in [
                                'ARCHIVE inside ARCHIVE', 'Incomplete',
                                'repair impossible'
                        ]:
                            if ignored in full_description:
                                log.info(
                                    'Wrong: Seems to be passworded or corrupted files: %s',
                                    new['name'])
                                return False

                        return True

                    new = {
                        'id':
                        nzbclub_id,
                        'type':
                        'nzb',
                        'provider':
                        self.getName(),
                        'name':
                        toUnicode(self.getTextElement(nzb, "title")),
                        'age':
                        self.calculateAge(
                            int(time.mktime(parse(date).timetuple()))),
                        'size':
                        tryInt(size) / 1024 / 1024,
                        'url':
                        enclosure['url'].replace(' ', '_'),
                        'download':
                        self.download,
                        'detail_url':
                        self.getTextElement(nzb, "link"),
                        'description':
                        '',
                        'get_more_info':
                        self.getMoreInfo,
                        'extra_check':
                        extra_check
                    }

                    is_correct_movie = fireEvent('searcher.correct_movie',
                                                 nzb=new,
                                                 movie=movie,
                                                 quality=quality,
                                                 imdb_results=False,
                                                 single=True)

                    if is_correct_movie:
                        new['score'] = fireEvent('score.calculate',
                                                 new,
                                                 movie,
                                                 single=True)
                        results.append(new)
                        self.found(new)

                return results
            except SyntaxError:
                log.error('Failed to parse XML response from NZBClub')