move remaining queries into db module
[mygpo.git] / mygpo / db / couchdb / episode_state.py
bloba2cc887a2856471857360ce5717682f2d337796d
1 import hashlib
3 from mygpo.users.models import EpisodeUserState
4 from mygpo.db.couchdb.podcast import podcast_by_id
5 from mygpo.db.couchdb.episode import episode_for_podcast_id_url
6 from mygpo.couch import get_main_database
7 from mygpo.cache import cache_result
11 def episode_state_for_user_episode(user, episode):
12 r = EpisodeUserState.view('episode_states/by_user_episode',
13 key = [user._id, episode._id],
14 include_docs = True,
15 limit = 1,
18 if r:
19 return r.first()
21 else:
22 podcast = podcast_by_id(episode.podcast)
24 state = EpisodeUserState()
25 state.episode = episode._id
26 state.podcast = episode.podcast
27 state.user = user._id
28 state.ref_url = episode.url
29 state.podcast_ref_url = podcast.url
31 return state
35 def all_episode_states(episode):
36 r = EpisodeUserState.view('episode_states/by_podcast_episode',
37 startkey = [episode.podcast, episode._id, None],
38 endkey = [episode.podcast, episode._id, {}],
39 include_docs = True,
41 return list(r)
45 def all_podcast_episode_states(podcast):
46 r = EpisodeUserState.view('episode_states/by_podcast_episode',
47 startkey = [podcast.get_id(), None, None],
48 endkey = [podcast.get_id(), {}, {}],
49 include_docs = True
51 return list(r)
55 @cache_result(timeout=60*60)
56 def podcast_listener_count(episode):
57 """ returns the number of users that have listened to this podcast """
59 r = EpisodeUserState.view('listeners/by_podcast',
60 startkey = [episode.get_id(), None],
61 endkey = [episode.get_id(), {}],
62 group = True,
63 group_level = 1,
64 reduce = True,
66 return r.first()['value'] if r else 0
69 def podcast_listener_count_timespan(podcast, start=None, end={}):
70 """ returns (date, listener-count) tuples for all days w/ listeners """
72 if isinstance(start, datetime):
73 start = start.isoformat()
75 if isinstance(end, datetime):
76 end = end.isoformat()
78 r = EpisodeUserState.view('listeners/by_podcast',
79 startkey = [podcast.get_id(), start],
80 endkey = [podcast.get_id(), end],
81 group = True,
82 group_level = 2,
83 reduce = True,
86 return map(_wrap_listener_count, r)
89 @cache_result(timeout=60*60)
90 def episode_listener_counts(episode):
91 """ (Episode-Id, listener-count) tuples for episodes w/ listeners """
93 r = EpisodeUserState.view('listeners/by_podcast_episode',
94 startkey = [episode.get_id(), None, None],
95 endkey = [episode.get_id(), {}, {}],
96 group = True,
97 group_level = 2,
98 reduce = True,
101 return map(_wrap_listeners)
105 def get_podcasts_episode_states(podcast, user_id):
106 """ Returns the latest episode actions for the podcast's episodes """
108 db = get_main_database()
109 res = db.view('episode_states/by_user_podcast',
110 startkey = [user_id, podcast.get_id(), None],
111 endkey = [user_id, podcast.get_id(), {}],
114 return map(lambda r: r['value'], res)
118 def episode_listener_count(episode, start=None, end={}):
119 """ returns the number of users that have listened to this episode """
121 r = EpisodeUserState.view('listeners/by_episode',
122 startkey = [episode._id, start],
123 endkey = [episode._id, end],
124 group = True,
125 group_level = 2,
126 reduce = True,
128 return r.first()['value'] if r else 0
132 @cache_result(timeout=60*60)
133 def episode_listener_count_timespan(episode, start=None, end={}):
134 """ returns (date, listener-count) tuples for all days w/ listeners """
136 if isinstance(start, datetime):
137 start = start.isoformat()
139 if isinstance(end, datetime):
140 end = end.isoformat()
142 r = EpisodeUserState.view('listeners/by_episode',
143 startkey = [episode._id, start],
144 endkey = [episode._id, end],
145 group = True,
146 group_level = 3,
147 reduce = True,
150 return map(_wrap_listener_count, r)
154 def episode_state_for_ref_urls(user, podcast_url, episode_url):
156 cache_key = 'episode-state-%s-%s-%s' % (user._id,
157 hashlib.md5(podcast_url).hexdigest(),
158 hashlib.md5(episode_url).hexdigest())
160 state = cache.get(cache_key)
161 if state:
162 return state
164 res = EpisodeUserState.view('episode_states/by_ref_urls',
165 key = [user._id, podcast_url, episode_url],
166 limit = 1,
167 include_docs=True,
170 if res:
171 state = res.first()
172 state.ref_url = episode_url
173 state.podcast_ref_url = podcast_url
174 cache.set(cache_key, state, 60*60)
175 return state
177 else:
178 episode = episode_for_podcast_id_url(podcast_url, episode_url,
179 create=True)
180 return episode_state_for_user_episode(user, episode)
184 def get_episode_actions(user_id, since=None, until={}, podcast_id=None,
185 device_id=None):
186 """ Returns Episode Actions for the given criteria"""
188 since_str = since.strftime('%Y-%m-%dT%H:%M:%S') if since else None
189 until_str = until.strftime('%Y-%m-%dT%H:%M:%S') if until else {}
191 if since_str >= until_str:
192 return
194 if not podcast_id and not device_id:
195 view = 'episode_actions/by_user'
196 startkey = [user_id, since_str]
197 endkey = [user_id, until_str]
199 elif podcast_id and not device_id:
200 view = 'episode_actions/by_podcast'
201 startkey = [user_id, podcast_id, since_str]
202 endkey = [user_id, podcast_id, until_str]
204 elif device_id and not podcast_id:
205 view = 'episode_actions/by_device'
206 startkey = [user_id, device_id, since_str]
207 endkey = [user_id, device_id, until_str]
209 else:
210 view = 'episode_actions/by_podcast_device'
211 startkey = [user_id, podcast_id, device_id, since_str]
212 endkey = [user_id, podcast_id, device_id, until_str]
214 db = get_main_database()
215 res = db.view(view,
216 startkey = startkey,
217 endkey = endkey
220 return map(lambda r: r['value'], res)
224 @cache_result(timeout=60*60)
225 def episode_states_count():
226 r = cls.view('episode_states/by_user_episode',
227 limit = 0,
228 stale = 'update_after',
230 return r.total_rows
233 def get_nth_episode_state(n):
234 first = EpisodeUserState.view('episode_states/by_user_episode',
235 skip = n,
236 include_docs = True,
237 limit = 1,
239 return first.one() if first else None
242 def get_duplicate_episode_states(user, episode):
243 states = EpisodeUserState.view('episode_states/by_user_episode',
244 key = [user, episode],
245 include_docs = True,
247 return list(states)
250 def _wrap_listener_count(res):
251 date = parser.parse(res['key'][1]).date()
252 listeners = res['value']
253 return (date, listeners)
256 def _wrap_listeners(res):
257 episode = res['key'][1]
258 listeners = res['value']
259 return (episode, listeners)
262 def get_heatmap(podcast_id, episode_id, user_id):
263 db = get_main_database()
265 group_level = len(filter(None, [podcast_id, episode_id, user_id]))
267 r = db.view('heatmap/by_episode',
268 startkey = [podcast_id, episode_id, user_id],
269 endkey = [podcast_id, episode_id or {}, user_id or {}],
270 reduce = True,
271 group = True,
272 group_level = group_level,
273 stale = 'update_after',
276 if not r:
277 return [], []
279 else:
280 res = r.first()['value']
281 return res['heatmap'], res['borders']