From 0713c9883c5e268dfc6a96baeb2c79cc957d924d Mon Sep 17 00:00:00 2001 From: Changaco Date: Wed, 30 Jan 2013 14:24:42 +0100 Subject: [PATCH] rename to media_hosts, add README, license and packaging stuff --- MANIFEST.in | 1 + README.rst | 36 +++++++++++++++++++ {media_info => media_hosts}/__init__.py | 28 +++++++++------ {media_info => media_hosts}/__main__.py | 16 ++++++--- .../backends/__init__.py | 0 .../backends/beatport.py | 14 ++++++-- .../backends/soundcloud.py | 14 ++++++-- .../backends/youtube.py | 14 ++++++-- {media_info => media_hosts}/imports.py | 10 +++++- {media_info => media_hosts}/utils.py | 8 +++++ setup.py | 22 ++++++++++++ version.py | 36 +++++++++++++++++++ 12 files changed, 175 insertions(+), 24 deletions(-) create mode 100644 MANIFEST.in create mode 100644 README.rst rename {media_info => media_hosts}/__init__.py (69%) rename {media_info => media_hosts}/__main__.py (62%) rename {media_info => media_hosts}/backends/__init__.py (100%) rename {media_info => media_hosts}/backends/beatport.py (74%) rename {media_info => media_hosts}/backends/soundcloud.py (80%) rename {media_info => media_hosts}/backends/youtube.py (90%) rename {media_info => media_hosts}/imports.py (51%) rename {media_info => media_hosts}/utils.py (68%) create mode 100644 setup.py create mode 100644 version.py diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..2e92268 --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1 @@ +include version.py diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..8f0fe45 --- /dev/null +++ b/README.rst @@ -0,0 +1,36 @@ +python-media-hosts gets media info from sites like Youtube and Soundcloud. + +Installation +============ + + pip install media-hosts + +media-hosts is compatible with python 2 and 3. + +Dependencies: + +- miss + +Optional dependencies: + +- python-dateutil: to parse dates returned by various APIs +- gdata: for some Youtube data +- jsonpickle: for __main__.py + +Usage +===== + +From python:: + + from media_hosts import MediaHosts, MediaHostException + media_hosts = MediaHosts(_=_, settings=settings) + media_hosts.get_info_by_url(url) + +From the command line:: + + $ python -m media_hosts 'https://www.youtube.com/watch?v=Gn3QXjNQNsk' + +License +======= + +LGPLv3+ diff --git a/media_info/__init__.py b/media_hosts/__init__.py similarity index 69% rename from media_info/__init__.py rename to media_hosts/__init__.py index e21e817..32e8631 100644 --- a/media_info/__init__.py +++ b/media_hosts/__init__.py @@ -1,3 +1,11 @@ +# This file is part of a program licensed under the terms of the GNU Lesser +# General Public License version 3 (or at your option any later version) +# as published by the Free Software Foundation. +# +# If you have not received a copy of the GNU Lesser General Public License +# along with this file, see . + + from importlib import import_module from os import listdir from os.path import dirname @@ -17,14 +25,14 @@ def list_backends(): if a[0] != '_' and a.endswith('.py')] -class MediaInfo: +class MediaHosts: def __init__(self, backends=None, _=mirror, settings={}): self._ = _ self.backends = [] for backend in (backends or list_backends()): try: - module = import_module('media_info.backends.'+backend) + module = import_module('media_hosts.backends.'+backend) cls = getattr(module, backend+'_backend') instance = cls(_, settings) self.backends.append(instance) @@ -33,30 +41,30 @@ def __init__(self, backends=None, _=mirror, settings={}): self.domains = {domain: backend for backend in self.backends for domain in backend.DOMAINS} - def get(self, url_str, raw=False): - url, backend = self.get_backend(url_str) - return self.get_by_id(backend, backend.get_id(url), raw) - def get_backend(self, url_str): url = urlparse(url_str) # this doesn't validate the URL and doesn't throw exceptions try: return (url, self.domains[pstrip(url.hostname, 'www.')]) except KeyError: - raise MediaInfoException(self._('Unrecognized domain name: %s') % url.hostname) + raise MediaHostException(self._('Unrecognized domain name: %s') % url.hostname) - def get_by_id(self, backend, media_id, raw=False): + def get_info_by_id(self, backend, media_id, raw=False): info = backend.get_info(media_id, raw) info.id = media_id info.service = backend.NAME return info + def get_info_by_url(self, url_str, raw=False): + url, backend = self.get_backend(url_str) + return self.get_info_by_id(backend, backend.get_id(url), raw) + def normalize(self, url_str): url, backend = self.get_backend(url_str) i = backend.get_id(url) return (backend, backend.normalize(i), i) -class MediaInfoBackend(object): +class MediaHost(object): def __init__(self, _, settings): self._ = _ @@ -67,4 +75,4 @@ def init(self): pass -class MediaInfoException(Exception): pass +class MediaHostException(Exception): pass diff --git a/media_info/__main__.py b/media_hosts/__main__.py similarity index 62% rename from media_info/__main__.py rename to media_hosts/__main__.py index 7675630..e538441 100644 --- a/media_info/__main__.py +++ b/media_hosts/__main__.py @@ -1,3 +1,11 @@ +# This file is part of a program licensed under the terms of the GNU Lesser +# General Public License version 3 (or at your option any later version) +# as published by the Free Software Foundation. +# +# If you have not received a copy of the GNU Lesser General Public License +# along with this file, see . + + from __future__ import print_function, unicode_literals import argparse @@ -7,7 +15,7 @@ except ImportError: jsonpickle = None -from . import MediaInfo, MediaInfoException +from . import MediaHosts, MediaHostException from .utils import urldecode @@ -28,10 +36,10 @@ def default(self, obj): settings = dict(s.split('=') for s in args.settings) -media_info = MediaInfo(backends=args.backends, settings=settings) +media_hosts = MediaHosts(backends=args.backends, settings=settings) try: - info = media_info.get(args.uri, args.raw) -except MediaInfoException as e: + info = media_hosts.get_info_by_url(args.uri, args.raw) +except MediaHostException as e: print(e.args[0]) exit(1) diff --git a/media_info/backends/__init__.py b/media_hosts/backends/__init__.py similarity index 100% rename from media_info/backends/__init__.py rename to media_hosts/backends/__init__.py diff --git a/media_info/backends/beatport.py b/media_hosts/backends/beatport.py similarity index 74% rename from media_info/backends/beatport.py rename to media_hosts/backends/beatport.py index 24dced7..185180d 100644 --- a/media_info/backends/beatport.py +++ b/media_hosts/backends/beatport.py @@ -1,3 +1,11 @@ +# This file is part of a program licensed under the terms of the GNU Lesser +# General Public License version 3 (or at your option any later version) +# as published by the Free Software Foundation. +# +# If you have not received a copy of the GNU Lesser General Public License +# along with this file, see . + + from __future__ import division, print_function, unicode_literals import json @@ -7,7 +15,7 @@ track_id_re = re.compile(r'/track/[^/]*/([0-9]+)') -class beatport_backend(MediaInfoBackend): +class beatport_backend(MediaHost): DOMAINS = ('beatport.com',) NAME = 'Beatport' @@ -15,7 +23,7 @@ class beatport_backend(MediaInfoBackend): def get_id(self, url): track_id = track_id_re.search(url.path) if not track_id: - raise MediaInfoException(self._('Unrecognized url: %s') % url.geturl()) + raise MediaHostException(self._('Unrecognized url: %s') % url.geturl()) return track_id.group(1) def get_info(self, track_id, raw): @@ -26,7 +34,7 @@ def get_info(self, track_id, raw): return info t = iNS(info.results.get('track', None)) if not t: - raise MediaInfoException(self._('Failed to retrieve information for track %s' % (track_id))) + raise MediaHostException(self._('Failed to retrieve information for track %s' % (track_id))) make_author = safe(lambda a: {'name':a['name'], 'urlname':a['slug']}) r.authors = list(filter(None, map(make_author, t.artists))) waveform = t.images.pop('waveform', identity) diff --git a/media_info/backends/soundcloud.py b/media_hosts/backends/soundcloud.py similarity index 80% rename from media_info/backends/soundcloud.py rename to media_hosts/backends/soundcloud.py index bf15496..78ae18c 100644 --- a/media_info/backends/soundcloud.py +++ b/media_hosts/backends/soundcloud.py @@ -1,3 +1,11 @@ +# This file is part of a program licensed under the terms of the GNU Lesser +# General Public License version 3 (or at your option any later version) +# as published by the Free Software Foundation. +# +# If you have not received a copy of the GNU Lesser General Public License +# along with this file, see . + + from __future__ import division, print_function, unicode_literals import json @@ -6,7 +14,7 @@ from ..imports import * -class soundcloud_backend(MediaInfoBackend): +class soundcloud_backend(MediaHost): DOMAINS = ('soundcloud.com',) NAME = 'Soundcloud' @@ -24,13 +32,13 @@ def get_id(self, url): def get_info(self, track_id, raw): if not hasattr(self, 'info_url'): - raise MediaInfoException(self._('Error: you need to provide a client ID to use the %s backend') % self.NAME) + raise MediaHostException(self._('Error: you need to provide a client ID to use the %s backend') % self.NAME) r = iNS(type='audio') info = iNS(json.loads(urlopen(self.info_url+track_id).read())) if raw: return info if info.kind != 'track': - raise MediaInfoException(self._('%s is a %s, not a track' % (track_id,info.kind))) + raise MediaHostException(self._('%s is a %s, not a track' % (track_id,info.kind))) r.alternates = call(lambda url: [{'type':'video','url':url}], info.video_url or identity) make_author = safe(lambda u: {'name':u['username'], 'urlname':u['permalink']}) r.authors = call(lambda a: [a], make_author(info.user or {})) diff --git a/media_info/backends/youtube.py b/media_hosts/backends/youtube.py similarity index 90% rename from media_info/backends/youtube.py rename to media_hosts/backends/youtube.py index 96ba258..fd0d52a 100644 --- a/media_info/backends/youtube.py +++ b/media_hosts/backends/youtube.py @@ -1,3 +1,11 @@ +# This file is part of a program licensed under the terms of the GNU Lesser +# General Public License version 3 (or at your option any later version) +# as published by the Free Software Foundation. +# +# If you have not received a copy of the GNU Lesser General Public License +# along with this file, see . + + from __future__ import division, print_function, unicode_literals from ..imports import * @@ -11,7 +19,7 @@ video_id_re = re.compile(r'/(?:watch\?.*v=)?([a-zA-Z0-9_-]{11})') -class youtube_backend(MediaInfoBackend): +class youtube_backend(MediaHost): DOMAINS = ('youtube.com', 'youtu.be') NAME = 'Youtube' @@ -19,7 +27,7 @@ class youtube_backend(MediaInfoBackend): def get_id(self, url): video_id = video_id_re.search(url.path + '?' + url.query) if not video_id: - raise MediaInfoException(self._('Unrecognized url: %s') % url.geturl()) + raise MediaHostException(self._('Unrecognized url: %s') % url.geturl()) return video_id.group(1) def get_info(self, video_id, raw): @@ -101,7 +109,7 @@ def get_info(self, video_id, raw): error = self._('Youtube said:\n"%s"') % max(errors, key=len) else: error = self._('unknown reason') - raise MediaInfoException(self._('Getting video info failed, %s') % error) + raise MediaHostException(self._('Getting video info failed, %s') % error) return r diff --git a/media_info/imports.py b/media_hosts/imports.py similarity index 51% rename from media_info/imports.py rename to media_hosts/imports.py index 060c1c6..09492c4 100644 --- a/media_info/imports.py +++ b/media_hosts/imports.py @@ -1,3 +1,11 @@ +# This file is part of a program licensed under the terms of the GNU Lesser +# General Public License version 3 (or at your option any later version) +# as published by the Free Software Foundation. +# +# If you have not received a copy of the GNU Lesser General Public License +# along with this file, see . + + from datetime import datetime import re try: @@ -16,5 +24,5 @@ from miss.namespace import iNS from miss.six import ustr -from . import MediaInfoBackend, MediaInfoException, mirror +from . import MediaHost, MediaHostException, mirror from .utils import * diff --git a/media_info/utils.py b/media_hosts/utils.py similarity index 68% rename from media_info/utils.py rename to media_hosts/utils.py index 4969f5f..a107c86 100644 --- a/media_info/utils.py +++ b/media_hosts/utils.py @@ -1,3 +1,11 @@ +# This file is part of a program licensed under the terms of the GNU Lesser +# General Public License version 3 (or at your option any later version) +# as published by the Free Software Foundation. +# +# If you have not received a copy of the GNU Lesser General Public License +# along with this file, see . + + try: from urllib.parse import parse_qsl except ImportError: diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..0a67687 --- /dev/null +++ b/setup.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- + +from os.path import join, dirname + +from setuptools import setup, find_packages + +from version import get_version + +setup( + name='media-hosts', + version=get_version(), + description='Gets media info from sites like Youtube and Soundcloud', + author='Changaco', + author_email='changaco ατ changaco δοτ net', + url='https://github.com/Changaco/python-media-hosts', + license='LGPLv3+', + packages=find_packages(), + long_description=open(join(dirname(__file__), 'README.rst')).read(), + install_requires = [ + 'miss>=0.2', + ], +) diff --git a/version.py b/version.py new file mode 100644 index 0000000..3441617 --- /dev/null +++ b/version.py @@ -0,0 +1,36 @@ +# This program is placed into the public domain. + +__all__ = ('get_version') + +from os.path import dirname, isdir, join +import re +from subprocess import CalledProcessError, check_output + +version_re = re.compile('^Version: (.+)$', re.M) + +def get_version(): + d = dirname(__file__) + + if isdir(join(d, '.git')): + # Get the version using "git describe". + cmd = 'git describe --tags --match [0-9]*'.split() + try: + version = check_output(cmd).decode().strip() + except CalledProcessError: + print('Unable to get version number from git tags') + exit(1) + + # PEP 386 compatibility + if '-' in version: + version = '.post'.join(version.split('-')[:2]) + + else: + # Extract the version from the PKG-INFO file. + with open(join(d, 'PKG-INFO')) as f: + version = version_re.search(f.read()).group(1) + + return version + + +if __name__ == '__main__': + print(get_version())