2
# Written by Owen Williams, (c) 2007
3
# see LICENSE for license information
5
# iTunes has very strange weblinks, but they are not that hard to read.
6
# A "viewPodcast" link returns a gzipped web page that contains a link that
7
# iTunes can load. Although the protocol of this link is itms://, we can
8
# load it with http. This time we get a gzipped xml file, and toward the
9
# bottom of the file is a simple key / value pair for episodeURL. This
10
# url is what the podcast author has told itunes to use, and it'll be regular
20
from xml.sax import saxutils, make_parser
21
from xml.sax.handler import feature_namespaces
24
if url.lower().startswith("itms://"):
27
def is_itunes_url(url):
28
""" Two simple checks to see if this is a valid itunes url:
29
(ie, http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewPodcast?id=207870198)
30
* does it contain "phobos.apple.com", and
31
* does it contain "viewPodcast"
33
There's also another form, as in http://www.itunes.com/podcast?id=207870198"""
35
if url.lower().startswith("itms://"):
37
if "apple.com/" in url.lower() and "viewPodcast" in url:
39
if "itunes.com/podcast" in url.lower():
43
def get_rss_from_itunes(url):
44
if not is_itunes_url(url):
45
raise ItunesError, "not an itunes url"
47
if not is_itms_url(url):
48
url2 = get_itms_url(url)
49
return get_podcast_url(url2)
51
url2 = url.replace("itms://", "http://")
52
return get_podcast_url(url2)
54
def get_itms_url(url):
55
# Part 1, get the itunes "webpage" for this feed
56
# we have to save the file because urlopen doesn't support seeking
57
filename, message = urllib.urlretrieve(url)
58
#uncompressed = gzip.GzipFile(filename=filename, mode='r')
59
uncompressed = open(filename, 'r')
61
parser = viewPodcastParser()
62
parser.feed(uncompressed.read())
64
if parser.url is None:
65
raise ItunesError, "error getting viewpodcast url from itunes"
68
def get_podcast_url(url):
69
# Part 2, find the actual rss link in the itunes "webpage"
70
filename, message = urllib.urlretrieve(url)
71
#uncompressed = gzip.GzipFile(filename=filename, mode='r')
72
uncompressed = open(filename, 'r')
74
parser = make_parser()
75
parser.setFeature(feature_namespaces, 0)
76
handler = itunesHandler()
77
parser.setContentHandler(handler)
78
parser.parse(uncompressed)
80
if handler.url is None:
81
raise ItunesError, "error finding podcast url"
85
class viewPodcastParser(HTMLParser.HTMLParser):
87
HTMLParser.HTMLParser.__init__(self)
90
def handle_starttag(self, tag, attrs):
92
if tag.upper() == "BODY":
93
for attr, val in attrs:
95
url = val[val.find("itms://") + 4:]
96
url = url[:url.find("'")]
101
from xml.sax.handler import ContentHandler
102
def_handler = ContentHandler
105
from xml.sax.saxutils import DefaultHandler
106
def_handler = DefaultHandler
108
logging.error("couldn't get xml parsing")
111
class itunesHandler(def_handler):
115
self._in_value = None
116
self._last_key = None
118
def startElement(self, name, attrs):
121
elif name == 'string':
124
def endElement(self, name):
126
self._last_key = self._in_key
128
elif name == 'string':
129
if self._last_key == 'feedURL':
130
self.url = self._in_value
131
self._in_value = None
133
def characters(self, ch):
134
if self._in_key is not None:
136
elif self._in_value is not None:
139
class ItunesError(Exception):
140
def __init__(self, m):