Example #1
0
    def getUserScript(self, script_route, **kwargs):

        klass = self

        class UserscriptHandler(RequestHandler):

            def get(self, random, route):

                bookmarklet_host = Env.setting('bookmarklet_host')
                loc = bookmarklet_host if bookmarklet_host else "{0}://{1}".format(self.request.protocol, self.request.headers.get('X-Forwarded-Host') or self.request.headers.get('host'))

                params = {
                    'includes': fireEvent('userscript.get_includes', merge = True),
                    'excludes': fireEvent('userscript.get_excludes', merge = True),
                    'version': klass.getVersion(),
                    'api': '%suserscript/' % Env.get('api_base'),
                    'host': loc,
                }

                script = klass.renderTemplate(__file__, 'template.js_tmpl', **params)
                klass.createFile(os.path.join(Env.get('cache_dir'), 'whatpotato.user.js'), script)

                self.redirect(Env.get('api_base') + 'file.cache/whatpotato.user.js')

        Env.get('app').add_handlers(".*$", [('%s%s' % (Env.get('api_base'), script_route), UserscriptHandler)])
Example #2
0
    def addMovies(self):

        movies = fireEvent('automation.get_movies', merge = True)
        movie_ids = []

        for imdb_id in movies:

            if self.shuttingDown():
                break

            prop_name = 'automation.added.%s' % imdb_id
            added = Env.prop(prop_name, default = False)
            if not added:
                added_movie = fireEvent('movie.add', params = {'identifier': imdb_id}, force_readd = False, search_after = False, update_after = True, single = True)
                if added_movie:
                    movie_ids.append(added_movie['_id'])
                Env.prop(prop_name, True)

        for movie_id in movie_ids:

            if self.shuttingDown():
                break

            movie_dict = fireEvent('media.get', movie_id, single = True)
            if movie_dict:
                fireEvent('movie.searcher.single', movie_dict)

        return True
Example #3
0
    def getDomain(self, url = ''):

        forced_domain = self.conf('domain')
        if forced_domain:
            return cleanHost(forced_domain).rstrip('/') + url

        if not self.proxy_domain:
            for proxy in self.proxy_list:

                prop_name = 'proxy.%s' % proxy
                last_check = float(Env.prop(prop_name, default = 0))

                if last_check > time.time() - 86400:
                    continue

                data = ''
                try:
                    data = self.urlopen(proxy, timeout = 3, show_error = False)
                except:
                    log.debug('Failed %s proxy %s: %s', (self.getName(), proxy, traceback.format_exc()))

                if self.correctProxy(data):
                    log.debug('Using proxy for %s: %s', (self.getName(), proxy))
                    self.proxy_domain = proxy
                    break

                Env.prop(prop_name, time.time())

        if not self.proxy_domain:
            log.error('No %s proxies left, please add one in settings, or let us know which one to add on the forum.', self.getName())
            return None

        return cleanHost(self.proxy_domain).rstrip('/') + url
Example #4
0
    def getCache(self, cache_key, url = None, **kwargs):

        use_cache = not len(kwargs.get('data', {})) > 0 and not kwargs.get('files')

        if use_cache:
            cache_key_md5 = md5(cache_key)
            cache = Env.get('cache').get(cache_key_md5)
            if cache:
                if not Env.get('dev'): log.debug('Getting cache %s', cache_key)
                return cache

        if url:
            try:

                cache_timeout = 300
                if 'cache_timeout' in kwargs:
                    cache_timeout = kwargs.get('cache_timeout')
                    del kwargs['cache_timeout']

                data = self.urlopen(url, **kwargs)
                if data and cache_timeout > 0 and use_cache:
                    self.setCache(cache_key, data, timeout = cache_timeout)
                return data
            except:
                if not kwargs.get('show_error', True):
                    raise

                log.debug('Failed getting cache: %s', (traceback.format_exc(0)))
                return ''
