Take the 2008 Git User's Survey and help out! [ hide ]

public
Description: Simple to use TVDB (thetvdb.com) API in Python, and automatic TV episode namer
Homepage: http://dbr.lighthouseapp.com/projects/13342-tvdb_api/tickets
Clone URL: git://github.com/dbr/tvdb_api.git
Search Repo:
dbr (author)
Mon May 05 06:02:27 -0700 2008
commit  9cd0164015f9c2e3e45722feedeeb80f293e1df9
tree    f6c341d1571f508b0abda9597306d63d5c9b3ad9
tvdb_api / tvdb_api.py
100644 195 lines (171 sloc) 7.672 kb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
class _Ddict(dict):
    def __init__(self, default=None):
        self.default = default
    #end __init__
 
    def __getitem__(self, key):
        if not self.has_key(key):
            self[key] = self.__class__(self.default) # Create sub-instance
        return dict.__getitem__(self, key)
    #end __getitem__
#end _Ddict
class tvdb_error(Exception):pass
class tvdb_shownotfound(Exception):pass
class tvdb_userabort(Exception):pass
class tvdb:
    """
Create easy-to-use interface to name of season/episode name
>>> i = tvdb()
>>> i['showname']['1']['24']['name']
'Last Episode'
"""
    import urllib
    from BeautifulSoup import BeautifulStoneSoup
    
    def __init__(self,interactive=False,debug=False):
        self.config={}
        self.config['apikey'] = "0629B785CE550C8D"
        # The following url_ configs are based of the http://www.thetvdb.com API documentation
        self.config['url_mirror'] = "http://www.thetvdb.com/api/%s/mirrors.xml" % (self.config['apikey'])
        self.config['url_getSeries'] = "http://www.thetvdb.com/api/GetSeries.php?seriesname=%s"
        self.config['url_epInfo'] = "http://www.thetvdb.com/api/%s/series/%%s/all/" % (self.config['apikey'])
        
        self.config['interactive'] = interactive # prompt for correct series if needed
        
        self.config['debug_enabled'] = debug # show debugging messages
        self.config['debug_tofile'] = False
        self.config['debug_filename'] = "tvdb.log"
        self.config['debug_path'] = '.'
        
        self.log = self.initLogger() # Setups the logger (self.log.debug() etc)
        self.shows = {} # Holds all show data in shows[show_id] = dict of ep data
        self.corrections = {} # Holds show-name to show_id mapping
        
        # Config setup. Grab TVDB mirrors
        self.mirrors = self._getMirrors() # TODO: Apply random mirror urls (Minor: Currently 1 mirror)
    #end __init__
    
    def initLogger(self):
        import os,logging,sys
        logdir = os.path.expanduser( self.config['debug_path'] )
        logpath = os.path.join(logdir,self.config['debug_filename'])
        
        logger = logging.getLogger("tvdb")
        formatter = logging.Formatter('%(asctime)s) %(levelname)s %(message)s')
        
        if self.config['debug_tofile']:
            hdlr = logging.StreamHandler(sys.stdout)
        else:
            hdlr = logging.FileHandler(logpath)
        #end if debug_tofile
        
        hdlr.setFormatter(formatter)
        logger.addHandler(hdlr)
        
        if self.config['debug']:
            logger.setLevel(logging.DEBUG)
        else:
            logger.setLevel(logging.INFO)
        return logger
    #end initLogger
    
    def _getsoupsrc(self,url):
        self.log.debug('Retriving URL %s' % (url.replace(" ","+")))
        
        url=url.replace(" ","+")
        try:
            src=self.urllib.urlopen(url).read()
        except IOError,errormsg:
            raise tvdb_error("Could not connect to server: %s\n" % (errormsg))
        #end try
        soup=self.BeautifulStoneSoup(src)
        return soup
    #end _getsoupsrc
    
    def _getMirrors(self):
        mirrorSoup=self._getsoupsrc( self.config['url_mirror'] )
        mirrors=[]
        for mirror in mirrorSoup.findAll('mirror'):
            self.log.debug('Found mirror %s' % (mirror))
            
            mirrors.append(
                mirror.find('mirrorpath').contents[0]
            )
        #end for mirror
        self.log.debug('Found total of %s mirrors' % (len(mirrors)))
        return mirrors
    #end _getMirrors
 
    def _getSeries(self,series,interactive=False):
        seriesSoup = self._getsoupsrc( self.config['url_getSeries'] % (series) )
        allSeries=[]
        for series in seriesSoup.findAll('series'):
            cur_name = series.find('seriesname').contents[0]
            cur_sid = series.find('id').contents[0]
            self.log.debug('Found series %s (id: %s)' % (cur_name,cur_sid))
            allSeries.append( {'sid':cur_sid, 'name':cur_name} )
        #end for series
        
        if len(allSeries) == 0:
            self.log.debug('Series result returned zero')
            raise tvdb_shownotfound("Show-name search returned zero results")
        
        if self.config['interactive']:
            self.log.debug('Interactivily selecting show')
            for i in range(len(allSeries[:6])):
                i_show = i + 1 # Start at more human readable number 1 (not zero)
                self.log.debug( 'Showing allSeries[%s] = %s)' % (i_show,allSeries[i]) )
                print "%s -> %s (tvdb id: %s)" % (i_show,allSeries[i]['name'],allSeries[i]['sid'])
            print "Enter choice (first number):"
            ans=raw_input()
            self.log.debug( 'Got choice of: %s' % (ans))
            try:
                selected_id = int(ans) - 1 # The human entered 1 as first result, not zero
                self.log.debug( 'Trying to return ID: %d' % (selected_id))
                return allSeries[ selected_id ]
            except ValueError: # Input was not number
                if ans == "q":
                    self.log.debug('Got quit command (q)')
                    raise tvdb_userabort("User aborted")
                else:
                    self.log.debug('Unknown keypress %s' % (ans))
                    raise tvdb_userabort("Invalid keypress") # TODO: Better UI
            #end for k,v
        else:
            self.log.debug('Auto-selecting first search result')
            return allSeries[0]
    #end _getSeries
 
    def _getEps(self,sid):
        self.log.debug('Getting all episodes of %s' % (sid))
        epsSoup=self._getsoupsrc( self.config['url_epInfo']% (sid) )
        for ep in epsSoup.findAll('episode'):
            ep_no = int( ep.find('episodenumber').contents[0] )
            seas_no = int( ep.find('seasonnumber').contents[0] )
            ep_name = str( ep.find('episodename').contents[0] )
            
            self.shows[sid][seas_no][ep_no] = {'name':ep_name}
        #end for ep
    #end _geEps
    
    def _nameToSid(self,name):
        """
Takes show name, returns the correct series ID (if the show has
already been grabbed), or grabs all episodes and returns
the correct SID.
"""
        if self.corrections.has_key(name):
            self.log.debug('Correcting %s to %s' % (name,self.corrections[name]) )
            print self.corrections
            sid = self.corrections[name]
        else:
            self.log.debug('Getting show %s' % (name))
            selected_series = self._getSeries( name )
            sname, sid = selected_series['name'], selected_series['sid']
            self.log.debug( "Got %s, sid %s" % (sname,sid) )
            self.shows[sid] = _Ddict(dict)
            self.corrections[name] = sid
            self._getEps( sid )
        #end if self.corrections.has_key
        return sid
 
    def __getitem__(self,key):
        """
Handles tvdb_instance['showname'] calls.
The dict index should be the show name
"""
        key=key.lower() # make key lower case
        sid = self._nameToSid(key)
        self.log.debug('Got series id %s' % (sid))
        return dict.__getitem__(self.shows, sid)
    #end __getitem__
    
    def __setitem__(self,key,value):
        self.log.debug('Setting %s = %s' % (key,value))
        self.shows[key] = value
    #end __getitem__
    def __str__(self):
        return str(self.shows) #TODO: Improve this
    #end __str__
#end tvdb
 
if __name__ == '__main__':
    x=tvdb(interactive=True,debug=True)
    print x['lost'][1][4]
    print x['Lost'][1][4]