This is a sample dummy provider for Quasar.
PLEASE NOTE THAT THIS IS SUBJECT TO CHANGE QUITE HEAVILY
When Quasar wants to find a stream for a media, it will call all the providers installed on the locally running XBMC instance.
To be recognized as a Quasar provider, the addon's name has to start with script.quasar.
.
Quasar will round up all the matching addons and call them using XBMC.RunAddon()
.
You can test your provider by calling Quasar on these endpoints
http://localhost:65251/provider/<PROVIDER_ID>/movie/<TMDB_ID>
http://localhost:65251/provider/<PROVIDER_ID>/show/<TMDB_ID>/season/<SEASON>/episode/<EPISODE>
It will print the search payload and the return results, as interpreted by Quasar.
Quasar ships with a provider SDK that unifies some of tasks commonly found in providers. For lack of PyDoc, we'll document this here for now.
To use this SDK, you must declare Quasar as a dependency for your provider and import the module
<import addon="plugin.video.quasar" version="0.9.1"/>
Then in your provider module:
from quasar import provider
provider.ADDON
provider.ADDON_ID
provider.ADDON_NAME
The SDK gives you access to the xbmcaddon.Addon
by default using these symbols.
provider.register(search, search_movie, search_episode, search_season)
Registers your search methods to Quasar. They can be either methods, or None
.
search (func or None)
the generic search functionsearch_movie (func or None)
the search function for moviessearch_episode (func or None)
the search function for episodessearch_season (func or None)
the search function for seasons
provider.HEAD(url, params={}, headers={}, data=None, with_cookies=False)
provider.GET(url, params={}, headers={}, data=None, with_cookies=False)
provider.POST(url, params={}, headers={}, data=None, with_cookies=False)
provider.PUT(url, params={}, headers={}, data=None, with_cookies=False)
provider.DELETE(url, params={}, headers={}, data=None, with_cookies=False)
Performs a HTTP HEAD
/GET
/POST
/PUT
/DELETE
request. Note that these functions already provide gzip
decoding and User-Agent
spoofing.
url (string)
the url to send the request toparams (dict)
the url query parameters that would go after?
headers (dict)
custom headers to send with the requestdata (string)
adds a body payload (and turns the request to aPOST
by default)with_cookies (bool)
if you want to enable cookies support, set this toTrue
, cookies can later be accessed withprovider.COOKIE_JAR
Returns a standard urllib2.Reponse
with 2 added methods:
json()
parses the body as json, returnsdict
xml()
parses the body as XML, returnsxml.etree.ElementTree.Element
provider.extract_magnets(data)
Extracts magnet links from a string
, using regular expression.
Returns a list
of torrent dict
.
provider.parse_rss(root)
Parses a RSS DOM.
root (xml.etree.ElementTree.Element)
root node to the RSS stream
Returns a list
of torrent dict
.
urllib.quote(string[, safe])
urllib.quote_plus(string[, safe])
urllib.urlencode(query[, doseq])
These are the standard urllib
methods provided here for conveniency (and maybe later lazy loading).
provider.notify(message='', header=None, time=5000, image='')
Sends a XBMC notification.
message (string)
the message to displayheader (string, optional)
the message title, it will default to your addon nametime (int, optional)
how long to display the notification in millisecondsimage (string, optional)
the associated icon to display
provider.append_headers(uri, headers)
Appends headers after a uri
for Quasar to use when downloading non magnets, if needed.
uri (string)
the uriheaders (dict)
custom headers
Returns a string
containing the modified uri
.
The provider SDK provides logging capabilities. Just use the provide.log
which is a standard python logging.Logger
object.
Note that if message
is not a string
, it will be sent to repr()
.
provider.log.debug(message)
provider.log.info(message)
provider.log.warning(message)
provider.log.error(message)
provider.log.critical(message)
Quasar expects provider to return a list
of dict
s with the following keys:
{
"name": "string", // Name of the torrent
"uri": "string", // URI
"info_hash": "string", // Torrent hash
"trackers": ["string", "..."], // List of trackers
"size": "string", // Reported size of the torrent
"provider": "string", // Name of this provider
"icon": "string", // Icon path for this provider
"seeds": int,
"peers": int,
"resolution": int,
"video_codec": int,
"audio_codec": int,
"rip_type": int,
"scene_rating": int,
"language": "string (ISO 639-1)"
}
Quasar needs to now about uniqueness. This is why Quasar needs to know about the info_hash
. Quasar has several options to know it:
- you provide it yourself by setting
info_hash
- you set
uri
to a magnet link - Quasar will download the
.torrent
file and figure it out itself
Keep in mind the 3rd options is potentially costly if there are lots of results (although it is not counted in the provider timeout). This step is called resolving.
If your file needs custom headers to be resolved, you can add headers (cookies etc...) to the URI a-la XBMC, like so:
http://foo.bar/myfile.torrent|User-Agent=I can have spaces|Cookies=ABCD;
Or even better, use provider.append_headers
:
myfile["uri"] = provider.append_headers(myfile["uri"], {
"User-Agent": "I can have spaces",
"Cookies": "ABCD;",
})
Finally, there is no use to send more than a page worth of links to Quasar, as they are supposed to be relevant anyway.
When deciding which stream to choose, Quasar tries to be smart and make a balance between quality and availability. For that reason it is crucial that you properly set the quality settings in your object if you have them (resolution
, video_codec
, audio_codec
, rip_type
and scene_rating
). See provider.py
for the possible values.
If you don't set them, Quasar will try to guess them from the name
.
Quasar tries to give you the most it can for your provider to make an informed decision when giving back streams.
If possible, if changes are made to the payloads, we will add keys, not remove them, to ensure backward compatibility. This might not be possible, but that's the goal anyway.
All the titles sent in payloads are normalized (accents, special characters, punctuation are removed, lowercase...).
Here is a sample movie payload
{
"imdb_id": "tt1254207",
"title": "big buck bunny",
"year": 2008,
"titles": {
"es": "el gran conejo",
"nl": "peach open movie project",
"ru": "большои кролик",
"us": "big buck bunny short 2008"
}
}
Note that an IMDB id is the best way to search for a movie. If you can't use that, a title + year is a good differentiator, too.
Quasar will also give you international titles for the movie you're searching. Note that these are countries and not languages (ISO 3166-1).
Here is a sample episode payload
{
"imdb_id": "tt0092400",
"tvdb_id": "76385",
"title": "married with children",
"season": 1,
"episode": 1,
"titles": null
}
Hopefully you have everything you need to know to write good providers.