Ejemplo n.º 1
0
    def __init__(self, main):
        super(ListSource, self).__init__(main)

        # Differs
        self._list_differ = ListDiffer()
        self._lists_differ = ListsDiffer()
Ejemplo n.º 2
0
    def __init__(self, main):
        super(ListSource, self).__init__(main)

        # Differs
        self._list_differ = ListDiffer()
        self._lists_differ = ListsDiffer()
Ejemplo n.º 3
0
class ListSource(Source):
    def __init__(self, main):
        super(ListSource, self).__init__(main)

        # Differs
        self._list_differ = ListDiffer()
        self._lists_differ = ListsDiffer()

    def refresh(self, username):
        if enums.Media.Lists not in self.media:
            return

        # Emit "started" event
        self.events.emit('refresh.list.started', source='list', total=self.steps())
        current_step = 0

        if enums.Data.Liked in self.data:
            # Update `current` progress, emit "progress" event
            self.events.emit('refresh.list.progress', source='list', current=current_step)
            current_step += 1

            # Refresh liked lists, yield changes
            for change in self.refresh_lists(username, enums.Data.Liked, Trakt['users'].likes('lists', pagination=True)):
                yield change

        if enums.Data.Personal in self.data:
            # Update `current` progress, emit "progress" event
            self.events.emit('refresh.list.progress', source='list', current=current_step)
            current_step += 1

            # Refresh personal lists, yield changes
            for change in self.refresh_lists(username, enums.Data.Personal, Trakt['users/*/lists'].get(username)):
                yield change

        # Emit "finished" event
        self.events.emit('refresh.list.finished', source='list', current=current_step)

    def refresh_lists(self, username, data, lists):
        key = (enums.Media.Lists, data)

        # Resolve lists
        lists = dict([
            (t_list.id, t_list)
            for t_list in lists
        ])

        # Find changes
        collection = self.get_collection(username, *key)
        changes = self.diff(key, collection['store'], lists)

        if changes is not None:
            yield self._collection_key(*key), changes

        # Store lists in cache
        self.update_store((username, ) + key, lists)

        # Store list items in cache, yield changes
        for l in lists.itervalues():
            for change in self.refresh_list(username, data, l):
                yield change

    def refresh_list(self, username, data, t_list):
        key = (enums.Media.Lists, data, t_list.id)

        collection = self.get_collection(username, *key)
        timestamp_key = enums.Data.get_timestamp_key(data)

        # Retrieve current timestamp from trakt.tv
        current = getattr(t_list, timestamp_key)

        # Determine if cached items are still valid
        last = collection['timestamps'].get(timestamp_key)

        if last and last.tzinfo is None:
            # Missing "tzinfo", assume UTC
            last = last.replace(tzinfo=tzutc())

        if last and last == current:
            # Latest data already cached
            return

        # Fetch latest data
        store = self.fetch(t_list)

        if store is None:
            # Unable to retrieve data
            return

        # Find changes
        changes = self.diff(key, collection['store'], store)

        # Update collection
        self.update_store((username, ) + key, store)

        collection['timestamps'][timestamp_key] = current

        if changes is None:
            # No changes detected
            return

        yield self._collection_key(*key), changes

    def steps(self):
        result = 0

        if enums.Data.Liked in self.data:
            result += 1

        if enums.Data.Personal in self.data:
            result += 1

        return result

    def diff(self, key, base, current):
        media, data, list_id = (None, None, None)

        if len(key) == 2:
            media, data = key
        elif len(key) == 3:
            media, data, list_id = key
        else:
            log.warn('Unsupported key: %r', key)
            return None

        if not base:
            if not current:
                return None

            # No `base` data stored, assume all the `current` items have been added
            if media != enums.Media.Lists:
                raise Exception('Unknown media type: %r', media)

            if list_id is not None:
                result = ListResult(self._list_differ)
            else:
                result = ListsResult(self._lists_differ)

            # Update `result` with current items
            result.add(current)

            return result

        if media != enums.Media.Lists:
            raise Exception('Unknown media type: %r', media)

        if list_id is not None:
            result = self._list_differ.run(base, current)
        else:
            result = self._lists_differ.run(base, current)

        if not result.changes:
            return None

        return result

    def fetch(self, t_list):
        log.debug('Fetching list: %r', t_list)

        try:
            return dict([
                (self._item_key(t_item), t_item)
                for t_item in t_list.items()
            ])
        except Exception, ex:
            log.warn('Unable to retrieve items for list %r - %s', t_list, ex, exc_info=True)

        return None