Example #5
0
    def __init__(self):

        if Env.get('desktop'):
            self.updater = DesktopUpdater()
        elif os.path.isdir(os.path.join(Env.get('app_dir'), '.git')):
            git_default = 'git'
            git_command = self.conf('git_command', default = git_default)
            git_command = git_command if git_command != git_default and (os.path.isfile(git_command) or re.match('^[a-zA-Z0-9_/\.\-]+$', git_command)) else git_default
            self.updater = GitUpdater(git_command)
        else:
            self.updater = SourceUpdater()

        addEvent('app.load', self.logVersion, priority = 10000)
        addEvent('app.load', self.setCrons)
        addEvent('updater.info', self.info)

        addApiView('updater.info', self.info, docs = {
            'desc': 'Get updater information',
            'return': {
                'type': 'object',
                'example': """{
        'last_check': "last checked for update",
        'update_version': "available update version or empty",
        'version': current_cp_version
}"""}
        })
        addApiView('updater.update', self.doUpdateView)
        addApiView('updater.check', self.checkView, docs = {
            'desc': 'Check for available update',
            'return': {'type': 'see updater.info'}
        })

        addEvent('setting.save.updater.enabled.after', self.setCrons)
Example #6
0
    def createBaseUrl(self):
        host = Env.setting('host')
        if host == '0.0.0.0' or host == '':
            host = 'localhost'
        port = Env.setting('port')
        ssl = Env.setting('ssl_cert') and Env.setting('ssl_key')

        return '%s:%d%s' % (cleanHost(host, ssl = ssl).rstrip('/'), int(port), Env.get('web_base'))
Example #7
0
 def getCredentials(self, **kwargs):
     try:
         oauth_token = kwargs.get('oauth')
     except:
         return 'redirect', Env.get('web_base') + 'settings/downloaders/'
     log.debug('oauth_token is: %s', oauth_token)
     self.conf('oauth_token', value = oauth_token);
     return 'redirect', Env.get('web_base') + 'settings/downloaders/'
Example #8
0
    def get_current_user(self):
        username = Env.setting('username')
        password = Env.setting('password')

        if username and password:
            return self.get_secure_cookie('user')
        else:  # Login when no username or password are set
            return True
Example #9
0
    def suggestView(self, limit = 6, **kwargs):
        if self.isDisabled():
            return {
                'success': True,
                'movies': []
            }

        movies = splitString(kwargs.get('movies', ''))
        ignored = splitString(kwargs.get('ignored', ''))
        seen = splitString(kwargs.get('seen', ''))

        cached_suggestion = self.getCache('suggestion_cached')
        if cached_suggestion:
            suggestions = cached_suggestion
        else:

            if not movies or len(movies) == 0:
                active_movies = fireEvent('media.with_status', ['active', 'done'], types = 'movie', single = True)
                movies = [getIdentifier(x) for x in active_movies]

            if not ignored or len(ignored) == 0:
                ignored = splitString(Env.prop('suggest_ignore', default = ''))
            if not seen or len(seen) == 0:
                movies.extend(splitString(Env.prop('suggest_seen', default = '')))

            suggestions = fireEvent('movie.suggest', movies = movies, ignore = ignored, single = True)
            self.setCache('suggestion_cached', suggestions, timeout = 6048000)  # Cache for 10 weeks

        medias = []
        for suggestion in suggestions[:int(limit)]:

            # Cache poster
            posters = suggestion.get('images', {}).get('poster', [])
            poster = [x for x in posters if 'tmdb' in x]
            posters = poster if len(poster) > 0 else posters

            cached_poster = fireEvent('file.download', url = posters[0], single = True) if len(posters) > 0 else False
            files = {'image_poster': [cached_poster] } if cached_poster else {}

            medias.append({
                'status': 'suggested',
                'title': getTitle(suggestion),
                'type': 'movie',
                'info': suggestion,
                'files': files,
                'identifiers': {
                    'imdb': suggestion.get('imdb')
                }
            })

        return {
            'success': True,
            'movies': medias
        }
Example #10
0
def page_not_found(rh):
    index_url = Env.get('web_base')
    url = rh.request.uri[len(index_url):]

    if url[:3] != 'api':
        r = index_url + '#' + url.lstrip('/')
        rh.redirect(r)
    else:
        if not Env.get('dev'):
            time.sleep(0.1)

        rh.set_status(404)
        rh.write('Wrong API key used')
