move get_main_database() to mygpo.db.couchdb
[mygpo.git] / mygpo / db / couchdb / episode.py
blobc939eff75e2e6c3d3fffcbcebef0bb4af2283500
1 from hashlib import sha1
2 from datetime import datetime
4 from django.core.cache import cache
6 from mygpo.core.models import Podcast, Episode, MergedIdException
7 from mygpo.cache import cache_result
8 from mygpo.db import QueryParameterMissing
9 from mygpo.db.couchdb.utils import is_couchdb_id
10 from mygpo.db.couchdb import get_main_database
11 from mygpo.db.couchdb.podcast import podcast_for_url, podcast_for_slug_id
14 @cache_result(timeout=60*60)
15 def episode_by_id(episode_id, current_id=False):
17 if not episode_id:
18 raise QueryParameterMissing('episode_id')
20 r = Episode.view('episodes/by_id',
21 key = episode_id,
22 include_docs = True,
25 if not r:
26 return None
28 obj = r.one()
29 if current_id and obj._id != episode_id:
30 raise MergedIdException(obj, obj._id)
32 return obj
35 @cache_result(timeout=60*60)
36 def episodes_by_id(episode_ids):
38 if episode_ids is None:
39 raise QueryParameterMissing('episode_ids')
41 if not episode_ids:
42 return []
44 r = Episode.view('episodes/by_id',
45 include_docs = True,
46 keys = episode_ids,
48 return list(r)
51 @cache_result(timeout=60*60)
52 def episode_for_oldid(oldid):
54 if not oldid:
55 raise QueryParameterMissing('oldid')
57 oldid = int(oldid)
58 r = Episode.view('episodes/by_oldid',
59 key = oldid,
60 limit = 1,
61 include_docs = True,
63 return r.one() if r else None
66 @cache_result(timeout=60*60)
67 def episode_for_slug(podcast_id, episode_slug):
69 if not podcast_id:
70 raise QueryParameterMissing('podcast_id')
72 if not episode_slug:
73 raise QueryParameterMissing('episode_slug')
76 r = Episode.view('episodes/by_slug',
77 key = [podcast_id, episode_slug],
78 include_docs = True,
80 return r.first() if r else None
83 def episode_for_podcast_url(podcast_url, episode_url, create=False):
85 if not podcast_url:
86 raise QueryParameterMissing('podcast_url')
88 if not episode_url:
89 raise QueryParameterMissing('episode_url')
92 podcast = podcast_for_url(podcast_url, create=create)
94 if not podcast: # podcast does not exist and should not be created
95 return None
97 return episode_for_podcast_id_url(podcast.get_id(), episode_url, create)
100 def episode_for_podcast_id_url(podcast_id, episode_url, create=False):
102 if not podcast_id:
103 raise QueryParameterMissing('podcast_id')
105 if not episode_url:
106 raise QueryParameterMissing('episode_url')
109 key = u'episode-podcastid-%s-url-%s' % (
110 sha1(podcast_id.encode('utf-8')).hexdigest(),
111 sha1(episode_url.encode('utf-8')).hexdigest())
113 episode = cache.get(key)
114 if episode:
115 return episode
117 r = Episode.view('episodes/by_podcast_url',
118 key = [podcast_id, episode_url],
119 include_docs = True,
120 reduce = False,
123 if r:
124 episode = r.first()
125 cache.set(key, episode)
126 return episode
128 if create:
129 episode = Episode()
130 episode.podcast = podcast_id
131 episode.urls = [episode_url]
132 episode.save()
133 cache.set(key, episode)
134 return episode
136 return None
139 @cache_result(timeout=60*60)
140 def episode_for_slug_id(p_slug_id, e_slug_id):
141 """ Returns the Episode for Podcast Slug/Id and Episode Slug/Id """
143 if not p_slug_id:
144 raise QueryParameterMissing('p_slug_id')
146 if not e_slug_id:
147 raise QueryParameterMissing('e_slug_id')
150 # The Episode-Id is unique, so take that
151 if is_couchdb_id(e_slug_id):
152 return episode_by_id(e_slug_id)
154 # If we search using a slug, we need the Podcast's Id
155 if is_couchdb_id(p_slug_id):
156 p_id = p_slug_id
157 else:
158 podcast = podcast_for_slug_id(p_slug_id)
160 if podcast is None:
161 return None
163 p_id = podcast.get_id()
165 return episode_for_slug(p_id, e_slug_id)
168 @cache_result(timeout=60*60)
169 def episode_count():
170 r = Episode.view('episodes/by_podcast',
171 reduce = True,
172 stale = 'update_after',
174 return r.one()['value'] if r else 0
177 def episodes_to_dict(ids, use_cache=False):
179 if ids is None:
180 raise QueryParameterMissing('ids')
182 if not ids:
183 return {}
186 ids = list(set(ids))
187 objs = dict()
189 cache_objs = []
190 if use_cache:
191 res = cache.get_many(ids)
192 cache_objs.extend(res.values())
193 ids = [x for x in ids if x not in res.keys()]
195 db_objs = list(episodes_by_id(ids))
197 for obj in (cache_objs + db_objs):
199 # get_multi returns dict {'key': _id, 'error': 'not found'}
200 # for non-existing objects
201 if isinstance(obj, dict) and 'error' in obj:
202 _id = obj['key']
203 objs[_id] = None
204 continue
206 for i in obj.get_ids():
207 objs[i] = obj
209 if use_cache:
210 cache.set_many(dict( (obj._id, obj) for obj in db_objs))
212 return objs
215 def episode_slugs_per_podcast(podcast_id, base_slug):
217 if not podcast_id:
218 raise QueryParameterMissing('podcast_id')
221 res = Episode.view('episodes/by_slug',
222 startkey = [podcast_id, base_slug],
223 endkey = [podcast_id, base_slug + 'ZZZZZ'],
224 wrap_doc = False,
226 return [r['key'][1] for r in res]
229 def episodes_for_podcast_uncached(podcast, since=None, until={}, **kwargs):
231 if not podcast:
232 raise QueryParameterMissing('podcast')
235 if kwargs.get('descending', False):
236 since, until = until, since
238 if isinstance(since, datetime):
239 since = since.isoformat()
241 if isinstance(until, datetime):
242 until = until.isoformat()
244 res = Episode.view('episodes/by_podcast',
245 startkey = [podcast.get_id(), since],
246 endkey = [podcast.get_id(), until],
247 include_docs = True,
248 reduce = False,
249 **kwargs
252 return list(res)
255 episodes_for_podcast = cache_result(timeout=60*60)(episodes_for_podcast_uncached)
258 @cache_result(timeout=60*60)
259 def episode_count_for_podcast(podcast, since=None, until={}, **kwargs):
261 if not podcast:
262 raise QueryParameterMissing('podcast')
265 if kwargs.get('descending', False):
266 since, until = until, since
268 if isinstance(since, datetime):
269 since = since.isoformat()
271 if isinstance(until, datetime):
272 until = until.isoformat()
274 res = Episode.view('episodes/by_podcast',
275 startkey = [podcast.get_id(), since],
276 endkey = [podcast.get_id(), until],
277 reduce = True,
278 group_level = 1,
279 **kwargs
282 return res.one()['value']
285 def favorite_episodes_for_user(user):
287 if not user:
288 raise QueryParameterMissing('user')
290 favorites = Episode.view('favorites/episodes_by_user',
291 key = user._id,
292 include_docs = True,
294 return list(favorites)
297 def chapters_for_episode(episode_id):
299 if not episode_id:
300 raise QueryParameterMissing('episode_id')
302 db = get_main_database()
303 r = db.view('chapters/by_episode',
304 startkey = [episode_id, None],
305 endkey = [episode_id, {}],
308 return map(_wrap_chapter, r)
311 def _wrap_chapter(res):
312 from mygpo.users.models import Chapter
313 user = res['key'][1]
314 chapter = Chapter.wrap(res['value'])
315 return (user, chapter)