Skip to content

Commit

Permalink
update urlresolver docs and document HostedMediaFile ready for merge …
Browse files Browse the repository at this point in the history
…back to master

still got plugin tutorial to work through....
  • Loading branch information
t0mm0 committed Oct 30, 2011
1 parent 7679772 commit 048993d
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 82 deletions.
2 changes: 2 additions & 0 deletions doc/source/modules/urlresolver/urlresolver.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@
.. automodule:: urlresolver
:members:

.. autoclass:: HostedMediaFile
:members:
124 changes: 43 additions & 81 deletions script.module.urlresolver/lib/urlresolver/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
For most cases you probably want to use :func:`urlresolver.resolve` or
:func:`urlresolver.choose_source`.
.. seealso::
:class:`HostedMediaFile`
'''

import os
Expand All @@ -35,7 +41,7 @@
plugnplay.load_plugins()

def resolve(web_url):
"""
'''
Resolve a web page to a media stream.
It is usually as simple as::
Expand All @@ -52,112 +58,66 @@ def resolve(web_url):
the URL, it passes the ``web_url`` to the plugin and returns the direct URL
to the media file, or ``False`` if it was not possible to resolve.
.. seealso::
:class:`HostedMediaFile`
Args:
web_url (str): A URL to a web page associated with a piece of media
content.
Returns:
If the ``web_url`` could be resolved, a string containing the direct
URL to the media file, if not, returns ``False``.
"""
imp = find_resolver(web_url)
if imp:
common.addon.log_notice('resolving using %s plugin' % imp.name)
if SiteAuth in imp.implements:
common.addon.log_debug('logging in')
imp.login()
return imp.get_media_url(web_url)
return False

def filter_urls(urls):
'''
Takes a list of URLs to web pages that are thought to be associated with
media content. If no resolver plugins exist to resolve a URL to a link to a
media file it is removed from the list.
Args:
urls (list of str): A list of URLs thought to be associated with media
content.
Returns:
The same list of URLs but with any that can't be resolved by a resolver
plugin removed.
'''
ret = []
for url in urls:
imp = find_resolver(url)
if imp:
ret.append(url)
return ret

def filter_dict(d):
'''
Similar to :func:`filter_urls` but takes a dictionary where the keys are
web URLs to check and returns a dictionary which only contains items that
have a resolver plugin.
Useful for when you want to filter a list of web URLs and keep some other
information with each URL.
Args:
d (dict): A dictionary where the keys are all web URLs
Returns:
A copy of the dictionary with items that can't be resolved by a resolver
plugin removed.
'''
return dict((k, v) for k, v in d.iteritems() if find_resolver(k))
source = HostedMediaFile(url=web_url)
return source.resolve()

def filter_source_list(source_list):
return [source for source in source_list if source]


def find_resolver(web_url):
'''
Finds the first resolver that says it can resolve the given URL to a media
file. Note that it might not actually be able to, but it advertises the
fact that it can.
.. note::
Takes a list of :class:`HostedMediaFile`s representing web pages that are
thought to be associated with media content. If no resolver plugins exist
to resolve a :class:`HostedMediaFile` to a link to a media file it is
removed from the list.
You probably won't need to access this function for normal usage - just
use :func:`urlresolver.resolve`.
Args:
web_url (str): A URL to a web page associated with a piece of media
content.
urls (list of :class:`HostedMediaFile`): A list of
:class:`HostedMediaFiles` representing web pages that are thought to be
associated with media content.
Returns:
An instance of a class that implements
:class:`urlresolver.plugnplay.interfaces.UrlResolver` and advertises
that it can resolve the given ``web_url``.
The same list of :class:`HostedMediaFile` but with any that can't be
resolved by a resolver plugin removed.
'''
for imp in UrlResolver.implementors():
if imp.valid_url(web_url):
return imp
return False
return [source for source in source_list if source]


def choose_source(sources):
'''
Given a dictionary of sources where the keys are web URLs to be resolved and
the values are a title to display this function checks which are playable
and if there are more than one it pops up a dialog box displaying the
choices.
Given a list of :class:`HostedMediaFile` representing web pages that are
thought to be associated with media content this function checks which are
playable and if there are more than one it pops up a dialog box displaying
the choices.
Example::
sources = {'http://youtu.be/VIDEOID': 'Youtube [verified] (20 views)',
'http://putlocker.com/file/VIDEOID': 'Putlocker (3 views)'}
stream_url = urlresolver.choose_source(sources)
sources = [HostedMediaFile(url='http://youtu.be/VIDEOID', title='Youtube [verified] (20 views)'),
HostedMediaFile(url='http://putlocker.com/file/VIDEOID', title='Putlocker (3 views)')]
source = urlresolver.choose_source(sources)
if source:
stream_url = source.resolve()
addon.resolve_url(stream_url)
else:
addon.resolve_url(False)
Args:
sources (dict): A dictionary where the keys are web URLs to be resolved
and the values are titles to be displayed in the coice dialog.
sources (list): A list of :class:`HostedMediaFile` representing web
pages that are thought to be associated with media content.
Returns:
If the chosen URL could be resolved, a string containing the direct
URL to the media file, if not, returns ``False``.
The chosen :class:`HostedMediaFile` or ``False`` if the dialog is
cancelled or none of the :class:`HostedMediaFile` are resolvable.
'''
#get rid of sources with no resolver plugin
Expand Down Expand Up @@ -201,6 +161,7 @@ def display_settings():
_update_settings_xml()
common.addon.show_settings()


def _update_settings_xml():
'''
This function writes a new ``resources/settings.xml`` file which contains
Expand All @@ -226,5 +187,6 @@ def _update_settings_xml():
except IOError:
common.addon.log_error('error writing ' + common.settings_file)


#make sure settings.xml is up to date
_update_settings_xml()
86 changes: 85 additions & 1 deletion script.module.urlresolver/lib/urlresolver/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,50 @@
from plugnplay.interfaces import SiteAuth

class HostedMediaFile:

'''
This class represents a piece of media (file or stream) that is hosted
somewhere on the internet. It may be instantiated with EITHER the url to the
web page associated with the media file, OR the host name and a unique
``media_id`` used by the host to point to the media.
For example::
HostedMediaFile(url='http://youtube.com/watch?v=ABC123XYZ')
represents the same piece of media as::
HostedMediaFile(host='youtube.com', media_id='ABC123XYZ')
``title`` is a free text field useful for display purposes such as in
:func:`choose_source`.
.. note::
If there is no resolver plugin to handle the arguments passed,
the resulting object will evaluate to ``False``. Otherwise it will
evaluate to ``True``. This is a handy way of checking whether
a resolver exists::
hmf = HostedMediaFile('http://youtube.com/watch?v=ABC123XYZ')
if hmf:
print 'yay! we can resolve this one'
else:
print 'sorry :( no resolvers available to handle this one.')
.. warning::
If you pass ``url`` you must not pass ``host`` or ``media_id``. You
must pass either ``url`` or ``host`` AND ``media_id``.
'''
def __init__(self, url='', host='', media_id='', title=''):
'''
Args:
url (str): a URL to a web page that represents a piece of media.
host (str): the host of the media to be represented.
media_id (str): the unique ID given to the media by the host.
'''
if not url and not (host and media_id) or (url and (host or media_id)):
raise ValueError('Set either url, or host AND media_id. ' +
'No other combinations are valid.')
Expand All @@ -42,15 +84,43 @@ def __init__(self, url='', host='', media_id='', title=''):
self.title = self._host

def get_url(self):
'''
Returns the URL of this :class:`HostedMediaFile`.
'''
return self._url

def get_host(self):
'''
Returns the host of this :class:`HostedMediaFile`.
'''
return self._host

def get_media_id(self):
'''
Returns the media_id of this :class:`HostedMediaFile`.
'''
return self._media_id

def resolve(self):
'''
Resolves this :class:`HostedMediaFile` to a media URL.
Example::
stream_url = HostedMediaFile(host='youtube.com', media_id='ABC123XYZ').resolve()
.. note::
This method currently uses just the highest priority resolver to
attempt to resolve to a media URL and if that fails it will return
False. In future perhaps we should be more clever and check to make
sure that there are no more resolvers capable of attempting to
resolve the URL first.
Returns:
A direct URL to the media file that is playable by XBMC, or False
if this was not possible.
'''
if self._resolvers:
resolver = self._resolvers[0]
common.addon.log_debug('resolving using %s plugin' % resolver.name)
Expand All @@ -62,6 +132,20 @@ def resolve(self):
return False

def valid_url(self):
'''
Returns True if the ``HostedMediaFile`` can be resolved.
.. note::
The following are exactly equivalent::
if HostedMediaFile('http://youtube.com/watch?v=ABC123XYZ').valid_url():
print 'resolvable!'
if HostedMediaFile('http://youtube.com/watch?v=ABC123XYZ'):
print 'resolvable!'
'''
if self._resolvers:
return True
return False
Expand Down

0 comments on commit 048993d

Please sign in to comment.