Example #11
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 = removeDuplicate(preferred_words + splitString(movie['category']['preferred'].lower()))
        except: pass

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

        for movie_title in movie['info']['titles']:
            score += nameRatioScore(toUnicode(nzb['name']), toUnicode(movie_title))
            score += namePositionScore(toUnicode(nzb['name']), toUnicode(movie_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))

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

        # Partial ignored words
        score += partialIgnoredScore(nzb['name'], getTitle(movie), 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
Example #12
0
    def post(self, *args, **kwargs):

        api_key = None

        username = Env.setting('username')
        password = Env.setting('password')

        if (self.get_argument('username') == username or not username) and (md5(self.get_argument('password')) == password or not password):
            api_key = Env.setting('api_key')

        if api_key:
            remember_me = tryInt(self.get_argument('remember_me', default = 0))
            self.set_secure_cookie('user', api_key, expires_days = 30 if remember_me > 0 else None)

        self.redirect(Env.get('web_base'))
Example #13
0
    def download(self, url = '', nzb_id = ''):
        try:
            return self.urlopen(url, headers = {'User-Agent': Env.getIdentifier()}, show_error = False)
        except:
            log.error('Failed getting release from %s: %s', (self.getName(), traceback.format_exc()))

        return 'try_next'
 def getRequestHeaders(self):
     return {
         'X-CP-Version': fireEvent('app.version', single = True),
         'X-CP-API': self.api_version,
         'X-CP-Time': time.time(),
         'X-CP-Identifier': '+%s' % Env.setting('api_key', 'core')[:10],  # Use first 10 as identifier, so we don't need to use IP address in api stats
     }
Example #15
0
    def check(self):

        if self.update_version:
            return True

        log.info('Checking for new version on github for %s', self.repo_name)
        if not Env.get('dev'):
            self.repo.fetch()

        current_branch = self.repo.getCurrentBranch().name

        for branch in self.repo.getRemoteByName('origin').getBranches():
            if current_branch == branch.name:

                local = self.repo.getHead()
                remote = branch.getHead()

                log.debug('Versions, local:%s, remote:%s', (local.hash[:8], remote.hash[:8]))

                if local.getDate() < remote.getDate():
                    self.update_version = {
                        'hash': remote.hash[:8],
                        'date': remote.getDate(),
                    }
                    return True

        self.last_check = time.time()
        return False
Example #16
0
    def get(self, nr = 0, **kwargs):

        nr = tryInt(nr)
        current_path = None

        total = 1
        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):
                total = x - 1
                break

            # Set current path
            if x is nr:
                current_path = path

        log_content = ''
        if current_path:
            f = open(current_path, 'r')
            log_content = f.read()
        logs = self.toList(log_content)

        return {
            'success': True,
            'log': logs,
            'total': total,
        }
Example #17
0
    def __init__(self):

        fireEvent('scheduler.interval', identifier = 'manage.update_library', handle = self.updateLibrary, hours = 2)

        addEvent('manage.update', self.updateLibrary)
        addEvent('manage.diskspace', self.getDiskSpace)

        # Add files after renaming
        def after_rename(message = None, group = None):
            if not group: group = {}
            return self.scanFilesToLibrary(folder = group['destination_dir'], files = group['renamed_files'], release_download = group['release_download'])
        addEvent('renamer.after', after_rename, priority = 110)

        addApiView('manage.update', self.updateLibraryView, docs = {
            'desc': 'Update the library by scanning for new movies',
            'params': {
                'full': {'desc': 'Do a full update or just recently changed/added movies.'},
            }
        })

        addApiView('manage.progress', self.getProgress, docs = {
            'desc': 'Get the progress of current manage update',
            'return': {'type': 'object', 'example': """{
    'progress': False || object, total & to_go,
}"""},
        })

        if not Env.get('dev') and self.conf('startup_scan'):
            addEvent('app.load', self.updateLibraryQuick)

        addEvent('app.load', self.setCrons)

        # Enable / disable interval
        addEvent('setting.save.manage.library_refresh_interval.after', self.setCrons)
