예제 #1
0
 def __init__(self):
     Rating.do = self
     self.shutdown = False
     self.queue = OrderedSetQueue()
     try:
         self.version, self.ratings, self.nzo_indexer_map = sabnzbd.load_admin(
             "Rating.sab", silent=not cfg.rating_enable())
         if self.version == 1:
             ratings = {}
             for k, v in self.ratings.iteritems():
                 ratings[k] = NzbRatingV2().to_v2(v)
             self.ratings = ratings
             self.version = 2
         if (self.version != Rating.VERSION):
             raise Exception()
     except:
         self.version = Rating.VERSION
         self.ratings = {}
         self.nzo_indexer_map = {}
     Thread.__init__(self)
     if not _HAVE_SSL:
         logging.warning(T('Ratings server requires secure connection'))
         self.stop()
예제 #2
0
파일: rating.py 프로젝트: labrys/sabnzbd
 def __init__(self):
     Rating.do = self
     self.shutdown = False
     self.queue = OrderedSetQueue()
     try:
         self.version, self.ratings, self.nzo_indexer_map = sabnzbd.load_admin("Rating.sab",
                                                                               silent=not cfg.rating_enable())
         if self.version == 1:
             ratings = {}
             for k, v in self.ratings.iteritems():
                 ratings[k] = NzbRatingV2().to_v2(v)
             self.ratings = ratings
             self.version = 2
         if self.version != Rating.VERSION:
             raise Exception()
     except:
         self.version = Rating.VERSION
         self.ratings = {}
         self.nzo_indexer_map = {}
     Thread.__init__(self)
     if not _HAVE_SSL:
         logging.warning(T('Ratings server requires secure connection'))
         self.stop()
