aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore57
-rw-r--r--README.md3
-rw-r--r--anidb/__init__.py139
-rw-r--r--setup.py36
4 files changed, 235 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c6797c2
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,57 @@
+# Created by http://www.gitignore.io
+
+### Python ###
+# Byte-compiled / optimized / DLL files
+__pycache__/
+*.py[cod]
+
+# C extensions
+*.so
+
+# Distribution / packaging
+.Python
+env/
+build/
+develop-eggs/
+dist/
+eggs/
+lib/
+lib64/
+parts/
+sdist/
+var/
+*.egg-info/
+.installed.cfg
+*.egg
+
+# PyInstaller
+# Usually these files are written by a python script from a template
+# before PyInstaller builds the exe, so as to inject date/other infos into it.
+*.manifest
+*.spec
+
+# Installer logs
+pip-log.txt
+pip-delete-this-directory.txt
+
+# Unit test / coverage reports
+htmlcov/
+.tox/
+.coverage
+.cache
+nosetests.xml
+coverage.xml
+
+# Translations
+*.mo
+*.pot
+
+# Django stuff:
+*.log
+
+# Sphinx documentation
+docs/_build/
+
+# PyBuilder
+target/
+
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..4ec932e
--- /dev/null
+++ b/README.md
@@ -0,0 +1,3 @@
+# anidb.py
+
+AniDB API wrapper \ No newline at end of file
diff --git a/anidb/__init__.py b/anidb/__init__.py
new file mode 100644
index 0000000..29e9b78
--- /dev/null
+++ b/anidb/__init__.py
@@ -0,0 +1,139 @@
+import requests
+from bs4 import BeautifulSoup
+
+from datetime import datetime
+
+BASE_URL = "http://api.anidb.net:9001/httpapi"
+SEARCH_URL = "http://anisearch.outrance.pl/"
+PROTOCOL_VERSION = 1
+
+try:
+ str = unicode
+except:
+ pass
+ # str = str
+
+class AniDB:
+ def __init__(self, client_id, client_ver=0):
+ self.client_id = client_id
+ self.client_ver = client_ver
+ self._cache = {}
+
+ def _request(self, datapage, params={}, cache=True):
+ params.update({
+ 'client': self.client_id,
+ 'clientver': self.client_ver,
+ 'protover': PROTOCOL_VERSION,
+ 'request': datapage
+ })
+ r = requests.get(BASE_URL, params=params)
+ r.raise_for_status()
+ return r
+
+ # Anime http://wiki.anidb.net/w/HTTP_API_Definition#Access
+
+ def search(self, q):
+ """
+ Search for `aid`s by anime title using service provided by eloyard.
+ http://anisearch.outrance.pl/doc.html
+ """
+ r = requests.get(SEARCH_URL, params={
+ 'task': "search",
+ 'query': q,
+ })
+ r.raise_for_status()
+ results = []
+ animetitles = BeautifulSoup(r.text, 'xml').animetitles
+ for anime in animetitles.find_all('anime'):
+ results.append(Anime({
+ 'id': int(anime['id']),
+ 'title': str(anime.find('title', attrs={'type': "main"}).string)
+ }, partial=True, updater=lambda: self.get(anime['id'])))
+
+ return results
+
+ def get(self, id):
+ """
+ Allows retrieval of non-file or episode related information for a specific anime by AID (AniDB anime id).
+ http://wiki.anidb.net/w/HTTP_API_Definition#Anime
+ """
+ id = int(id) # why?
+
+ r = self._request("anime", {'aid': id})
+ soup = BeautifulSoup(r.text, 'xml')
+ if soup.error is not None:
+ raise Exception(soup.error.string)
+
+ anime = soup.anime
+ titles = anime.titles
+
+ a = Anime({
+ 'id': id,
+ 'type': str(anime.type.string),
+ 'episodecount': int(anime.episodecount.string),
+ 'startdate': datetime(*list(map(int, anime.startdate.string.split("-")))),
+ 'enddate': datetime(*list(map(int, anime.enddate.string.split("-")))),
+ 'titles': [(
+ str(title.string),
+ title['type'] if 'type' in title else "unknown"
+ ) for title in anime.find_all('title')],
+ 'title': str(titles.find('title', attrs={'type': "main"}).string),
+ 'relatedanime': [],
+ 'url': str(anime.url.string),
+ 'creators': [],
+ 'description': str(anime.description.string),
+ 'ratings': SmartDict({
+ 'permanent': float(anime.ratings.permanent.string),
+ 'temporary': float(anime.ratings.temporary.string),
+ 'review': float(anime.ratings.review.string)
+ }),
+ 'picture': "http://img7.anidb.net/pics/anime/" + str(anime.picture.string),
+ 'categories': [],
+ 'tags': [],
+ 'characters': [],
+ 'episodes': [],
+ })
+
+ self._cache[id] = a
+
+ return a
+
+class SmartDict(dict):
+ def __init__(self, *a, **kw):
+ super(SmartDict, self).__init__(**kw)
+ for x in a:
+ try:
+ self.update(x)
+ except TypeError:
+ self.update(x.__dict__)
+ self.__dict__ = self
+
+class Anime:
+ def __init__(self, data={}, partial=False, **kw):
+ self._data = data
+ self._partial = partial
+ if partial:
+ self._updater = kw['updater']
+
+ def _update(self):
+ if not self._partial:
+ raise Exception("Attempted to update a ready object")
+ else:
+ self._data = self._updater()._data
+ self._partial = False
+
+ def __getattr__(self, name):
+ if name in self._data:
+ return self._data[name]
+ else:
+ if self._partial:
+ self._update()
+ if name in self._data:
+ return self._data[name]
+ else:
+ raise AttributeError("no attribute called '%s'" % name)
+ else:
+ raise AttributeError("no attribute called '%s'" % name)
+
+ def __repr__(self):
+ return u'<Anime %i "%s">' % (self.id, self.title) \ No newline at end of file
diff --git a/setup.py b/setup.py
new file mode 100644
index 0000000..a75b0f8
--- /dev/null
+++ b/setup.py
@@ -0,0 +1,36 @@
+#!/usr/bin/env python
+
+import os
+import sys
+
+try:
+ from setuptools import setup
+except ImportError:
+ from distutils.core import setup
+
+if sys.argv[-1] == 'publish':
+ os.system('python setup.py sdist upload')
+ sys.exit()
+
+setup(
+ name="anidb",
+ version="0.0.1",
+ description="AniDB API wrapper",
+ long_description="",
+ url="https://github.com/iamale/anidb.py",
+ author="Ale",
+ author_email="ale@incrowd.ws",
+ packages=['anidb'],
+ package_dir={'anidb': 'anidb'},
+ install_requires=["requests==2.3.0", "beautifulsoup4==4.3.2"],
+ license='MIT',
+ classifiers=(
+ 'Development Status :: 2 - Pre-Alpha',
+ 'Intended Audience :: Developers',
+ 'Natural Language :: English',
+ 'License :: OSI Approved :: MIT License',
+ 'Programming Language :: Python',
+ 'Programming Language :: Python :: 2.6',
+ 'Programming Language :: Python :: 2.7'
+ ),
+)