Example #18
0
    def createStructure(self):

        custom_dir = os.path.join(Env.get('data_dir'), 'custom_plugins')

        if not os.path.isdir(custom_dir):
            self.makeDir(custom_dir)
            self.createFile(os.path.join(custom_dir, '__init__.py'), '# Don\'t remove this file')
Example #19
0
    def download(self, url = '', nzb_id = ''):
        host = urlparse(url).hostname

        if self.limits_reached.get(host):
            # Try again in 3 hours
            if self.limits_reached[host] > time.time() - 10800:
                return 'try_next'

        try:
            data = self.urlopen(url, show_error = False, headers = {'User-Agent': Env.getIdentifier()})
            self.limits_reached[host] = False
            return data
        except HTTPError as e:
            sc = e.response.status_code
            if sc in [503, 429]:
                response = e.read().lower()
                if sc == 429 or 'maximum api' in response or 'download limit' in response:
                    if not self.limits_reached.get(host):
                        log.error('Limit reached / to many requests for newznab provider: %s', host)
                    self.limits_reached[host] = time.time()
                    return 'try_next'

            log.error('Failed download from %s: %s', (host, traceback.format_exc()))

        return 'try_next'
Example #20
0
    def _createType(self, meta_name, root, movie_info, group, file_type, i):  # Get file path
        camelcase_method = underscoreToCamel(file_type.capitalize())
        name = getattr(self, "get" + camelcase_method + "Name")(meta_name, root, i)

        if name and (self.conf("meta_" + file_type) or self.conf("meta_" + file_type) is None):

            # Get file content
            content = getattr(self, "get" + camelcase_method)(movie_info=movie_info, data=group, i=i)
            if content:
                log.debug("Creating %s file: %s", (file_type, name))
                if os.path.isfile(content):
                    content = sp(content)
                    name = sp(name)

                    if not os.path.exists(os.path.dirname(name)):
                        os.makedirs(os.path.dirname(name))

                    shutil.copy2(content, name)
                    shutil.copyfile(content, name)

                    # Try and copy stats seperately
                    try:
                        shutil.copystat(content, name)
                    except:
                        pass
                else:
                    self.createFile(name, content)
                    group["renamed_files"].append(name)

                try:
                    os.chmod(sp(name), Env.getPermission("file"))
                except:
                    log.debug("Failed setting permissions for %s: %s", (name, traceback.format_exc()))
Example #21
0
    def search(self, name, year = None, imdb_only = False):

        prop_name = 'automation.cached.%s.%s' % (name, year)
        cached_imdb = Env.prop(prop_name, default = False)
        if cached_imdb and imdb_only:
            return cached_imdb

        result = fireEvent('movie.search', q = '%s %s' % (name, year if year else ''), limit = 1, merge = True)

        if len(result) > 0:
            if imdb_only and result[0].get('imdb'):
                Env.prop(prop_name, result[0].get('imdb'))

            return result[0].get('imdb') if imdb_only else result[0]
        else:
            return None
Example #22
0
    def register(self):
        if self.registered:
            return
        try:

            hostname = self.conf("hostname")
            password = self.conf("password")
            port = self.conf("port")

            self.growl = notifier.GrowlNotifier(
                applicationName=Env.get("appname"),
                notifications=["Updates"],
                defaultNotifications=["Updates"],
                applicationIcon=self.getNotificationImage("medium"),
                hostname=hostname if hostname else "localhost",
                password=password if password else None,
                port=port if port else 23053,
            )
            self.growl.register()
            self.registered = True
        except Exception as e:
            if "timed out" in str(e):
                self.registered = True
            else:
                log.error("Failed register of growl: %s", traceback.format_exc())
