1 from __future__
import division
3 from itertools
import imap
as map
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
, \
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
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', {
58 'max_subscribers': max_subscribers
,
61 'all_languages': all_langs
,
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
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
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)
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
)
106 def get_random_podcast(self
):
107 random_podcast
= next(random_podcasts(), None)
109 yield random_podcast
.get_podcast()
112 @cache_control(private
=True)
114 def category(request
, category
, page_size
=20):
115 category
= category_for_tag(category
)
117 return HttpResponseNotFound()
119 # Make sure page request is an int. If not, deliver first page.
121 page
= int(request
.GET
.get('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', {
133 'category': category
.label
,
134 'page_list': page_list
,
141 @cache_control(private
=True)
143 def search(request
, template
='search.html', args
={}):
145 if 'q' in request
.GET
:
146 q
= request
.GET
.get('q', '').encode('utf-8')
149 page
= int(request
.GET
.get('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)
163 max_subscribers
= max([p
.subscriber_count() for p
in results
] + [0])
164 current_site
= RequestSite(request
)
166 return render(request
, template
, dict(
169 page_list
= page_list
,
170 max_subscribers
= max_subscribers
,
171 domain
= current_site
.domain
,
176 @cache_control(private
=True)
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', {
200 'max_listeners': max_listeners
,
203 'all_languages': all_langs
,
207 @cache_control(private
=True)
209 def podcast_lists(request
, page_size
=20):
211 # Make sure page request is an int. If not, deliver first page.
213 page
= int(request
.GET
.get('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
)
223 l
.username
= user
.username
if user
else ''
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', {
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)
255 podcast
= podcast_for_url(url
)
257 # if the podcast does already exist, there's nothing more to do
261 # check if we could add a podcast for the given URL
264 updater
= PodcastUpdater()
267 can_add
= updater
.verify_podcast_url(url
)
269 except (ParserException
, FetchFeedException
,
270 NoEpisodesException
) as ex
:
272 messages
.error(request
, unicode(ex
))
274 return render(request
, 'missing.html', {
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)
295 res
= update_podcasts
.delay([url
])
297 return HttpResponseRedirect(reverse('add-podcast-status',
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({
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
))
323 return self
.render_to_response({
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
)
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 """
357 def get_podcast_count():
358 """ must return the total number of podcasts """
361 def other_context(self
, request
, **kwargs
):
362 """ can return a dict of additional context data """
365 def get_page(self
, request
):
366 # Make sure page request is an int. If not, deliver first page.
368 return int(request
.GET
.get('page', '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
):
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
):
410 'licenses': get_podcast_licenses().most_common(),
412 return self
.render_to_response(context
)