Ejemplo n.º 4
0
class ListSource(Source):
    def __init__(self, main):
        super(ListSource, self).__init__(main)

        # Differs
        self._list_differ = ListDiffer()
        self._lists_differ = ListsDiffer()

    def refresh(self, username):
        if enums.Media.Lists not in self.media:
            return

        # Emit "started" event
        self.events.emit('refresh.list.started', source='list', total=self.steps())
        current_step = 0

        if enums.Data.Liked in self.data:
            # Update `current` progress, emit "progress" event
            self.events.emit('refresh.list.progress', source='list', current=current_step)
            current_step += 1

            # Refresh liked lists, yield changes
            for change in self.refresh_lists(username, enums.Data.Liked, Trakt['users'].likes('lists')):
                yield change

        if enums.Data.Personal in self.data:
            # Update `current` progress, emit "progress" event
            self.events.emit('refresh.list.progress', source='list', current=current_step)
            current_step += 1

            # Refresh personal lists, yield changes
            for change in self.refresh_lists(username, enums.Data.Personal, Trakt['users/*/lists'].get(username)):
                yield change

        # Emit "finished" event
        self.events.emit('refresh.list.finished', source='list', current=current_step)

    def refresh_lists(self, username, data, lists):
        key = (enums.Media.Lists, data)

        # Resolve lists
        lists = dict([
            (t_list.id, t_list)
            for t_list in lists
        ])

        # Find changes
        collection = self.get_collection(username, *key)
        changes = self.diff(key, collection['store'], lists)

        if changes is not None:
            yield self._collection_key(*key), changes

        # Store lists in cache
        self.update_store((username, ) + key, lists)

        # Store list items in cache, yield changes
        for l in lists.itervalues():
            for change in self.refresh_list(username, data, l):
                yield change

    def refresh_list(self, username, data, t_list):
        key = (enums.Media.Lists, data, t_list.id)

        collection = self.get_collection(username, *key)
        timestamp_key = enums.Data.get_timestamp_key(data)

        # Retrieve current timestamp from trakt.tv
        current = getattr(t_list, timestamp_key)

        # Determine if cached items are still valid
        last = collection['timestamps'].get(timestamp_key)

        if last and last.tzinfo is None:
            # Missing "tzinfo", assume UTC
            last = last.replace(tzinfo=tzutc())

        if last and last == current:
            # Latest data already cached
            return

        # Fetch latest data
        store = self.fetch(t_list)

        if store is None:
            # Unable to retrieve data
            return

        # Find changes
        changes = self.diff(key, collection['store'], store)

        # Update collection
        self.update_store((username, ) + key, store)

        collection['timestamps'][timestamp_key] = current

        if changes is None:
            # No changes detected
            return

        yield self._collection_key(*key), changes

    def steps(self):
        result = 0

        if enums.Data.Liked in self.data:
            result += 1

        if enums.Data.Personal in self.data:
            result += 1

        return result

    def diff(self, key, base, current):
        media, data, list_id = (None, None, None)

        if len(key) == 2:
            media, data = key
        elif len(key) == 3:
            media, data, list_id = key
        else:
            log.warn('Unsupported key: %r', key)
            return None

        if not base:
            if not current:
                return None

            # No `base` data stored, assume all the `current` items have been added
            if media != enums.Media.Lists:
                raise Exception('Unknown media type: %r', media)

            if list_id is not None:
                result = ListResult(self._list_differ)
            else:
                result = ListsResult(self._lists_differ)

            # Update `result` with current items
            result.add(current)

            return result

        if media != enums.Media.Lists:
            raise Exception('Unknown media type: %r', media)

        if list_id is not None:
            result = self._list_differ.run(base, current)
        else:
            result = self._lists_differ.run(base, current)

        if not result.changes:
            return None

        return result

    def fetch(self, t_list):
        log.debug('Fetching list: %r', t_list)

        try:
            return dict([
                (self._item_key(t_item), t_item)
                for t_item in t_list.items()
            ])
        except Exception, ex:
            log.warn('Unable to retrieve items for list %r - %s', t_list, ex, exc_info=True)

        return None