Example #23
0
        def __init__(self):

            desktop = Env.get('desktop')
            desktop.setSettings({
                'base_url': fireEvent('app.base_url', single = True),
                'api_url': fireEvent('app.api_url', single = True),
                'api': Env.setting('api'),
            })

            # Events from desktop
            desktop.addEvents({
                'onClose': self.onClose,
            })

            # Events to desktop
            addEvent('app.after_shutdown', desktop.afterShutdown)
            addEvent('app.load', desktop.onAppLoad, priority = 110)
Example #24
0
    def signalHandler(self):
        if Env.get('daemonized'): return

        def signal_handler(*args, **kwargs):
            fireEvent('app.shutdown', single = True)

        signal.signal(signal.SIGINT, signal_handler)
        signal.signal(signal.SIGTERM, signal_handler)
Example #25
0
def providerScore(provider):

    try:
        score = tryInt(Env.setting('extra_score', section = provider.lower(), default = 0))
    except:
        score = 0

    return score
Example #26
0
    def get(self, *args, **kwargs):
        api_key = None

        try:
            username = Env.setting('username')
            password = Env.setting('password')

            if (self.get_argument('u') == md5(username) or not username) and (self.get_argument('p') == password or not password):
                api_key = Env.setting('api_key')

            self.write({
                'success': api_key is not None,
                'api_key': api_key
            })
        except:
            log.error('Failed doing key request: %s', (traceback.format_exc()))
            self.write({'success': False, 'error': 'Failed returning results'})
Example #27
0
    def __init__(self):

        addEvent('app.load', self.setCrons)

        if not Env.get('dev'):
            addEvent('app.load', self.addMovies)

        addEvent('setting.save.automation.hour.after', self.setCrons)
Example #28
0
    def replaceWith(self, path):
        path = sp(path)
        app_dir = Env.get('app_dir')
        data_dir = Env.get('data_dir')

        # Get list of files we want to overwrite
        removePyc(app_dir)
        existing_files = []
        for root, subfiles, filenames in os.walk(app_dir):
            for filename in filenames:
                existing_files.append(os.path.join(root, filename))

        for root, subfiles, filenames in os.walk(path):
            for filename in filenames:
                fromfile = os.path.join(root, filename)
                tofile = os.path.join(app_dir, fromfile.replace(path + os.path.sep, ''))

                if not Env.get('dev'):
                    try:
                        if os.path.isfile(tofile):
                            os.remove(tofile)

                        dirname = os.path.dirname(tofile)
                        if not os.path.isdir(dirname):
                            self.makeDir(dirname)

                        shutil.move(fromfile, tofile)
                        try:
                            existing_files.remove(tofile)
                        except ValueError:
                            pass
                    except:
                        log.error('Failed overwriting file "%s": %s', (tofile, traceback.format_exc()))
                        return False

        for still_exists in existing_files:

            if data_dir in still_exists:
                continue

            try:
                os.remove(still_exists)
            except:
                log.error('Failed removing non-used file: %s', traceback.format_exc())

        return True
Example #29
0
    def checkMessages(self):

        prop_name = 'messages.last_check'
        last_check = tryInt(Env.prop(prop_name, default = 0))

        messages = fireEvent('cp.messages', last_check = last_check, single = True) or []

        for message in messages:
            if message.get('time') > last_check:
                message['sticky'] = True  # Always sticky core messages

                message_type = 'core.message.important' if message.get('important') else 'core.message'
                fireEvent(message_type, message = message.get('message'), data = message)

            if last_check < message.get('time'):
                last_check = message.get('time')

        Env.prop(prop_name, value = last_check)
Example #30
0
    def fillResult(self, result):

        defaults = {
            'id': 0,
            'protocol': self.provider.protocol,
            'type': self.provider.type,
            'provider': self.provider.getName(),
            'download': self.provider.loginDownload if self.provider.urls.get('login') else self.provider.download,
            'seed_ratio': Env.setting('seed_ratio', section = self.provider.getName().lower(), default = ''),
            'seed_time': Env.setting('seed_time', section = self.provider.getName().lower(), default = ''),
            'url': '',
            'name': '',
            'age': 0,
            'size': 0,
            'description': '',
            'score': 0
        }

        return mergeDicts(defaults, result)