fix calculation of page count in directory
[mygpo.git] / mygpo / directory / views.py
blobdf39c6f1e89510195a5fba4041b0673927f56c52
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
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.models import User
29 from mygpo.users.settings import FLATTR_TOKEN
30 from mygpo.data.feeddownloader import PodcastUpdater, NoEpisodesException
31 from mygpo.db.couchdb.podcast import get_podcast_languages, podcasts_by_id, \
32 random_podcasts, podcasts_to_dict, podcast_for_url, \
33 get_flattr_podcasts, get_flattr_podcast_count
34 from mygpo.db.couchdb.directory import category_for_tag
35 from mygpo.db.couchdb.podcastlist import random_podcastlists, \
36 podcastlist_count, podcastlists_by_rating
39 @vary_on_cookie
40 @cache_control(private=True)
41 def toplist(request, num=100, lang=None):
43 lang = process_lang_params(request)
45 toplist = PodcastToplist(lang)
46 entries = toplist[:num]
48 max_subscribers = max([p.subscriber_count() for (oldp, p) in entries]) if entries else 0
49 current_site = RequestSite(request)
51 languages = get_podcast_languages()
52 all_langs = get_language_names(languages)
54 return render(request, 'toplist.html', {
55 'entries': entries,
56 'max_subscribers': max_subscribers,
57 'url': current_site,
58 'language': lang,
59 'all_languages': all_langs,
63 class Carousel(View):
64 """ A carousel demo """
66 @method_decorator(cache_control(private=True))
67 @method_decorator(vary_on_cookie)
68 def get(self, request):
70 return render(request, 'carousel.html', {
71 # evaluated lazyly, cached by template
72 'topics': Topics(),
76 class Directory(View):
77 """ The main directory page """
79 @method_decorator(cache_control(private=True))
80 @method_decorator(vary_on_cookie)
81 def get(self, request):
83 return render(request, 'directory.html', {
85 # evaluated lazyly, cached by template
86 'topics': Topics(),
87 'trending_podcasts': TrendingPodcasts(''),
88 'podcastlists': self.get_random_list(),
89 'random_podcasts': self.get_random_podcast(),
93 def get_random_list(self, podcasts_per_list=5):
94 random_list = next(random_podcastlists(), None)
95 list_owner = None
96 if random_list:
97 random_list = proxy_object(random_list)
98 random_list.more_podcasts = max(0, len(random_list.podcasts) - podcasts_per_list)
99 random_list.podcasts = podcasts_by_id(random_list.podcasts[:podcasts_per_list])
100 random_list.user = User.get(random_list.user)
102 yield random_list
104 def get_random_podcast(self):
105 random_podcast = next(random_podcasts(), None)
106 if random_podcast:
107 yield random_podcast.get_podcast()
110 @cache_control(private=True)
111 @vary_on_cookie
112 def category(request, category, page_size=20):
113 category = category_for_tag(category)
114 if not category:
115 return HttpResponseNotFound()
117 # Make sure page request is an int. If not, deliver first page.
118 try:
119 page = int(request.GET.get('page', '1'))
120 except ValueError:
121 page = 1
123 entries = category.get_podcasts( (page-1) * page_size, page*page_size )
124 podcasts = filter(None, entries)
125 num_pages = ceil(len(category.podcasts) / page_size)
127 page_list = get_page_list(1, num_pages, page, 15)
129 return render(request, 'category.html', {
130 'entries': podcasts,
131 'category': category.label,
132 'page_list': page_list,
137 RESULTS_PER_PAGE=20
139 @cache_control(private=True)
140 @vary_on_cookie
141 def search(request, template='search.html', args={}):
143 if 'q' in request.GET:
144 q = request.GET.get('q', '').encode('utf-8')
146 try:
147 page = int(request.GET.get('page', 1))
148 except ValueError:
149 page = 1
151 results, total = search_podcasts(q=q, skip=RESULTS_PER_PAGE*(page-1))
152 num_pages = ceil(total / RESULTS_PER_PAGE)
154 page_list = get_page_list(1, num_pages, page, 15)
156 else:
157 results = []
158 q = None
159 page_list = []
161 max_subscribers = max([p.subscriber_count() for p in results] + [0])
162 current_site = RequestSite(request)
164 return render(request, template, dict(
165 q= q,
166 results= results,
167 page_list= page_list,
168 max_subscribers= max_subscribers,
169 domain= current_site.domain,
170 **args
174 @cache_control(private=True)
175 @vary_on_cookie
176 def episode_toplist(request, num=100):
177 lang = process_lang_params(request)
179 toplist = EpisodeToplist(language=lang)
180 entries = list(map(proxy_object, toplist[:num]))
182 # load podcast objects
183 podcast_ids = [e.podcast for e in entries]
184 podcasts = podcasts_to_dict(podcast_ids, True)
185 for entry in entries:
186 entry.podcast = podcasts.get(entry.podcast, None)
188 current_site = RequestSite(request)
190 # Determine maximum listener amount (or 0 if no entries exist)
191 max_listeners = max([0]+[e.listeners for e in entries])
193 languages = get_podcast_languages()
194 all_langs = get_language_names(languages)
196 return render(request, 'episode_toplist.html', {
197 'entries': entries,
198 'max_listeners': max_listeners,
199 'url': current_site,
200 'language': lang,
201 'all_languages': all_langs,
205 @cache_control(private=True)
206 @vary_on_cookie
207 def podcast_lists(request, page_size=20):
209 # Make sure page request is an int. If not, deliver first page.
210 try:
211 page = int(request.GET.get('page', '1'))
212 except ValueError:
213 page = 1
215 lists = podcastlists_by_rating(skip=(page-1) * page_size, limit=page_size)
218 def _prepare_list(l):
219 user = User.get(l.user)
220 l = proxy_object(l)
221 l.username = user.username
222 return l
224 lists = map(_prepare_list, lists)
226 num_pages = int(ceil(podcastlist_count() / float(page_size)))
228 page_list = get_page_list(1, num_pages, page, 15)
230 return render(request, 'podcast_lists.html', {
231 'lists': lists,
232 'page_list': page_list,
237 class MissingPodcast(View):
238 """ Check if a podcast is missing """
240 @method_decorator(login_required)
241 def get(self, request):
243 site = RequestSite(request)
245 # check if we're doing a query
246 url = request.GET.get('q', None)
248 if not url:
249 podcast = None
250 can_add = False
252 else:
253 podcast = podcast_for_url(url)
255 # if the podcast does already exist, there's nothing more to do
256 if podcast:
257 can_add = False
259 # check if we could add a podcast for the given URL
260 else:
261 podcast = False
262 updater = PodcastUpdater()
264 try:
265 can_add = updater.verify_podcast_url(url)
267 except (ParserException, FetchFeedException,
268 NoEpisodesException) as ex:
269 can_add = False
270 messages.error(request, str(ex))
272 return render(request, 'missing.html', {
273 'site': site,
274 'q': url,
275 'podcast': podcast,
276 'can_add': can_add,
280 class AddPodcast(View):
281 """ Add a missing podcast"""
283 @method_decorator(login_required)
284 @method_decorator(cache_control(private=True))
285 @method_decorator(vary_on_cookie)
286 def post(self, request):
288 url = request.POST.get('url', None)
290 if not url:
291 raise Http404
293 updater = PodcastUpdater()
295 try:
296 podcast = updater.update(url)
298 messages.success(request, _('The podcast has been added'))
300 return HttpResponseRedirect(get_podcast_link_target(podcast))
302 except (ParserException, FetchFeedException,
303 NoEpisodesException) as ex:
304 messages.error(request, str(ex))
306 add_page = '%s?q=%s' % (reverse('missing-podcast'), url)
307 return HttpResponseRedirect(add_page)
311 class FlattrPodcastList(View):
312 """ Lists podcasts that have Flattr payment URLs """
314 @method_decorator(cache_control(private=True))
315 @method_decorator(vary_on_cookie)
316 def get(self, request, page_size=20):
318 # Make sure page request is an int. If not, deliver first page.
319 try:
320 page = int(request.GET.get('page', '1'))
321 except ValueError:
322 page = 1
324 podcasts = get_flattr_podcasts( (page-1) * page_size, page_size)
325 podcast_count = get_flattr_podcast_count()
326 num_pages = ceil(podcast_count / page_size)
327 page_list = get_page_list(1, num_pages, page, 15)
329 max_subscribers = max([p.subscriber_count() for p in podcasts] + [0])
331 user = request.user
332 flattr_auth = user.is_authenticated() and bool(user.get_wksetting(FLATTR_TOKEN))
334 return render(request, 'flattr-podcasts.html', {
335 'podcasts': podcasts,
336 'page_list': page_list,
337 'current_page': page,
338 'flattr_auth': flattr_auth,
339 'max_subscribers': max_subscribers,