def handle(self, *args, **options): skip = options.get('skip') total = EpisodeUserState.view('episode_states/by_user_episode', limit=0, ).total_rows db = get_main_database() actions = Counter() actions['merged'] = 0 for n in count(skip): first = EpisodeUserState.view('episode_states/by_user_episode', skip = n, include_docs = True, limit = 1, ) first = list(first) if not first: break first = first[0] states = EpisodeUserState.view('episode_states/by_user_episode', key = [first.user, first.episode], include_docs = True, ) states = list(states) l1 = len(states) # we don't want to delete this one states.remove(first) assert len(states) == l1-1 if states: updater = get_updater(states) obj_funs = [(first, updater)] + [(state, do_delete) for state in states] bulk_save_retry(db, obj_funs) merged = len(states)-1 actions['merged'] += merged total -= merged status_str = ', '.join('%s: %d' % x for x in actions.items()) progress(n+1, total, status_str)
def get_all_states(self): from mygpo.users.models import EpisodeUserState r = EpisodeUserState.view('episode_states/by_podcast_episode', startkey = [self.podcast, self._id, None], endkey = [self.podcast, self._id, {}], include_docs=True) return iter(r)
def get_episode_states(podcast): r = EpisodeUserState.view('users/episode_states_by_podcast_episode', startkey = [podcast.get_id(), None, None], endkey = [podcast.get_id(), {}, {}], include_docs = True ) return r
def update_episodes(user, actions, now, ua_string): update_urls = [] grouped_actions = defaultdict(list) # group all actions by their episode for action in actions: podcast_url = action['podcast'] podcast_url = sanitize_append(podcast_url, 'podcast', update_urls) if podcast_url == '': continue episode_url = action['episode'] episode_url = sanitize_append(episode_url, 'episode', update_urls) if episode_url == '': continue act = parse_episode_action(action, user, update_urls, now, ua_string) grouped_actions[ (podcast_url, episode_url) ].append(act) # Prepare the updates for each episode state obj_funs = [] for (p_url, e_url), action_list in grouped_actions.iteritems(): episode_state = EpisodeUserState.for_ref_urls(user, p_url, e_url) fun = partial(update_episode_actions, action_list=action_list) obj_funs.append( (episode_state, fun) ) db = get_main_database() bulk_save_retry(db, obj_funs) return update_urls
def handle_obj(self, seq, doc, actions): state = EpisodeUserState.wrap(doc) episode = episode_by_id(state.episode) if not episode: actions['missing'] += 1 return listeners = episode_listener_count(episode) updated = set_episode_listeners(episode, listeners) actions['updated'] += int(updated)
def listener_count(self): """ returns the number of users that have listened to this podcast """ from mygpo.users.models import EpisodeUserState r = EpisodeUserState.view('listeners/by_podcast', startkey = [self.get_id(), None], endkey = [self.get_id(), {}], group = True, group_level = 1, reduce = True, ) return r.first()['value'] if r else 0
def listener_count(self, start=None, end={}): """ returns the number of users that have listened to this episode """ from mygpo.users.models import EpisodeUserState r = EpisodeUserState.view('listeners/by_episode', startkey = [self._id, start], endkey = [self._id, end], reduce = True, group = True, group_level = 1 ) return r.first()['value'] if r else 0
def handle_obj(self, seq, doc, actions): state = EpisodeUserState.wrap(doc) try: episode = Episode.get(state.episode) except ResourceNotFound: episode = None if episode: listeners = episode.listener_count() updated = self.update(episode=episode, listeners=listeners) actions['updated'] += updated else: actions['missing'] += 1
def episode_listener_counts(self): """ (Episode-Id, listener-count) tuples for episodes w/ listeners """ from mygpo.users.models import EpisodeUserState r = EpisodeUserState.view('listeners/by_podcast_episode', startkey = [self.get_id(), None, None], endkey = [self.get_id(), {}, {}], group = True, group_level = 2, reduce = True, ) for res in r: episode = res['key'][1] listeners = res['value'] yield (episode, listeners)
def listener_count_timespan(self, start=None, end={}): """ returns (date, listener-count) tuples for all days w/ listeners """ if isinstance(start, datetime): start = start.isoformat() if isinstance(end, datetime): end = end.isoformat() from mygpo.users.models import EpisodeUserState r = EpisodeUserState.view('listeners/by_podcast', startkey = [self.get_id(), start], endkey = [self.get_id(), end], group = True, group_level = 2, reduce = True, ) for res in r: date = parser.parse(res['key'][1]).date() listeners = res['value'] yield (date, listeners)
def episode_state_for_user_episode(user, episode): if not user: raise QueryParameterMissing('user') if not episode: raise QueryParameterMissing('episode') key = 'episode-state-userid-%s-episodeid-%s' % (sha1(user._id).hexdigest(), sha1(episode._id).hexdigest()) # Disabled as cache invalidation does not work properly # state = cache.get(key) # if state: # return state udb = get_userdata_database() state = get_single_result(udb, 'episode_states/by_user_episode', key = [user._id, episode._id], include_docs = True, limit = 1, schema = EpisodeUserState, ) if state: cache.set(key, state) return state else: podcast = podcast_by_id(episode.podcast) state = EpisodeUserState() state.episode = episode._id state.podcast = episode.podcast state.user = user._id state.ref_url = episode.url state.podcast_ref_url = podcast.url # don't cache here, because the state is saved by the calling function return state
def get_user_state(self, user): from mygpo.users.models import EpisodeUserState return EpisodeUserState.for_user_episode(user, self)