예제 #3
0
파일: rating.py 프로젝트: labrys/sabnzbd
class Rating(Thread):
    VERSION = 2

    VOTE_UP = 1
    VOTE_DOWN = 2

    FLAG_OK = 0
    FLAG_SPAM = 1
    FLAG_ENCRYPTED = 2
    FLAG_EXPIRED = 3
    FLAG_OTHER = 4
    FLAG_COMMENT = 5

    CHANGED_USER_VIDEO = 0x01
    CHANGED_USER_AUDIO = 0x02
    CHANGED_USER_VOTE = 0x04
    CHANGED_USER_FLAG = 0x08
    CHANGED_AUTO_FLAG = 0x10

    do = None

    def __init__(self):
        Rating.do = self
        self.shutdown = False
        self.queue = OrderedSetQueue()
        try:
            self.version, self.ratings, self.nzo_indexer_map = sabnzbd.load_admin("Rating.sab",
                                                                                  silent=not cfg.rating_enable())
            if self.version == 1:
                ratings = {}
                for k, v in self.ratings.iteritems():
                    ratings[k] = NzbRatingV2().to_v2(v)
                self.ratings = ratings
                self.version = 2
            if self.version != Rating.VERSION:
                raise Exception()
        except:
            self.version = Rating.VERSION
            self.ratings = {}
            self.nzo_indexer_map = {}
        Thread.__init__(self)
        if not _HAVE_SSL:
            logging.warning(T('Ratings server requires secure connection'))
            self.stop()

    def stop(self):
        self.shutdown = True
        self.queue.put(None)  # Unblock queue

    def run(self):
        self.shutdown = False
        while not self.shutdown:
            time.sleep(1)
            if not cfg.rating_enable():
                continue
            indexer_id = self.queue.get()
            try:
                if indexer_id and not self._send_rating(indexer_id):
                    for unused in range(0, 60):
                        if self.shutdown:
                            break
                        time.sleep(1)
                    self.queue.put(indexer_id)
            except:
                pass
        logging.debug('Stopping ratings')

    @synchronized(RATING_LOCK)
    def save(self):
        if self.ratings and self.nzo_indexer_map:
            sabnzbd.save_admin((self.version, self.ratings, self.nzo_indexer_map), "Rating.sab")

    # The same file may be uploaded multiple times creating a new nzo_id each time
    @synchronized(RATING_LOCK)
    def add_rating(self, indexer_id, nzo_id, fields):
        if indexer_id and nzo_id:
            logging.debug('Add rating (%s, %s: %s, %s, %s, %s)', indexer_id, nzo_id, fields['video'], fields['audio'], fields['voteup'], fields['votedown'])
            try:
                rating = self.ratings.get(indexer_id, NzbRatingV2())
                if fields['video'] and fields['videocnt']:
                    rating.avg_video = int(float(fields['video']))
                    rating.avg_video_cnt = int(float(fields['videocnt']))
                if fields['audio'] and fields['audiocnt']:
                    rating.avg_audio = int(float(fields['audio']))
                    rating.avg_audio_cnt = int(float(fields['audiocnt']))
                if fields['voteup']:
                    rating.avg_vote_up = int(float(fields['voteup']))
                if fields['votedown']:
                    rating.avg_vote_down = int(float(fields['votedown']))
                if fields['spam']:
                    rating.avg_spam_cnt = int(float(fields['spam']))
                if fields['confirmed-spam']:
                    rating.avg_spam_confirm = (fields['confirmed-spam'].lower() == 'yes')
                if fields['passworded']:
                    rating.avg_encrypted_cnt = int(float(fields['passworded']))
                if fields['confirmed-passworded']:
                    rating.avg_encrypted_confirm = (fields['confirmed-passworded'].lower() == 'yes')
                # Indexers can supply a full URL or just a host
                if fields['host']:
                    rating.host = fields['host'][0] if fields['host'] and isinstance(fields['host'], list) else fields['host']
                if fields['url']:
                    rating.host = fields['url'][0] if fields['url'] and isinstance(fields['url'], list) else fields['url']
                self.ratings[indexer_id] = rating
                self.nzo_indexer_map[nzo_id] = indexer_id
            except:
                pass

    @synchronized(RATING_LOCK)
    def update_user_rating(self, nzo_id, video, audio, vote, flag, flag_detail=None):
        logging.debug('Updating user rating (%s: %s, %s, %s, %s)', nzo_id, video, audio, vote, flag)
        if nzo_id not in self.nzo_indexer_map:
            logging.warning(T('Indexer id (%s) not found for ratings file'), nzo_id)
            return
        indexer_id = self.nzo_indexer_map[nzo_id]
        rating = self.ratings[indexer_id]
        if video:
            rating.user_video = int(video)
            rating.avg_video = int((rating.avg_video_cnt * rating.avg_video + rating.user_video) / (rating.avg_video_cnt + 1))
            rating.changed = rating.changed | Rating.CHANGED_USER_VIDEO
        if audio:
            rating.user_audio = int(audio)
            rating.avg_audio = int((rating.avg_audio_cnt * rating.avg_audio + rating.user_audio) / (rating.avg_audio_cnt + 1))
            rating.changed = rating.changed | Rating.CHANGED_USER_AUDIO
        if flag:
            rating.user_flag = {'val': int(flag), 'detail': flag_detail}
            rating.changed = rating.changed | Rating.CHANGED_USER_FLAG
        if vote:
            rating.changed = rating.changed | Rating.CHANGED_USER_VOTE
            if int(vote) == Rating.VOTE_UP:
                rating.avg_vote_up += 1
                # Update if already a vote
                if rating.user_vote and rating.user_vote == Rating.VOTE_DOWN:
                    rating.avg_vote_down -= 1
            else:
                rating.avg_vote_down += 1
                # Update if already a vote
                if rating.user_vote and rating.user_vote == Rating.VOTE_UP:
                    rating.avg_vote_up -= 1

            rating.user_vote = int(vote)
        self.queue.put(indexer_id)

    @synchronized(RATING_LOCK)
    def update_auto_flag(self, nzo_id, flag, flag_detail=None):
        if not flag or not cfg.rating_enable() or not cfg.rating_feedback() or (nzo_id not in self.nzo_indexer_map):
            return
        logging.debug('Updating auto flag (%s: %s)', nzo_id, flag)
        indexer_id = self.nzo_indexer_map[nzo_id]
        rating = self.ratings[indexer_id]
        rating.auto_flag = {'val': int(flag), 'detail': flag_detail}
        rating.changed = rating.changed | Rating.CHANGED_AUTO_FLAG
        self.queue.put(indexer_id)

    @synchronized(RATING_LOCK)
    def get_rating_by_nzo(self, nzo_id):
        if nzo_id not in self.nzo_indexer_map:
            return None
        return copy.copy(self.ratings[self.nzo_indexer_map[nzo_id]])

    @synchronized(RATING_LOCK)
    def _get_rating_by_indexer(self, indexer_id):
        return copy.copy(self.ratings[indexer_id])

    def _flag_request(self, val, flag_detail, auto):
        if val == Rating.FLAG_SPAM:
            return {'m': 'rs', 'auto': auto}
        if val == Rating.FLAG_ENCRYPTED:
            return {'m': 'rp', 'auto': auto}
        if val == Rating.FLAG_EXPIRED:
            expired_host = flag_detail if flag_detail and len(flag_detail) > 0 else 'Other'
            return {'m': 'rpr', 'pr': expired_host, 'auto': auto}
        if (val == Rating.FLAG_OTHER) and flag_detail and len(flag_detail) > 0:
            return {'m': 'o', 'r': flag_detail}
        if (val == Rating.FLAG_COMMENT) and flag_detail and len(flag_detail) > 0:
            return {'m': 'rc', 'r': flag_detail}

    def _send_rating(self, indexer_id):
        logging.debug('Updating indexer rating (%s)', indexer_id)

        api_key = cfg.rating_api_key()
        rating_host = cfg.rating_host()
        rating_url = _RATING_URL
        if not api_key:
            return True

        requests = []
        _headers = {'User-agent': 'SABnzbd+/%s' % sabnzbd.version.__version__, 'Content-type': 'application/x-www-form-urlencoded'}
        rating = self._get_rating_by_indexer(indexer_id)  # Requesting info here ensures always have latest information even on retry
        if hasattr(rating, 'host') and rating.host:
            host_parsed = urlparse.urlparse(rating.host)
            rating_host = host_parsed.netloc
            # Is it an URL or just a HOST?
            if host_parsed.path and host_parsed.path != '/':
                rating_url = host_parsed.path + '?' + host_parsed.query if host_parsed.query else host_parsed.path
        if not rating_host:
            return True
        if rating.changed & Rating.CHANGED_USER_VIDEO:
            requests.append({'m': 'r', 'r': 'videoQuality', 'rn': rating.user_video})
        if rating.changed & Rating.CHANGED_USER_AUDIO:
            requests.append({'m': 'r', 'r': 'audioQuality', 'rn': rating.user_audio})
        if rating.changed & Rating.CHANGED_USER_VOTE:
            up_down = 'up' if rating.user_vote == Rating.VOTE_UP else 'down'
            requests.append({'m': 'v', 'v': up_down, 'r': 'overall'})
        if rating.changed & Rating.CHANGED_USER_FLAG:
            requests.append(self._flag_request(rating.user_flag.get('val'), rating.user_flag.get('detail'), 0))
        if rating.changed & Rating.CHANGED_AUTO_FLAG:
            requests.append(self._flag_request(rating.auto_flag.get('val'), rating.auto_flag.get('detail'), 1))

        try:
            conn = httplib.HTTPSConnection(rating_host)
            for request in filter(lambda r: r is not None, requests):
                if api_key:
                    request['apikey'] = api_key
                request['i'] = indexer_id
                conn.request('POST', rating_url, urllib.urlencode(request), headers=_headers)

                response = conn.getresponse()
                response.read()
                if response.status == httplib.UNAUTHORIZED:
                    _warn('Ratings server unauthorized user')
                    return False
                elif response.status != httplib.OK:
                    _warn('Ratings server failed to process request (%s, %s)' % (response.status, response.reason))
                    return False
            self.ratings[indexer_id].changed = self.ratings[indexer_id].changed & ~rating.changed
            _reset_warn()
            return True
        except:
            _warn('Problem accessing ratings server: %s' % rating_host)
            return False
