import datetime from podcasts.models import Episode, Podcast from django.contrib.syndication.views import Feed from django.contrib.sites.shortcuts import get_current_site from django.views.generic.base import RedirectView from django.utils.feedgenerator import rfc2822_date, Rss201rev2Feed, Atom1Feed from django.shortcuts import get_object_or_404 from .models import MIME_CHOICES class ITunesElements(object): def add_root_elements(self, handler): """ Add additional elements to the podcast object""" super(ITunesElements, self).add_root_elements(handler) podcast = self.feed["podcast"] if podcast.featured_image: # grab thumbs here #itunes_sm_url = thumbnailer.get_thumbnail(aliases["itunes_sm"]).url #itunes_lg_url = thumbnailer.get_thumbnail(aliases["itunes_lg"]).url if itunes_sm_url and itunes_lg_url: handler.addQuickElement("itunes:image", attrs={"href": itunes_lg_url}) handler.startElement("image", {}) handler.addQuickElement("url", itunes_sm_url) handler.addQuickElement("title", self.feed["title"]) handler.addQuickElement("link", self.feed["link"]) handler.endElement("image") handler.addQuickElement("guid", str(podcast.uuid), attrs={"isPermaLink": "false"}) handler.addQuickElement("itunes:subtitle", self.feed["subtitle"]) handler.addQuickElement("itunes:author", podcast.publisher) handler.startElement("itunes:owner", {}) handler.addQuickElement("itunes:name", podcast.publisher) handler.addQuickElement("itunes:email", podcast.publisher_email) handler.endElement("itunes:owner") handler.addQuickElement("itunes:category", attrs={"text": self.feed["categories"][0]}) handler.addQuickElement("itunes:summary", podcast.description) handler.addQuickElement("itunes:explicit", "no") handler.addQuickElement("keywords", podcast.keywords) try: handler.addQuickElement("lastBuildDate", rfc2822_date(podcast.episode_set.filter(status=1)[1].pub_date)) except IndexError: pass handler.addQuickElement("generator", "Luxagraf's Django Web Framework") handler.addQuickElement("docs", "http://blogs.law.harvard.edu/tech/rss") def add_item_elements(self, handler, item): """ Add additional elements to the episode object""" super(ITunesElements, self).add_item_elements(handler, item) podcast = item["podcast"] episode = item["episode"] if episode.featured_image: #grab episode thumbs #itunes_sm_url = None #itunes_lg_url = None if itunes_sm_url and itunes_lg_url: handler.addQuickElement("itunes:image", attrs={"href": itunes_lg_url}) handler.startElement("image", {}) handler.addQuickElement("url", itunes_sm_url) handler.addQuickElement("title", episode.title) handler.addQuickElement("link", episode.get_absolute_url()) handler.endElement("image") handler.addQuickElement("guid", str(episode.uuid), attrs={"isPermaLink": "false"}) handler.addQuickElement("copyright", "{0} {1}".format(podcast.license, datetime.date.today().year)) handler.addQuickElement("itunes:author", episode.podcast.publisher) handler.addQuickElement("itunes:subtitle", episode.subtitle) handler.addQuickElement("itunes:summary", episode.description) handler.addQuickElement("itunes:duration", "%02d:%02d:%02d" % (episode.hours, episode.minutes, episode.seconds)) handler.addQuickElement("itunes:keywords", episode.keywords) handler.addQuickElement("itunes:explicit", "no") if episode.block: handler.addQuickElement("itunes:block", "yes") def namespace_attributes(self): return {"xmlns:itunes": "http://www.itunes.com/dtds/podcast-1.0.dtd"} class AtomITunesFeedGenerator(ITunesElements, Atom1Feed): def root_attributes(self): atom_attrs = super(AtomITunesFeedGenerator, self).root_attributes() atom_attrs.update(self.namespace_attributes()) return atom_attrs class RssITunesFeedGenerator(ITunesElements, Rss201rev2Feed): def rss_attributes(self): rss_attrs = super(RssITunesFeedGenerator, self).rss_attributes() rss_attrs.update(self.namespace_attributes()) return rss_attrs class ShowFeed(Feed): """ A feed of podcasts for iTunes and other compatible podcatchers. """ def title(self, podcast): return podcast.title def link(self, podcast): return podcast.get_absolute_url() def categories(self, podcast): return ("Music",) def feed_copyright(self, podcast): return "{0} {1}".format(podcast.license, datetime.date.today().year) def ttl(self, podcast): return podcast.ttl def items(self, podcast): return podcast.episode_set.filter(status=1)[:300] def get_object(self, request, *args, **kwargs): self.mime = [mc[0] for mc in MIME_CHOICES if mc[0] == kwargs["mime_type"]][0] site = get_current_site(request) self.podcast = get_object_or_404(Podcast, slug=kwargs["show_slug"]) return self.podcast def item_title(self, episode): return episode.title def item_description(self, episode): "renders summary for atom" return episode.description def item_link(self, episode): return reverse("podcasting_episode_detail", kwargs={"podcast_slug": self.podcast.slug, "slug": episode.slug}) # def item_author_link(self, episode): # return "todo" #this one doesn't add anything in atom or rss # # def item_author_email(self, episode): # return "todo" #this one doesn't add anything in atom or rss def item_pubdate(self, episode): return episode.pub_date def item_categories(self, episode): return self.categories(self.podcast) def item_enclosure_url(self, episode): try: e = episode.enclosure_set.get(mime=self.mime) return e.url except Enclosure.DoesNotExist: pass def item_enclosure_length(self, episode): try: e = episode.enclosure_set.get(mime=self.mime) return e.size except Enclosure.DoesNotExist: pass def item_enclosure_mime_type(self, episode): try: e = episode.enclosure_set.get(mime=self.mime) return e.get_mime_display() except Enclosure.DoesNotExist: pass def item_keywords(self, episode): return episode.keywords def feed_extra_kwargs(self, obj): extra = {} extra["podcast"] = self.podcast return extra def item_extra_kwargs(self, item): extra = {} extra["podcast"] = self.podcast extra["episode"] = item return extra class AtomShowFeed(ShowFeed): feed_type = AtomITunesFeedGenerator def subtitle(self, show): return show.subtitle def author_name(self, show): return show.publisher def author_email(self, show): return show.publisher_email def author_link(self, show): return show.get_absolute_url() class RssShowFeed(ShowFeed): feed_type = RssITunesFeedGenerator def item_guid(self, episode): "ITunesElements can't add isPermaLink attr unless None is returned here." return None def description(self, show): return show.description class AtomRedirectView(RedirectView): permanent = False def get_redirect_url(self, show_slug, mime_type): return reverse( "podcasts_show_feed_atom", kwargs={"show_slug": show_slug, "mime_type": mime_type}) class RssRedirectView(RedirectView): permanent = False def get_redirect_url(self, show_slug, mime_type): return reverse( "podcasts_show_feed_rss", kwargs={"show_slug": show_slug, "mime_type": mime_type})