Projects
Multimedia
python-tvdb_api
Sign Up
Log In
Username
Password
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
Expand all
Collapse all
Changes of Revision 2
View file
python-tvdb_api.changes
Changed
@@ -1,4 +1,10 @@ ------------------------------------------------------------------- +Fri Apr 21 12:40:16 UTC 2017 - aloisio@gmx.com + +- Update to version 1.10 +- Spec cleanup + +------------------------------------------------------------------- Mon Feb 4 14:26:00 UTC 2013 - hvogel@opensuse.org - Update to version 1.8.2
View file
python-tvdb_api.spec
Changed
@@ -1,32 +1,57 @@ +# +# spec file for package python-tvdb_api +# +# Copyright (c) 2017 Packman Team <packman@links2linux.de> +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. + +# Please submit bugfixes or comments via http://bugs.links2linux.org/ +# + + %define modname tvdb_api -Name: python-tvdb_api -Summary: Python module to access the API from thetvdb.com -License: GPL -Url: http://pypi.python.org/pypi/tvdb_api -Group: Productivity/Multimedia/Other -Version: 1.8.2 -Release: 1 -Source0: tvdb_api-%version.tar.bz2 -BuildRoot: %{_tmppath}/%{name}-buildroot -BuildRequires: python-devel python-setuptools +Name: python-tvdb_api +Version: 1.10 +Release: 0 +Summary: Python module to access the API from thetvdb.com +# The UnLicense (https://unlicense.org) +License: SUSE-Permissive +Group: Productivity/Multimedia/Other +Url: https://github.com/dbr/tvdb_api/tree/master +Source0: https://files.pythonhosted.org/packages/source/t/%{modname}/%{modname}-%{version}.tar.gz +BuildRequires: python-devel +BuildRequires: python-setuptools +BuildRoot: %{_tmppath}/%{name}-%{version}-build +BuildArch: noarch %py_requires %description -tvdb_api is an easy to use interface to thetvdb.com +tvdb_api is an easy to use interface to thetvdb.com via python %prep -%setup -q -n %modname-%version +%setup -q -n %{modname}-%{version} +for file in {tvdb_cache,tvdb_api,tvdb_ui,tvdb_exceptions} +do + sed -i "1d" $file.py +done %build +python setup.py build %install -python setup.py install --root=$RPM_BUILD_ROOT --prefix=%_prefix \ - --record-rpm=INSTALLED_FILES - -%clean -rm -rf $RPM_BUILD_ROOT +python setup.py install --root=%{buildroot} --prefix=%{_prefix} -%files -f INSTALLED_FILES +%files %defattr(-,root,root) +%doc UNLICENSE readme.md +%{python_sitelib}/tvdb_*.py* +%{python_sitelib}/%{modname}-%{version}-py%{python_version}.egg-info %changelog
View file
tvdb_api-1.8.2.tar.bz2/PKG-INFO -> tvdb_api-1.10.tar.gz/PKG-INFO
Changed
@@ -1,6 +1,6 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: tvdb_api -Version: 1.8.2 +Version: 1.10 Summary: Interface to thetvdb.com Home-page: http://github.com/dbr/tvdb_api/tree/master Author: dbr/Ben @@ -22,6 +22,11 @@ Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Multimedia Classifier: Topic :: Utilities Classifier: Topic :: Software Development :: Libraries :: Python Modules
View file
tvdb_api-1.8.2.tar.bz2/Rakefile -> tvdb_api-1.10.tar.gz/Rakefile
Changed
@@ -47,10 +47,10 @@ end desc "Upload current version to PyPi" -task :topypi => :test do +task :topypi do cur_file = File.open("tvdb_api.py").read() tvdb_api_version = cur_file.scan(/__version__ = "(.*)"/) - tvdb_api_version = tvdb_api_version[0][0].to_f + tvdb_api_version = tvdb_api_version[0][0] puts "Build sdist and send tvdb_api v#{tvdb_api_version} to PyPi?" if $stdin.gets.chomp == "y"
View file
tvdb_api-1.8.2.tar.bz2/readme.md -> tvdb_api-1.10.tar.gz/readme.md
Changed
@@ -2,6 +2,8 @@ `tvdb_api` is an easy to use interface to [thetvdb.com][tvdb] +It supports Python 2.6, 2.7, 3.3 and 3.4 + `tvnamer` has moved to a separate repository: [github.com/dbr/tvnamer][tvnamer] - it is a utility which uses `tvdb_api` to rename files from `some.show.s01e03.blah.abc.avi` to `Some Show - [01x03] - The Episode Name.avi` (which works by getting the episode name from `tvdb_api`) [![Build Status](https://secure.travis-ci.org/dbr/tvdb_api.png?branch=master)](http://travis-ci.org/dbr/tvdb_api) @@ -38,7 +40,7 @@ There are several exceptions you may catch, these can be imported from `tvdb_api`: -- `tvdb_error` - this is raised when there is an error communicating with [www.thetvdb.com][tvdb] (a network error most commonly) +- `tvdb_error` - this is raised when there is an error communicating with [thetvdb.com][tvdb] (a network error most commonly) - `tvdb_userabort` - raised when a user aborts the Select Series dialog (by `ctrl+c`, or entering `q`) - `tvdb_shownotfound` - raised when `t['show name']` cannot find anything - `tvdb_seasonnotfound` - raised when the requested series (`t['show name][99]`) does not exist @@ -63,7 +65,7 @@ The data is stored in an attribute named `data`, within the Show instance: >>> t['scrubs'].data.keys() - ['networkid', 'rating', 'airs_dayofweek', 'contentrating', 'seriesname', 'id', 'airs_time', 'network', 'fanart', 'lastupdated', 'actors', 'ratingcount', 'status', 'added', 'poster', 'imdb_id', 'genre', 'banner', 'seriesid', 'language', 'zap2it_id', 'addedby', 'firstaired', 'runtime', 'overview'] + ['networkid', 'rating', 'airs_dayofweek', 'contentrating', 'seriesname', 'id', 'airs_time', 'network', 'fanart', 'lastupdated', 'actors', 'ratingcount', 'status', 'added', 'poster', 'imdb_id', 'genre', 'banner', 'seriesid', 'language', 'zap2it_id', 'addedby', 'tms_wanted', 'firstaired', 'runtime', 'overview'] Although each element is also accessible via `t['scrubs']` for ease-of-use: @@ -105,5 +107,5 @@ >>> t['scrubs']['actors'] u'|Zach Braff|Donald Faison|Sarah Chalke|Christa Miller|Aloma Wright|Robert Maschio|Sam Lloyd|Neil Flynn|Ken Jenkins|Judy Reyes|John C. McGinley|Travis Schuldt|Johnny Kastl|Heather Graham|Michael Mosley|Kerry Bish\xe9|Dave Franco|Eliza Coupe|' -[tvdb]: http://www.thetvdb.com +[tvdb]: http://thetvdb.com [tvnamer]: http://github.com/dbr/tvnamer
View file
tvdb_api-1.8.2.tar.bz2/setup.py -> tvdb_api-1.10.tar.gz/setup.py
Changed
@@ -1,7 +1,25 @@ +import sys from setuptools import setup + +IS_PY2 = sys.version_info[0] == 2 + +_requirements = [] +if not IS_PY2: + _requirements.append('requests_cache') + + # 'requests' is installed as requirement by requests-cache, + # commented out because it triggers a bug in setuptool: + # https://bitbucket.org/pypa/setuptools/issue/196/tests_require-pytest-pytest-cov-breaks + + +_modules = ['tvdb_api', 'tvdb_ui', 'tvdb_exceptions'] +if IS_PY2: + _modules.append('tvdb_cache') + + setup( name = 'tvdb_api', -version='1.8.2', +version='1.10', author='dbr/Ben', description='Interface to thetvdb.com', @@ -21,13 +39,19 @@ u'Stole a Badge' """, -py_modules = ['tvdb_api', 'tvdb_ui', 'tvdb_exceptions', 'tvdb_cache'], +py_modules = _modules, +install_requires = _requirements, classifiers=[ "Intended Audience :: Developers", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", + "Programming Language :: Python :: 2", + "Programming Language :: Python :: 2.6", + "Programming Language :: Python :: 2.7", + "Programming Language :: Python :: 3.3", + "Programming Language :: Python :: 3.4", "Topic :: Multimedia", "Topic :: Utilities", "Topic :: Software Development :: Libraries :: Python Modules",
View file
tvdb_api-1.8.2.tar.bz2/tests/test_tvdb_api.py -> tvdb_api-1.10.tar.gz/tests/test_tvdb_api.py
Changed
@@ -21,6 +21,10 @@ from tvdb_api import (tvdb_shownotfound, tvdb_seasonnotfound, tvdb_episodenotfound, tvdb_attributenotfound) + +IS_PY2 = sys.version_info[0] == 2 + + class test_tvdb_basic(unittest.TestCase): # Used to store the cached instance of Tvdb() t = None @@ -99,6 +103,10 @@ show ) + def test_no_season(self): + show = self.t['Katekyo Hitman Reborn'] + print(tvdb_api) + print(show[1][1]) class test_tvdb_errors(unittest.TestCase): # Used to store the cached instance of Tvdb() @@ -229,7 +237,7 @@ """Check valid_languages is up-to-date (compared to languages.xml) """ et = self.t._getetsrc( - "http://www.thetvdb.com/api/%s/languages.xml" % ( + "http://thetvdb.com/api/%s/languages.xml" % ( self.t.config['apikey'] ) ) @@ -452,13 +460,16 @@ self.fail("Expected ValueError from setting cache to float") def test_custom_urlopener(self): + if not IS_PY2: + raise unittest.SkipTest("cannot supply custom opener in Python 3 because requests is used") + class UsedCustomOpener(Exception): pass import urllib2 class TestOpener(urllib2.BaseHandler): def default_open(self, request): - print request.get_method() + print(request.get_method()) raise UsedCustomOpener("Something") custom_opener = urllib2.build_opener(TestOpener()) @@ -470,6 +481,26 @@ else: self.fail("Did not use custom opener") + def test_custom_request_session(self): + if IS_PY2: + return + from requests import Session as OriginalSession + class Used(Exception): + pass + class CustomCacheForTest(OriginalSession): + call_count = 0 + def request(self, *args, **kwargs): + raise Used("Hurray") + c = CustomCacheForTest() + t = tvdb_api.Tvdb(cache = c) + try: + t['scrubs'] + except Used: + pass + else: + self.fail("Did not use custom session") + + class test_tvdb_by_id(unittest.TestCase): t = None def setUp(self): @@ -505,6 +536,59 @@ self.assertEquals(self.t['My Name Is Earl'][1][4]['episodename'], 'Faked His Own Death') +class test_tvdb_show_ordering(unittest.TestCase): + # Used to store the cached instance of Tvdb() + t_dvd = None + t_air = None + + def setUp(self): + if self.t_dvd is None: + self.t_dvd = tvdb_api.Tvdb(cache = True, useZip = True, dvdorder=True) + + if self.t_air is None: + self.t_air = tvdb_api.Tvdb(cache = True, useZip = True) + + def test_ordering(self): + """Test Tvdb.search method + """ + self.assertEquals(u'The Train Job', self.t_air['Firefly'][1][1]['episodename']) + self.assertEquals(u'Serenity', self.t_dvd['Firefly'][1][1]['episodename']) + + self.assertEquals(u'The Cat & the Claw (Part 1)', self.t_air['Batman The Animated Series'][1][1]['episodename']) + self.assertEquals(u'On Leather Wings', self.t_dvd['Batman The Animated Series'][1][1]['episodename']) + +class test_tvdb_show_search(unittest.TestCase): + # Used to store the cached instance of Tvdb() + t = None + + def setUp(self): + if self.t is None: + self.__class__.t = tvdb_api.Tvdb(cache = True, useZip = True) + + def test_search(self): + """Test Tvdb.search method + """ + results = self.t.search("my name is earl") + all_ids = [x['seriesid'] for x in results] + self.assertTrue('75397' in all_ids) + + +class test_tvdb_alt_names(unittest.TestCase): + t = None + def setUp(self): + if self.t is None: + self.__class__.t = tvdb_api.Tvdb(cache = True, actors = True) + + def test_1(self): + """Tests basic access of series name alias + """ + results = self.t.search("Don't Trust the B---- in Apartment 23") + series = results[0] + self.assertTrue( + 'Apartment 23' in series['aliasnames'] + ) + + if __name__ == '__main__': runner = unittest.TextTestRunner(verbosity = 2) unittest.main(testRunner = runner)
View file
tvdb_api-1.8.2.tar.bz2/tvdb_api.egg-info/PKG-INFO -> tvdb_api-1.10.tar.gz/tvdb_api.egg-info/PKG-INFO
Changed
@@ -1,6 +1,6 @@ -Metadata-Version: 1.0 +Metadata-Version: 1.1 Name: tvdb-api -Version: 1.8.2 +Version: 1.10 Summary: Interface to thetvdb.com Home-page: http://github.com/dbr/tvdb_api/tree/master Author: dbr/Ben @@ -22,6 +22,11 @@ Classifier: Natural Language :: English Classifier: Operating System :: OS Independent Classifier: Programming Language :: Python +Classifier: Programming Language :: Python :: 2 +Classifier: Programming Language :: Python :: 2.6 +Classifier: Programming Language :: Python :: 2.7 +Classifier: Programming Language :: Python :: 3.3 +Classifier: Programming Language :: Python :: 3.4 Classifier: Topic :: Multimedia Classifier: Topic :: Utilities Classifier: Topic :: Software Development :: Libraries :: Python Modules
View file
tvdb_api-1.8.2.tar.bz2/tvdb_api.py -> tvdb_api-1.10.tar.gz/tvdb_api.py
Changed
@@ -5,7 +5,7 @@ #repository:http://github.com/dbr/tvdb_api #license:unlicense (http://unlicense.org/) -"""Simple-to-use Python interface to The TVDB's API (www.thetvdb.com) +"""Simple-to-use Python interface to The TVDB's API (thetvdb.com) Example usage: @@ -15,14 +15,23 @@ u'Cabin Fever' """ __author__ = "dbr/Ben" -__version__ = "1.8.2" +__version__ = "1.10" + +import sys + +IS_PY2 = sys.version_info[0] == 2 import os import time -import urllib -import urllib2 +if IS_PY2: + import urllib + import urllib2 + from tvdb_cache import CacheHandler + from urllib import quote as url_quote +else: + import requests + from urllib.parse import quote as url_quote import getpass -import StringIO import tempfile import warnings import logging @@ -40,7 +49,13 @@ gzip = None -from tvdb_cache import CacheHandler +if IS_PY2: + int_types = (int, long) + text_type = unicode +else: + int_types = int + text_type = str + from tvdb_ui import BaseUI, ConsoleUI from tvdb_exceptions import (tvdb_error, tvdb_userabort, tvdb_shownotfound, @@ -65,16 +80,12 @@ #keep only the 100th latest results if time.time() - self._lastgc > 20: - tbd = self._stack[:-100] - i = 0 - for o in tbd: + for o in self._stack[:-100]: del self[o] - del self._stack[i] - i += 1 + self._stack = self._stack[-100:] + + self._lastgc = time.time() - _lastgc = time.time() - del tbd - super(ShowContainer, self).__setitem__(key, value) @@ -171,7 +182,7 @@ searchresult = cur_season.search(term = term, key = key) if len(searchresult) != 0: results.extend(searchresult) - #end for cur_season + return results @@ -259,16 +270,14 @@ if term == None: raise TypeError("must supply string to search for (contents)") - term = unicode(term).lower() + term = text_type(term).lower() for cur_key, cur_value in self.items(): - cur_key, cur_value = unicode(cur_key).lower(), unicode(cur_value).lower() + cur_key, cur_value = text_type(cur_key).lower(), text_type(cur_value).lower() if key is not None and cur_key != key: # Do not search this key continue - if cur_value.find( unicode(term).lower() ) > -1: + if cur_value.find( text_type(term).lower() ) > -1: return self - #end if cur_value.find() - #end for cur_key, cur_value class Actors(list): @@ -308,7 +317,8 @@ search_all_languages = False, apikey = None, forceConnect=False, - useZip=False): + useZip=False, + dvdorder=False): """interactive (True/False): When True, uses built-in console UI is used to select the correct show. @@ -333,6 +343,12 @@ an arbitrary Python object, which is used as a urllib2 opener, which should be created by urllib2.build_opener + In Python 3, True/False enable or disable default + caching. Passing string specified directory where to store + the "tvdb.sqlite3" cache file. Also a custom + requests.Session instance can be passed (e.g maybe a + customised instance of requests_cache.CachedSession) + banners (True/False): Retrieves the banners for a show. These are accessed via the _banners key of a Show(), for example: @@ -382,6 +398,7 @@ And only the main language xml is used, the actor and banner xml are lost. """ + global lastTimeout # if we're given a lastTimeout that is less than 1 min just give up @@ -410,33 +427,61 @@ self.config['useZip'] = useZip + self.config['dvdorder'] = dvdorder - if cache is True: - self.config['cache_enabled'] = True - self.config['cache_location'] = self._getTempDir() - self.urlopener = urllib2.build_opener( - CacheHandler(self.config['cache_location']) - ) + if not IS_PY2: # FIXME: Allow using requests in Python 2? + import requests_cache + if cache is True: + self.session = requests_cache.CachedSession( + expire_after=21600, # 6 hours + backend='sqlite', + cache_name=self._getTempDir(), + ) + self.config['cache_enabled'] = True + elif cache is False: + self.session = requests.Session() + self.config['cache_enabled'] = False + elif isinstance(cache, text_type): + # Specified cache path + self.session = requests_cache.CachedSession( + expire_after=21600, # 6 hours + backend='sqlite', + cache_name=os.path.join(cache, "tvdb_api"), + ) + else: + self.session = cache + try: + self.session.get + except AttributeError: + raise ValueError("cache argument must be True/False, string as cache path or requests.Session-type object (e.g from requests_cache.CachedSession)") + else: + # For backwards compatibility in Python 2.x + if cache is True: + self.config['cache_enabled'] = True + self.config['cache_location'] = self._getTempDir() + self.urlopener = urllib2.build_opener( + CacheHandler(self.config['cache_location']) + ) - elif cache is False: - self.config['cache_enabled'] = False - self.urlopener = urllib2.build_opener() # default opener with no caching + elif cache is False: + self.config['cache_enabled'] = False + self.urlopener = urllib2.build_opener() # default opener with no caching - elif isinstance(cache, basestring): - self.config['cache_enabled'] = True - self.config['cache_location'] = cache - self.urlopener = urllib2.build_opener( - CacheHandler(self.config['cache_location']) - ) + elif isinstance(cache, basestring): + self.config['cache_enabled'] = True + self.config['cache_location'] = cache + self.urlopener = urllib2.build_opener( + CacheHandler(self.config['cache_location']) + ) - elif isinstance(cache, urllib2.OpenerDirector): - # If passed something from urllib2.build_opener, use that - log().debug("Using %r as urlopener" % cache) - self.config['cache_enabled'] = True - self.urlopener = cache + elif isinstance(cache, urllib2.OpenerDirector): + # If passed something from urllib2.build_opener, use that + log().debug("Using %r as urlopener" % cache) + self.config['cache_enabled'] = True + self.urlopener = cache - else: - raise ValueError("Invalid value for Cache %r (type was %s)" % (cache, type(cache))) + else: + raise ValueError("Invalid value for Cache %r (type was %s)" % (cache, type(cache))) self.config['banners_enabled'] = banners self.config['actors_enabled'] = actors @@ -448,7 +493,7 @@ logging.basicConfig(level=logging.DEBUG) - # List of language from http://www.thetvdb.com/api/0629B785CE550C8D/languages.xml + # List of language from http://thetvdb.com/api/0629B785CE550C8D/languages.xml # Hard-coded here as it is realtively static, and saves another HTTP request, as # recommended on http://thetvdb.com/wiki/index.php/API:languages.xml self.config['valid_languages'] = [ @@ -477,7 +522,7 @@ # The following url_ configs are based of the # http://thetvdb.com/wiki/index.php/Programmers_API - self.config['base_url'] = "http://www.thetvdb.com" + self.config['base_url'] = "http://thetvdb.com" if self.config['search_all_languages']: self.config['url_getSeries'] = u"%(base_url)s/api/GetSeries.php?seriesname=%%s&language=all" % self.config @@ -493,8 +538,6 @@ self.config['url_seriesBanner'] = u"%(base_url)s/api/%(apikey)s/series/%%s/banners.xml" % self.config self.config['url_artworkPrefix'] = u"%(base_url)s/banners/%%s" % self.config - #end __init__ - def _getTempDir(self): """Returns the [system temp dir]/tvdb_api-u501 (or tvdb_api-myuser) @@ -503,67 +546,96 @@ uid = "u%d" % (os.getuid()) else: # For Windows - uid = getpass.getuser() + try: + uid = getpass.getuser() + except ImportError: + return os.path.join(tempfile.gettempdir(), "tvdb_api") return os.path.join(tempfile.gettempdir(), "tvdb_api-%s" % (uid)) def _loadUrl(self, url, recache = False, language=None): - global lastTimeout - try: - log().debug("Retrieving URL %s" % url) - resp = self.urlopener.open(url) - if 'x-local-cache' in resp.headers: - log().debug("URL %s was cached in %s" % ( - url, - resp.headers['x-local-cache']) - ) - if recache: - log().debug("Attempting to recache %s" % url) - resp.recache() - except (IOError, urllib2.URLError), errormsg: - if not str(errormsg).startswith('HTTP Error'): - lastTimeout = datetime.datetime.now() - raise tvdb_error("Could not connect to server: %s" % (errormsg)) - #end try - - # handle gzipped content, - # http://dbr.lighthouseapp.com/projects/13342/tickets/72-gzipped-data-patch - if 'gzip' in resp.headers.get("Content-Encoding", ''): - if gzip: - stream = StringIO.StringIO(resp.read()) - gz = gzip.GzipFile(fileobj=stream) - return gz.read() - - raise tvdb_error("Received gzip data from thetvdb.com, but could not correctly handle it") + if not IS_PY2: + # Python 3: return content at URL as bytes + resp = self.session.get(url) + if 'application/zip' in resp.headers.get("Content-Type", ''): + try: + # TODO: The zip contains actors.xml and banners.xml, which are currently ignored [GH-20] + log().debug("We recived a zip file unpacking now ...") + from io import BytesIO + myzipfile = zipfile.ZipFile(BytesIO(resp.content)) + return myzipfile.read('%s.xml' % language) + except zipfile.BadZipfile: + self.session.cache.delete_url(url) + raise tvdb_error("Bad zip file received from thetvdb.com, could not read it") + return resp.content - if 'application/zip' in resp.headers.get("Content-Type", ''): + else: + global lastTimeout try: - # TODO: The zip contains actors.xml and banners.xml, which are currently ignored [GH-20] - log().debug("We recived a zip file unpacking now ...") - zipdata = StringIO.StringIO() - zipdata.write(resp.read()) - myzipfile = zipfile.ZipFile(zipdata) - return myzipfile.read('%s.xml' % language) - except zipfile.BadZipfile: + log().debug("Retrieving URL %s" % url) + resp = self.urlopener.open(url) if 'x-local-cache' in resp.headers: - resp.delete_cache() - raise tvdb_error("Bad zip file received from thetvdb.com, could not read it") - - return resp.read() + log().debug("URL %s was cached in %s" % ( + url, + resp.headers['x-local-cache']) + ) + if recache: + log().debug("Attempting to recache %s" % url) + resp.recache() + except (IOError, urllib2.URLError) as errormsg: + if not str(errormsg).startswith('HTTP Error'): + lastTimeout = datetime.datetime.now() + raise tvdb_error("Could not connect to server: %s" % (errormsg)) + + + # handle gzipped content, + # http://dbr.lighthouseapp.com/projects/13342/tickets/72-gzipped-data-patch + if 'gzip' in resp.headers.get("Content-Encoding", ''): + if gzip: + from StringIO import StringIO + stream = StringIO(resp.read()) + gz = gzip.GzipFile(fileobj=stream) + return gz.read() + + raise tvdb_error("Received gzip data from thetvdb.com, but could not correctly handle it") + + if 'application/zip' in resp.headers.get("Content-Type", ''): + try: + # TODO: The zip contains actors.xml and banners.xml, which are currently ignored [GH-20] + log().debug("We recived a zip file unpacking now ...") + from StringIO import StringIO + zipdata = StringIO() + zipdata.write(resp.read()) + myzipfile = zipfile.ZipFile(zipdata) + return myzipfile.read('%s.xml' % language) + except zipfile.BadZipfile: + if 'x-local-cache' in resp.headers: + resp.delete_cache() + raise tvdb_error("Bad zip file received from thetvdb.com, could not read it") + + return resp.read() def _getetsrc(self, url, language=None): """Loads a URL using caching, returns an ElementTree of the source """ src = self._loadUrl(url, language=language) + + + # TVDB doesn't sanitize \r (CR) from user input in some fields, + # remove it to avoid errors. Change from SickBeard, from will14m + if not IS_PY2: + # Remove trailing \r byte + src = src.replace(b"\r", b"") + else: + src = src.rstrip("\r") # FIXME: this seems wrong + try: - # TVDB doesn't sanitize \r (CR) from user input in some fields, - # remove it to avoid errors. Change from SickBeard, from will14m - return ElementTree.fromstring(src.rstrip("\r")) + return ElementTree.fromstring(src) except SyntaxError: src = self._loadUrl(url, recache=True, language=language) try: - return ElementTree.fromstring(src.rstrip("\r")) - except SyntaxError, exceptionmsg: + return ElementTree.fromstring(src) + except SyntaxError as exceptionmsg: errormsg = "There was an error with the XML retrieved from thetvdb.com:\n%s" % ( exceptionmsg ) @@ -576,7 +648,6 @@ errormsg += "\nIf this does not resolve the issue, please try again later. If the error persists, report a bug on" errormsg += "\nhttp://dbr.lighthouseapp.com/projects/13342-tvdb_api/overview\n" raise tvdb_error(errormsg) - #end _getetsrc def _setItem(self, sid, seas, ep, attrib, value): """Creates a new episode, creating Show(), Season() and @@ -600,7 +671,6 @@ if ep not in self.shows[sid][seas]: self.shows[sid][seas][ep] = Episode(season = self.shows[sid][seas]) self.shows[sid][seas][ep][attrib] = value - #end _set_item def _setShowData(self, sid, key, value): """Sets self.shows[sid] to a new Show instance, or sets the data @@ -619,15 +689,12 @@ data = data.replace(u"&", u"&") data = data.strip() return data - #end _cleanData - def _getSeries(self, series): - """This searches TheTVDB.com for the series name, - If a custom_ui UI is configured, it uses this to select the correct - series. If not, and interactive == True, ConsoleUI is used, if not - BaseUI is used to select the first result. + def search(self, series): + """This searches TheTVDB.com for the series name + and returns the result list """ - series = urllib.quote(series.encode("utf-8")) + series = url_quote(series.encode("utf-8")) log().debug("Searching for show %s" % series) seriesEt = self._getetsrc(self.config['url_getSeries'] % (series)) allSeries = [] @@ -635,9 +702,20 @@ result = dict((k.tag.lower(), k.text) for k in series.getchildren()) result['id'] = int(result['id']) result['lid'] = self.config['langabbv_to_id'][result['language']] + if 'aliasnames' in result: + result['aliasnames'] = result['aliasnames'].split("|") log().debug('Found series %(seriesname)s' % result) allSeries.append(result) - #end for series + + return allSeries + + def _getSeries(self, series): + """This searches TheTVDB.com for the series name, + If a custom_ui UI is configured, it uses this to select the correct + series. If not, and interactive == True, ConsoleUI is used, if not + BaseUI is used to select the first result. + """ + allSeries = self.search(series) if len(allSeries) == 0: log().debug('Series result returned zero') @@ -653,16 +731,12 @@ else: log().debug('Interactively selecting show using ConsoleUI') ui = ConsoleUI(config = self.config) - #end if config['interactive] - #end if custom_ui != None return ui.selectSeries(allSeries) - #end _getSeries - def _parseBanners(self, sid): """Parses banners XML, from - http://www.thetvdb.com/api/[APIKEY]/series/[SERIES ID]/banners.xml + http://thetvdb.com/api/[APIKEY]/series/[SERIES ID]/banners.xml Banners are retrieved using t['show name]['_banners'], for example: @@ -670,7 +744,7 @@ >>> t['scrubs']['_banners'].keys() ['fanart', 'poster', 'series', 'season'] >>> t['scrubs']['_banners']['poster']['680x1000']['35308']['_bannerpath'] - u'http://www.thetvdb.com/banners/posters/76156-2.jpg' + u'http://thetvdb.com/banners/posters/76156-2.jpg' >>> Any key starting with an underscore has been processed (not the raw @@ -703,7 +777,7 @@ tag, value = tag.lower(), value.lower() banners[btype][btype2][bid][tag] = value - for k, v in banners[btype][btype2][bid].items(): + for k, v in list(banners[btype][btype2][bid].items()): if k.endswith("path"): new_key = "_%s" % (k) log().debug("Transforming %s to %s" % (k, new_key)) @@ -714,7 +788,7 @@ def _parseActors(self, sid): """Parsers actors XML, from - http://www.thetvdb.com/api/[APIKEY]/series/[SERIES ID]/actors.xml + http://thetvdb.com/api/[APIKEY]/series/[SERIES ID]/actors.xml Actors are retrieved using t['show name]['_actors'], for example: @@ -731,7 +805,7 @@ >>> actors[0]['name'] u'Zach Braff' >>> actors[0]['image'] - u'http://www.thetvdb.com/banners/actors/43640.jpg' + u'http://thetvdb.com/banners/actors/43640.jpg' Any key starting with an underscore has been processed (not the raw data from the XML) @@ -790,7 +864,6 @@ value = self._cleanData(value) self._setShowData(sid, tag, value) - #end for series # Parse banners if self.config['banners_enabled']: @@ -811,8 +884,31 @@ epsEt = self._getetsrc( url, language=language) for cur_ep in epsEt.findall("Episode"): - seas_no = int(cur_ep.find('SeasonNumber').text) - ep_no = int(cur_ep.find('EpisodeNumber').text) + + if self.config['dvdorder']: + log().debug('Using DVD ordering.') + use_dvd = cur_ep.find('DVD_season').text != None and cur_ep.find('DVD_episodenumber').text != None + else: + use_dvd = False + + if use_dvd: + elem_seasnum, elem_epno = cur_ep.find('DVD_season'), cur_ep.find('DVD_episodenumber') + else: + elem_seasnum, elem_epno = cur_ep.find('SeasonNumber'), cur_ep.find('EpisodeNumber') + + if elem_seasnum is None or elem_epno is None: + log().warning("An episode has incomplete season/episode number (season: %r, episode: %r)" % ( + elem_seasnum, elem_epno)) + log().debug( + " ".join( + "%r is %r" % (child.tag, child.text) for child in cur_ep.getchildren())) + # TODO: Should this happen? + continue # Skip to next episode + + # float() is because https://github.com/dbr/tvnamer/issues/95 - should probably be fixed in TVDB data + seas_no = int(float(elem_seasnum.text)) + ep_no = int(float(elem_epno.text)) + for cur_item in cur_ep.getchildren(): tag = cur_item.tag.lower() value = cur_item.text @@ -822,8 +918,6 @@ else: value = self._cleanData(value) self._setItem(sid, seas_no, ep_no, tag, value) - #end for cur_ep - #end _geEps def _nameToSid(self, name): """Takes show name, returns the correct series ID (if the show has @@ -841,15 +935,14 @@ self.corrections[name] = sid self._getShowData(selected_series['id'], selected_series['language']) - #end if name in self.corrections + return sid - #end _nameToSid def __getitem__(self, key): """Handles tvdb_instance['seriesname'] calls. The dict index should be the show id """ - if isinstance(key, (int, long)): + if isinstance(key, int_types): # Item is integer, treat as show id if key not in self.shows: self._getShowData(key, self.config['language']) @@ -859,12 +952,10 @@ sid = self._nameToSid(key) log().debug('Got series id %s' % (sid)) return self.shows[sid] - #end __getitem__ def __repr__(self): return str(self.shows) - #end __repr__ -#end Tvdb + def main(): """Simple example of using tvdb_api - it just @@ -874,8 +965,8 @@ logging.basicConfig(level=logging.DEBUG) tvdb_instance = Tvdb(interactive=True, cache=False) - print tvdb_instance['Lost']['seriesname'] - print tvdb_instance['Lost'][1][4]['episodename'] + print(tvdb_instance['Lost']['seriesname']) + print(tvdb_instance['Lost'][1][4]['episodename']) if __name__ == '__main__': main()
View file
tvdb_api-1.8.2.tar.bz2/tvdb_cache.py -> tvdb_api-1.10.tar.gz/tvdb_cache.py
Changed
@@ -12,7 +12,7 @@ from __future__ import with_statement __author__ = "dbr/Ben" -__version__ = "1.8.2" +__version__ = "1.10" import os import time @@ -159,7 +159,6 @@ ) else: set_cache_header = True - #end if x-cache in response return CachedResponse( self.cache_location,
View file
tvdb_api-1.8.2.tar.bz2/tvdb_exceptions.py -> tvdb_api-1.10.tar.gz/tvdb_exceptions.py
Changed
@@ -9,7 +9,7 @@ """ __author__ = "dbr/Ben" -__version__ = "1.8.2" +__version__ = "1.10" __all__ = ["tvdb_error", "tvdb_userabort", "tvdb_shownotfound", "tvdb_seasonnotfound", "tvdb_episodenotfound", "tvdb_attributenotfound"] @@ -20,7 +20,7 @@ pass class tvdb_error(tvdb_exception): - """An error with www.thetvdb.com (Cannot connect, for example) + """An error with thetvdb.com (Cannot connect, for example) """ pass @@ -31,17 +31,17 @@ pass class tvdb_shownotfound(tvdb_exception): - """Show cannot be found on www.thetvdb.com (non-existant show) + """Show cannot be found on thetvdb.com (non-existant show) """ pass class tvdb_seasonnotfound(tvdb_exception): - """Season cannot be found on www.thetvdb.com + """Season cannot be found on thetvdb.com """ pass class tvdb_episodenotfound(tvdb_exception): - """Episode cannot be found on www.thetvdb.com + """Episode cannot be found on thetvdb.com """ pass
View file
tvdb_api-1.8.2.tar.bz2/tvdb_ui.py -> tvdb_api-1.10.tar.gz/tvdb_ui.py
Changed
@@ -43,13 +43,23 @@ """ __author__ = "dbr/Ben" -__version__ = "1.8.2" +__version__ = "1.10" +import sys import logging import warnings from tvdb_exceptions import tvdb_userabort + +IS_PY2 = sys.version_info[0] == 2 + +if IS_PY2: + user_input = raw_input +else: + user_input = input + + def log(): return logging.getLogger(__name__) @@ -80,7 +90,7 @@ else: toshow = allSeries - print "TVDB Search Results:" + print("TVDB Search Results:") for i, cshow in enumerate(toshow): i_show = i + 1 # Start at more human readable number 1 (not 0) log().debug('Showing allSeries[%s], series %s)' % (i_show, allSeries[i]['seriesname'])) @@ -89,31 +99,35 @@ else: extra = "" - print "%s -> %s [%s] # http://thetvdb.com/?tab=series&id=%s&lid=%s%s" % ( + output = "%s -> %s [%s] # http://thetvdb.com/?tab=series&id=%s&lid=%s%s" % ( i_show, - cshow['seriesname'].encode("UTF-8", "ignore"), - cshow['language'].encode("UTF-8", "ignore"), + cshow['seriesname'], + cshow['language'], str(cshow['id']), cshow['lid'], extra ) + if IS_PY2: + print(output.encode("UTF-8", "ignore")) + else: + print(output) def selectSeries(self, allSeries): self._displaySeries(allSeries) if len(allSeries) == 1: # Single result, return it! - print "Automatically selecting only result" + print("Automatically selecting only result") return allSeries[0] if self.config['select_first'] is True: - print "Automatically returning first search result" + print("Automatically returning first search result") return allSeries[0] while True: # return breaks this loop try: - print "Enter choice (first number, return for default, 'all', ? for help):" - ans = raw_input() + print("Enter choice (first number, return for default, 'all', ? for help):") + ans = user_input() except KeyboardInterrupt: raise tvdb_userabort("User aborted (^c keyboard interupt)") except EOFError: @@ -131,13 +145,13 @@ log().debug('Got quit command (q)') raise tvdb_userabort("User aborted ('q' quit command)") elif ans == "?": - print "## Help" - print "# Enter the number that corresponds to the correct show." - print "# a - display all results" - print "# all - display all results" - print "# ? - this help" - print "# q - abort tvnamer" - print "# Press return with no input to select first result" + print("## Help") + print("# Enter the number that corresponds to the correct show.") + print("# a - display all results") + print("# all - display all results") + print("# ? - this help") + print("# q - abort tvnamer") + print("# Press return with no input to select first result") elif ans.lower() in ["a", "all"]: self._displaySeries(allSeries, limit = None) else: @@ -148,8 +162,6 @@ return allSeries[selected_id] except IndexError: log().debug('Invalid show number entered!') - print "Invalid number (%s) selected!" + print("Invalid number (%s) selected!") self._displaySeries(allSeries) - #end try - #end while not valid_input
Locations
Projects
Search
Status Monitor
Help
Open Build Service
OBS Manuals
API Documentation
OBS Portal
Reporting a Bug
Contact
Mailing List
Forums
Chat (IRC)
Twitter
Open Build Service (OBS)
is an
openSUSE project
.