예제 #4
0
class Rating(Thread):
    VERSION = 2

    VOTE_UP = 1
    VOTE_DOWN = 2

    FLAG_OK = 0
    FLAG_SPAM = 1
    FLAG_ENCRYPTED = 2
    FLAG_EXPIRED = 3
    FLAG_OTHER = 4
    FLAG_COMMENT = 5

    CHANGED_USER_VIDEO = 0x01
    CHANGED_USER_AUDIO = 0x02
    CHANGED_USER_VOTE = 0x04
    CHANGED_USER_FLAG = 0x08
    CHANGED_AUTO_FLAG = 0x10

    do = None

    def __init__(self):
        Rating.do = self
        self.shutdown = False
        self.queue = OrderedSetQueue()
        try:
            self.version, self.ratings, self.nzo_indexer_map = sabnzbd.load_admin(
                "Rating.sab", silent=not cfg.rating_enable())
            if self.version == 1:
                ratings = {}
                for k, v in self.ratings.iteritems():
                    ratings[k] = NzbRatingV2().to_v2(v)
                self.ratings = ratings
                self.version = 2
            if (self.version != Rating.VERSION):
                raise Exception()
        except:
            self.version = Rating.VERSION
            self.ratings = {}
            self.nzo_indexer_map = {}
        Thread.__init__(self)
        if not _HAVE_SSL:
            logging.warning(T('Ratings server requires secure connection'))
            self.stop()

    def stop(self):
        self.shutdown = True
        self.queue.put(None)  # Unblock queue

    def run(self):
        self.shutdown = False
        while not self.shutdown:
            time.sleep(1)
            if not cfg.rating_enable():
                continue
            indexer_id = self.queue.get()
            try:
                if indexer_id and not self._send_rating(indexer_id):
                    for unused in range(0, 60):
                        if self.shutdown:
                            break
                        time.sleep(1)
                    self.queue.put(indexer_id)
            except:
                pass
        logging.debug('Stopping ratings')

    @synchronized(RATING_LOCK)
    def save(self):
        if self.ratings and self.nzo_indexer_map:
            sabnzbd.save_admin(
                (self.version, self.ratings, self.nzo_indexer_map),
                "Rating.sab")

    # The same file may be uploaded multiple times creating a new nzo_id each time
    @synchronized(RATING_LOCK)
    def add_rating(self, indexer_id, nzo_id, host, fields):
        if indexer_id and nzo_id and (len(fields) == 10):
            logging.debug('Add rating (%s, %s: %s, %s, %s, %s)', indexer_id,
                          nzo_id, fields['video'], fields['audio'],
                          fields['voteup'], fields['votedown'])
            try:
                rating = self.ratings.get(indexer_id, NzbRatingV2())
                if fields['video'] and fields['videocnt']:
                    rating.avg_video = int(float(fields['video']))
                    rating.avg_video_cnt = int(float(fields['videocnt']))
                if fields['audio'] and fields['audiocnt']:
                    rating.avg_audio = int(float(fields['audio']))
                    rating.avg_audio_cnt = int(float(fields['audiocnt']))
                if fields['voteup']:
                    rating.avg_vote_up = int(float(fields['voteup']))
                if fields['votedown']:
                    rating.avg_vote_down = int(float(fields['votedown']))
                if fields['spam']:
                    rating.avg_spam_cnt = int(float(fields['spam']))
                if fields['confirmed-spam']:
                    rating.avg_spam_confirm = (
                        fields['confirmed-spam'].lower() == 'yes')
                if fields['passworded']:
                    rating.avg_encrypted_cnt = int(float(fields['passworded']))
                if fields['confirmed-passworded']:
                    rating.avg_encrypted_confirm = (
                        fields['confirmed-passworded'].lower() == 'yes')
                rating.host = host[0] if host and isinstance(host,
                                                             list) else host
                self.ratings[indexer_id] = rating
                self.nzo_indexer_map[nzo_id] = indexer_id
            except:
                pass

    @synchronized(RATING_LOCK)
    def update_user_rating(self,
                           nzo_id,
                           video,
                           audio,
                           vote,
                           flag,
                           flag_detail=None):
        logging.debug('Updating user rating (%s: %s, %s, %s, %s)', nzo_id,
                      video, audio, vote, flag)
        if nzo_id not in self.nzo_indexer_map:
            logging.warning(T('Indexer id (%s) not found for ratings file'),
                            nzo_id)
            return
        indexer_id = self.nzo_indexer_map[nzo_id]
        rating = self.ratings[indexer_id]
        if video:
            rating.user_video = int(video)
            rating.avg_video = int(
                (rating.avg_video_cnt * rating.avg_video + rating.user_video) /
                (rating.avg_video_cnt + 1))
            rating.changed = rating.changed | Rating.CHANGED_USER_VIDEO
        if audio:
            rating.user_audio = int(audio)
            rating.avg_audio = int(
                (rating.avg_audio_cnt * rating.avg_audio + rating.user_audio) /
                (rating.avg_audio_cnt + 1))
            rating.changed = rating.changed | Rating.CHANGED_USER_AUDIO
        if flag:
            rating.user_flag = {'val': int(flag), 'detail': flag_detail}
            rating.changed = rating.changed | Rating.CHANGED_USER_FLAG
        if vote:
            rating.changed = rating.changed | Rating.CHANGED_USER_VOTE
            if int(vote) == Rating.VOTE_UP:
                rating.avg_vote_up += 1
                # Update if already a vote
                if rating.user_vote and rating.user_vote == Rating.VOTE_DOWN:
                    rating.avg_vote_down -= 1
            else:
                rating.avg_vote_down += 1
                # Update if already a vote
                if rating.user_vote and rating.user_vote == Rating.VOTE_UP:
                    rating.avg_vote_up -= 1

            rating.user_vote = int(vote)
        self.queue.put(indexer_id)

    @synchronized(RATING_LOCK)
    def update_auto_flag(self, nzo_id, flag, flag_detail=None):
        if not flag or not cfg.rating_enable() or not cfg.rating_feedback(
        ) or (nzo_id not in self.nzo_indexer_map):
            return
        logging.debug('Updating auto flag (%s: %s)', nzo_id, flag)
        indexer_id = self.nzo_indexer_map[nzo_id]
        rating = self.ratings[indexer_id]
        rating.auto_flag = {'val': int(flag), 'detail': flag_detail}
        rating.changed = rating.changed | Rating.CHANGED_AUTO_FLAG
        self.queue.put(indexer_id)

    @synchronized(RATING_LOCK)
    def get_rating_by_nzo(self, nzo_id):
        if nzo_id not in self.nzo_indexer_map:
            return None
        return copy.copy(self.ratings[self.nzo_indexer_map[nzo_id]])

    @synchronized(RATING_LOCK)
    def _get_rating_by_indexer(self, indexer_id):
        return copy.copy(self.ratings[indexer_id])

    def _flag_request(self, val, flag_detail, auto):
        if val == Rating.FLAG_SPAM:
            return {'m': 'rs', 'auto': auto}
        if val == Rating.FLAG_ENCRYPTED:
            return {'m': 'rp', 'auto': auto}
        if val == Rating.FLAG_EXPIRED:
            expired_host = flag_detail if flag_detail and len(
                flag_detail) > 0 else 'Other'
            return {'m': 'rpr', 'pr': expired_host, 'auto': auto}
        if (val == Rating.FLAG_OTHER) and flag_detail and len(flag_detail) > 0:
            return {'m': 'o', 'r': flag_detail}
        if (val == Rating.FLAG_COMMENT
            ) and flag_detail and len(flag_detail) > 0:
            return {'m': 'rc', 'r': flag_detail}

    def _send_rating(self, indexer_id):
        logging.debug('Updating indexer rating (%s)', indexer_id)

        api_key = cfg.rating_api_key()
        rating_host = cfg.rating_host()
        if not api_key:
            return True

        requests = []
        _headers = {
            'User-agent': 'SABnzbd+/%s' % sabnzbd.version.__version__,
            'Content-type': 'application/x-www-form-urlencoded'
        }
        rating = self._get_rating_by_indexer(
            indexer_id
        )  # Requesting info here ensures always have latest information even on retry
        if hasattr(rating, 'host') and rating.host:
            rating_host = rating.host
        if not rating_host:
            return True
        if rating.changed & Rating.CHANGED_USER_VIDEO:
            requests.append({
                'm': 'r',
                'r': 'videoQuality',
                'rn': rating.user_video
            })
        if rating.changed & Rating.CHANGED_USER_AUDIO:
            requests.append({
                'm': 'r',
                'r': 'audioQuality',
                'rn': rating.user_audio
            })
        if rating.changed & Rating.CHANGED_USER_VOTE:
            up_down = 'up' if rating.user_vote == Rating.VOTE_UP else 'down'
            requests.append({'m': 'v', 'v': up_down, 'r': 'overall'})
        if rating.changed & Rating.CHANGED_USER_FLAG:
            requests.append(
                self._flag_request(rating.user_flag.get('val'),
                                   rating.user_flag.get('detail'), 0))
        if rating.changed & Rating.CHANGED_AUTO_FLAG:
            requests.append(
                self._flag_request(rating.auto_flag.get('val'),
                                   rating.auto_flag.get('detail'), 1))

        try:
            conn = httplib.HTTPSConnection(rating_host)
            for request in filter(lambda r: r is not None, requests):
                request['apikey'] = api_key
                request['i'] = indexer_id
                conn.request('POST',
                             RATING_URL,
                             urllib.urlencode(request),
                             headers=_headers)

                response = conn.getresponse()
                response.read()
                if response.status == httplib.UNAUTHORIZED:
                    _warn('Ratings server unauthorized user')
                    return False
                elif response.status != httplib.OK:
                    _warn('Ratings server failed to process request (%s, %s)' %
                          (response.status, response.reason))
                    return False
            self.ratings[indexer_id].changed = self.ratings[
                indexer_id].changed & ~rating.changed
            _reset_warn()
            return True
        except:
            _warn('Problem accessing ratings server: %s' % rating_host)
            return False