fix typo
[mygpo.git] / mygpo / directory / views.py
blob60ea7fe2ab1d3b56b5271ae2c772ecbb0f0f371f
1 from __future__ import division
3 from itertools import imap as map
4 from math import ceil
6 from django.http import HttpResponseNotFound, Http404, HttpResponseRedirect
7 from django.core.urlresolvers import reverse
8 from django.shortcuts import render
9 from django.contrib.sites.models import RequestSite
10 from django.views.decorators.cache import cache_control
11 from django.views.decorators.vary import vary_on_cookie
12 from django.utils.decorators import method_decorator
13 from django.views.generic.base import View, TemplateView
14 from django.contrib.auth.decorators import login_required
15 from django.contrib import messages
16 from django.utils.translation import ugettext as _
18 from feedservice.parse.models import ParserException
19 from feedservice.parse import FetchFeedException
21 from mygpo.core.proxy import proxy_object
22 from mygpo.directory.toplist import PodcastToplist, EpisodeToplist, \
23 TrendingPodcasts
24 from mygpo.directory.search import search_podcasts
25 from mygpo.web.utils import process_lang_params, get_language_names, \
26 get_page_list, get_podcast_link_target
27 from mygpo.directory.tags import Topics
28 from mygpo.users.settings import FLATTR_TOKEN
29 from mygpo.data.feeddownloader import PodcastUpdater, NoEpisodesException
30 from mygpo.data.tasks import update_podcasts
31 from mygpo.db.couchdb.user import get_user_by_id
32 from mygpo.db.couchdb.podcast import get_podcast_languages, podcasts_by_id, \
33 random_podcasts, podcasts_to_dict, podcast_for_url, \
34 get_flattr_podcasts, get_flattr_podcast_count, get_license_podcasts, \
35 get_license_podcast_count, get_podcast_licenses
36 from mygpo.db.couchdb.directory import category_for_tag
37 from mygpo.db.couchdb.podcastlist import random_podcastlists, \
38 podcastlist_count, podcastlists_by_rating
41 @vary_on_cookie
42 @cache_control(private=True)
43 def toplist(request, num=100, lang=None):
45 lang = process_lang_params(request)
47 toplist = PodcastToplist(lang)
48 entries = toplist[:num]
50 max_subscribers = max([p.subscriber_count() for (oldp, p) in entries]) if entries else 0
51 current_site = RequestSite(request)
53 languages = get_podcast_languages()
54 all_langs = get_language_names(languages)
56 return render(request, 'toplist.html', {
57 'entries': entries,
58 'max_subscribers': max_subscribers,
59 'url': current_site,
60 'language': lang,
61 'all_languages': all_langs,
65 class Carousel(View):
66 """ A carousel demo """
68 @method_decorator(cache_control(private=True))
69 @method_decorator(vary_on_cookie)
70 def get(self, request):
72 return render(request, 'carousel.html', {
73 # evaluated lazyly, cached by template
74 'topics': Topics(),
78 class Directory(View):
79 """ The main directory page """
81 @method_decorator(cache_control(private=True))
82 @method_decorator(vary_on_cookie)
83 def get(self, request):
85 return render(request, 'directory.html', {
87 # evaluated lazyly, cached by template
88 'topics': Topics(),
89 'trending_podcasts': TrendingPodcasts(''),
90 'podcastlists': self.get_random_list(),
91 'random_podcasts': self.get_random_podcast(),
95 def get_random_list(self, podcasts_per_list=5):
96 random_list = next(random_podcastlists(), None)
97 list_owner = None
98 if random_list:
99 random_list = proxy_object(random_list)
100 random_list.more_podcasts = max(0, len(random_list.podcasts) - podcasts_per_list)
101 random_list.podcasts = podcasts_by_id(random_list.podcasts[:podcasts_per_list])
102 random_list.user = get_user_by_id(random_list.user)
104 yield random_list
106 def get_random_podcast(self):
107 random_podcast = next(random_podcasts(), None)
108 if random_podcast:
109 yield random_podcast.get_podcast()
112 @cache_control(private=True)
113 @vary_on_cookie
114 def category(request, category, page_size=20):
115 category = category_for_tag(category)
116 if not category:
117 return HttpResponseNotFound()
119 # Make sure page request is an int. If not, deliver first page.
120 try:
121 page = int(request.GET.get('page', '1'))
122 except ValueError:
123 page = 1
125 entries = category.get_podcasts( (page-1) * page_size, page*page_size )
126 podcasts = filter(None, entries)
127 num_pages = int(ceil(len(category.podcasts) / page_size))
129 page_list = get_page_list(1, num_pages, page, 15)
131 return render(request, 'category.html', {
132 'entries': podcasts,
133 'category': category.label,
134 'page_list': page_list,
139 RESULTS_PER_PAGE=20
141 @cache_control(private=True)
142 @vary_on_cookie
143 def search(request, template='search.html', args={}):
145 if 'q' in request.GET:
146 q = request.GET.get('q', '').encode('utf-8')
148 try:
149 page = int(request.GET.get('page', 1))
150 except ValueError:
151 page = 1
153 results, total = search_podcasts(q=q, skip=RESULTS_PER_PAGE*(page-1))
154 num_pages = int(ceil(total / RESULTS_PER_PAGE))
156 page_list = get_page_list(1, num_pages, page, 15)
158 else:
159 results = []
160 q = None
161 page_list = []
163 max_subscribers = max([p.subscriber_count() for p in results] + [0])
164 current_site = RequestSite(request)
166 return render(request, template, dict(
167 q= q,
168 results= results,
169 page_list= page_list,
170 max_subscribers= max_subscribers,
171 domain= current_site.domain,
172 **args
176 @cache_control(private=True)
177 @vary_on_cookie
178 def episode_toplist(request, num=100):
179 lang = process_lang_params(request)
181 toplist = EpisodeToplist(language=lang)
182 entries = list(map(proxy_object, toplist[:num]))
184 # load podcast objects
185 podcast_ids = [e.podcast for e in entries]
186 podcasts = podcasts_to_dict(podcast_ids, True)
187 for entry in entries:
188 entry.podcast = podcasts.get(entry.podcast, None)
190 current_site = RequestSite(request)
192 # Determine maximum listener amount (or 0 if no entries exist)
193 max_listeners = max([0]+[e.listeners for e in entries])
195 languages = get_podcast_languages()
196 all_langs = get_language_names(languages)
198 return render(request, 'episode_toplist.html', {
199 'entries': entries,
200 'max_listeners': max_listeners,
201 'url': current_site,
202 'language': lang,
203 'all_languages': all_langs,
207 @cache_control(private=True)
208 @vary_on_cookie
209 def podcast_lists(request, page_size=20):
211 # Make sure page request is an int. If not, deliver first page.
212 try:
213 page = int(request.GET.get('page', '1'))
214 except ValueError:
215 page = 1
217 lists = podcastlists_by_rating(skip=(page-1) * page_size, limit=page_size)
220 def _prepare_list(l):
221 user = get_user_by_id(l.user)
222 l = proxy_object(l)
223 l.username = user.username if user else ''
224 return l
226 lists = map(_prepare_list, lists)
228 num_pages = int(ceil(podcastlist_count() / float(page_size)))
230 page_list = get_page_list(1, num_pages, page, 15)
232 return render(request, 'podcast_lists.html', {
233 'lists': lists,
234 'page_list': page_list,
239 class MissingPodcast(View):
240 """ Check if a podcast is missing """
242 @method_decorator(login_required)
243 def get(self, request):
245 site = RequestSite(request)
247 # check if we're doing a query
248 url = request.GET.get('q', None)
250 if not url:
251 podcast = None
252 can_add = False
254 else:
255 podcast = podcast_for_url(url)
257 # if the podcast does already exist, there's nothing more to do
258 if podcast:
259 can_add = False
261 # check if we could add a podcast for the given URL
262 else:
263 podcast = False
264 updater = PodcastUpdater()
266 try:
267 can_add = updater.verify_podcast_url(url)
269 except (ParserException, FetchFeedException,
270 NoEpisodesException) as ex:
271 can_add = False
272 messages.error(request, unicode(ex))
274 return render(request, 'missing.html', {
275 'site': site,
276 'q': url,
277 'podcast': podcast,
278 'can_add': can_add,
282 class AddPodcast(View):
283 """ Add a missing podcast"""
285 @method_decorator(login_required)
286 @method_decorator(cache_control(private=True))
287 @method_decorator(vary_on_cookie)
288 def post(self, request):
290 url = request.POST.get('url', None)
292 if not url:
293 raise Http404
295 res = update_podcasts.delay([url])
297 return HttpResponseRedirect(reverse('add-podcast-status',
298 args=[res.task_id]))
301 class AddPodcastStatus(TemplateView):
302 """ Status of adding a podcast """
304 template_name = 'directory/add-podcast-status.html'
306 def get(self, request, task_id):
307 result = update_podcasts.AsyncResult(task_id)
309 if not result.ready():
310 return self.render_to_response({
311 'ready': False,
314 try:
315 podcasts = result.get()
316 messages.success(request, _('%d podcasts added' % len(podcasts)))
318 except (ParserException, FetchFeedException,
319 NoEpisodesException) as ex:
320 messages.error(request, str(ex))
321 podcast = None
323 return self.render_to_response({
324 'ready': True,
325 'podcasts': podcasts,
329 class PodcastListView(TemplateView):
330 """ A generic podcast list view """
332 @method_decorator(cache_control(private=True))
333 @method_decorator(vary_on_cookie)
334 def get(self, request, page_size=20, **kwargs):
336 page = self.get_page(request)
337 podcasts = self.get_podcasts( (page-1) * page_size, page_size, **kwargs)
338 podcast_count = self.get_podcast_count(**kwargs)
340 context = kwargs
341 context.update({
342 'podcasts': podcasts,
343 'page_list': self.get_page_list(page, page_size, podcast_count),
344 'current_page': page,
345 'max_subscribers': self.get_max_subscribers(podcasts),
348 context.update(self.other_context(request))
350 return self.render_to_response(context)
353 def get_podcasts(self, offset, limit):
354 """ must return a list of podcasts """
355 raise NotImplemented
357 def get_podcast_count():
358 """ must return the total number of podcasts """
359 raise NotImplemented
361 def other_context(self, request, **kwargs):
362 """ can return a dict of additional context data """
363 return {}
365 def get_page(self, request):
366 # Make sure page request is an int. If not, deliver first page.
367 try:
368 return int(request.GET.get('page', '1'))
369 except ValueError:
370 return 1
372 def get_page_list(self, page, page_size, podcast_count):
373 num_pages = int(ceil(podcast_count / page_size))
374 return get_page_list(1, num_pages, page, 15)
376 def get_max_subscribers(self, podcasts):
377 return max([p.subscriber_count() for p in podcasts] + [0])
380 class FlattrPodcastList(PodcastListView):
381 """ Lists podcasts that have Flattr payment URLs """
383 template_name = 'flattr-podcasts.html'
384 get_podcasts = staticmethod(get_flattr_podcasts)
385 get_podcast_count = staticmethod(get_flattr_podcast_count)
387 def other_context(self, request):
388 user = request.user
389 return {
390 'flattr_auth': user.is_authenticated() and
391 bool(user.get_wksetting(FLATTR_TOKEN))
395 class LicensePodcastList(PodcastListView):
396 """ Lists podcasts with a given license """
398 template_name = 'directory/license-podcasts.html'
399 get_podcasts = staticmethod(get_license_podcasts)
400 get_podcast_count = staticmethod(get_license_podcast_count)
403 class LicenseList(TemplateView):
404 """ Lists all podcast licenses """
406 template_name = 'directory/licenses.html'
408 def get(self, request):
409 context = {
410 'licenses': get_podcast_licenses().most_common(),
412 return self.render_to_response(context)