Welcome to Burst’s documentation!¶
A burst of providers.
Features¶
- Fast, very fast
- No extra add-ons to install, all providers are included
- No extra service running in the background
- Easy settings to enable or disable providers and filters
- First-class support with Quasar, and only Quasar (don’t even ask)
- Simple definitions-based architecture with overrides
- Clean, PEP8 compliant code
Installation¶
Get the latest release from https://burst.surge.sh and Install from zip within Kodi, or install the add-on from the Quasar Repository if you already have Quasar installed.
Topics¶
Using filters¶
If you go in the add-on’s Advanced settings, you will notice an option named
Additional keyword filters (comma separated)
. Enabling this option will
bring up three sub-settings: Accept
, Block
and Require
. They all
expect the same kind of parameters, which is a comma-separated list of keywords
to respectively either accept, block or require. Although it’s mostly
self-explanatory, let’s go over each of them to fully understand how they
behave, and what kind of results you mind expect when using those settings.
Format¶
A comma-separated list is a standard way of defining multiple values. You can
include spaces between keywords for readability, and Burst will work just the
same. For example, those two settings will be equivalent: HEVC,H265
vs
HEVC, H265
. They will both be understood as a list with the values
["HEVC", "H265"]
. Also note that uppercase or lowercase makes no
difference, so both hevc
and HeVc
in a result name would also be
considered a match.
The only special trick about the format of keywords is done by using
underscores (_
), which tell Burst to make sure there is a space, dot, dash,
also an underscore, or other separator between your keyword and the other parts
of the result’s name. For example, if you want to match ITA
, but not
italian
, you would use _ITA_
as your keyword, which would match names
like A.Movie.2017.ITA.720p
but not A.Movie.2017.Italian.720p
. A
trailing underscore would also return a match, ie. A.Movie.720p.ITA
.
Note that the `Require` keyword treats underscores literally, so using
_ITA_
in Require would only match names like A.Movie_ITA_720p
.
Keyword types¶
Accept¶
The Accept setting will return results that include any of the keywords
you specify. For example, Italian, French
will return results that either
include italian
or french
.
Block¶
The Block setting will block results that include any of the keywords
you specify, and can be the most dangerous filter to use. For example, ITA
would block every result that has ita
anywhere in its name, regardless of
delimiters like dots and dashes, so if you’re looking for a movie named
My Inheritance, you would get absolutely no result. For that reason, you
should usually always add underscores around Block keywords to make sure
there are delimiters around those keywords.
Require¶
The Require setting is also a dangerous filter to use, and will require
all the keywords you specify to be included in the result names. For
example, if you specify ITA, _FR_
, you would only get results that include
both ITA
and FR
(with delimiters), which will be very few if any.
It can however be a very useful setting to get only results that include your
preferred language.
Using overrides¶
Definitions are loaded from burst/providers/definitions.py starting with all the default providers in the providers.json file. You can override existing definitions using either an overrides.py or overrides.json file.
Using a Python file is deprecated but will remain supported.
Start by adding a new file named overrides.json in your userdata folder, ie. in ~/.kodi/userdata/addon_data/script.quasar.burst/overrides.json and either paste the content of an existing provider or start with small overrides:
{
'torlock': {
'name': 'MyTorLock'
}
}
If you are using the older Python format, put all your overrides in the overrides variable within that file, as such:
overrides = {
'torlock': {
'name': 'MyTorLock'
}
}
Adding providers¶
Adding a custom provider is similar to using overrides, but using a JSON file for each of your providers, unless you add them all in your custom overrides.json file, which also works.
To add a provider, simply create a file with the .json
extension under the
providers
folder in your userdata folder, ie. as
~/.kodi/userdata/addon_data/script.quasar.burst/providers/nice_provider.json
,
and make sure it follows the format below (hopefully with
"subpage": false
):
{
"1337x": {
"name": "1337x",
"enabled": true,
"private": false,
"languages": "en",
"anime_extra": "",
"anime_keywords": "{title:original} {episode}",
"anime_query": "EXTRA",
"base_url": "https://www.1337x.to/search/QUERY/1/",
"color": "FFF14E13",
"general_extra": "",
"general_keywords": "{title:original}",
"general_query": "EXTRA",
"language": null,
"login_failed": "",
"login_object": "",
"login_path": null,
"movie_extra": "",
"movie_keywords": "{title:original} {year}",
"movie_query": "EXTRA",
"parser": {
"infohash": "",
"name": "item('a', order=2)",
"peers": "item(tag='td', order=3)",
"row": "find_once(tag='tbody').find_all('tr')",
"seeds": "item(tag='td', order=2)",
"size": "item(tag='td', order=5)",
"torrent": "'https://www.1337x.to%s' % item(tag='a', attribute='href', order=2)"
},
"season_extra": "",
"season_extra2": "",
"season_keywords": "{title:original} s{season:2}",
"season_keywords2": "",
"season_query": "EXTRA",
"separator": "+",
"show_query": "",
"subpage": true,
"tv_extra": "",
"tv_extra2": "",
"tv_keywords": "{title:original} s{season:2}e{episode:2}",
"tv_keywords2": ""
}
}
Provider fields¶
name¶
The provider’s name as displayed to the user, typically with color.
color¶
The color of the provider name using Kodi’s ARGB (alpha-red-green-blue) color format.
base_url¶
The base_url
is the part of the provider’s URL that is always found in
your browser bar when you visit or more importantly, search the site. It may or
may not contain the QUERY
part (more on that later); it really only depends
on the common part of the different search queries.
language¶
Forces a language preference for translations if they’re available, eg. es
private¶
Boolean flag to mark this provider as private, see PrivateProviders.
separator¶
Space separator used in URL queries by this provider, typically %20
for an
encoded white-space or +
subpage¶
The most expensive boolean flag, to be avoided as much as possible. This tells
Burst that we have no choice but to open each and every link to get to the
torrent or magnet link. As it stands, we also waste the torrent
(more on
that later) definition under parser
, which becomes the link to follow, and
the page at that link gets automatically processed to find a magnet or torrent
link in it.
*_query¶
Second part of the URL after base_url
which will contain the QUERY
keyword if it’s not already in the base_url
. This typically include
category parameters specific to each provider, ie. /movies/QUERY
*_extra¶
The most confusing part of queries. Those will contain extra parameters,
typically categories also, replacing the EXTRA
keyword often found in the
respective *_query
definition, and often simply for the convenience of
shorter *_query
definitions. Note that this is mostly always just an empty
string and not being used.
*_keywords¶
Keyword definitions for the different search types, with special placeholders
like {title}
for a movie or TV show title.
List of keyword types¶
{title}
Movie or TV show title{year}
Release date, typically for movies only{season}
Season number. Using{season:2}
pads to 2 characters with leading zeros, eg.s{season:2}
would becomes01
for an episode of season 1.{episode}
Episode number, same formatting as{season}
with regards to padding, ie.{episode:2}
. Typically used with season as such:s{season:2}e{episode:2}
parser¶
This is the most important part of every provider, and tells Burst how to
find torrents within search result pages. The first parser definition to be used
is the row
, and is also the “parent” to all to the others. It most usually
ends with a find_all('tr')
, and tells Burst which HTML tags, typically table
rows, hold the results we’re interested in. All other parser definitions will
then look within each row for their respective information. Each other
parser definition tells Burst what HTML tag has its information, for example
item(tag='td', order=1)
for name
tells Burst that the torrent name is
in the first table column of each row.
TODO: A more detailed description of parser fields and a tutorial on how to actually create providers will soon be added.
Private providers¶
login_path¶
The login_path
is the part of the URL used for logging in, typically
something like "/login.php"
. This can be found by inspecting the login
form’s HTML and taking its action
attribute.
login_object¶
The login_object
represents the form elements sent to the login_path
.
For built-in private providers, placeholders are used to replace setting values
for the username and password (USERNAME
and PASSWORD
respectively).
Custom providers cannot define new settings, and must therefore put the username
and password in the login_object
directly.
login_failed¶
String that must not be included in the response’s content. If this string is present in the page when trying to login, it returns as having failed and no search queries will be sent.
Providers by media type¶
Using overrides, you can enable or disable providers depending on the type of media they contain. A type field can be set for this.
If a provider should be used for all media types, simply do not set its type field, which is the default behavior.
- Available types:
- movies
- shows as alias for both - episodes - seasons
- anime
{
'torlock': {
'type': 'movies'
}
}
If you are using the older Python format:
overrides = {
'torlock': {
'type': 'movies'
}
}
burst package¶
Subpackages¶
burst.parser package¶
Submodules¶
burst.parser.HTMLParser module¶
A parser for HTML and XHTML.
-
exception
burst.parser.HTMLParser.
HTMLParseError
(msg, position=(None, None))[source]¶ Bases:
exceptions.Exception
Exception raised for all parse errors.
-
class
burst.parser.HTMLParser.
HTMLParser
[source]¶ Bases:
burst.parser.markupbase.ParserBase
Find tags and other markup and call handler functions.
- Usage:
- p = HTMLParser() p.feed(data) … p.close()
Start tags are handled by calling self.handle_starttag() or self.handle_startendtag(); end tags by self.handle_endtag(). The data between tags is passed from the parser to the derived class by calling self.handle_data() with the data as argument (the data may be split up in arbitrary chunks). Entity references are passed by calling self.handle_entityref() with the entity reference as the argument. Numeric character references are passed to self.handle_charref() with the string containing the reference as the argument.
-
CDATA_CONTENT_ELEMENTS
= ('script', 'style')¶
-
feed
(data)[source]¶ Feed data to the parser.
Call this as often as you want, with as little or as much text as you want (may include ‘n’).
-
entitydefs
= None¶
burst.parser.ehp module¶
” All the credit of this code to Iury de oliveira gomes figueiredo Easy Html Parser is an AST generator for html/xml documents. You can easily delete/insert/extract tags in html/xml documents as well as look for patterns. https://github.com/iogf/ehp
-
class
burst.parser.ehp.
Attribute
[source]¶ Bases:
dict
This class holds the tags’s attributes. The idea consists in providing an efficient and flexible way of manipulating tags attributes inside the dom.
Example: dom = Html().feed(‘<p style=”color:green”> foo </p>’)
for ind in dom.sail(): if ind.name == ‘p’: ind.attr[‘style’] = “color:blue”
It would change to color blue.
-
class
burst.parser.ehp.
Root
(name=None, attr=None)[source]¶ Bases:
list
A Root instance is the outmost node for a xml/html document. All xml/html entities inherit from this class.
html = Html() dom = html.feed(‘<html> … </body>’)
dom.name == ‘’ True type(dom) == Root True
-
sail
()[source]¶ This is used to navigate through the xml/html document. Every xml/html object is represented by a python class instance that inherits from Root.
The method sail is used to return an iterator for these objects.
Example: data = ‘<a> <b> </b> </a>’
html = Html() dom = html.feed(data)
for ind in dom.sail(): print type(ind),’,’, ind.name
It would output.
<class ‘ehp.Root’> , a <class ‘ehp.Root’> , b
-
index
(item, **kwargs)[source]¶ This is similar to index but uses id to check for equality.
Example:
data = ‘<a><b></b><b></b></a>’ html = Html() dom = html.feed(data)
for root, ind in dom.sail_with_root(): print root.name, ind.name, root.index(ind)
It would print.
a b 0 a b 1 a 0
The line where it appears ‘ a 0’ corresponds to the outmost object. The outmost object is an instance of Root that contains all the other objects. :param item:
-
remove
(item)[source]¶ This is as list.remove but works with id.
data = ‘<a><b></b><b></b></a>’ html = Html() dom = html.feed(data) for root, ind in dom.sail_with_root(): if ind.name == ‘b’: root.remove(ind)
print dom
It should print.
<a ></a>
-
find
(name='', every=1, start=1, *args)[source]¶ It is used to find all objects that match name.
Example 1:
data = ‘<a><b></b><b></b></a>’ html = Html() dom = html.feed(data)
for ind in dom.find(‘b’): print ind
It should print.
<b ></b> <b ></b>
Example 2.
data = ‘<body> <p> alpha. </p> <p style=”color:green”> beta.</p> </body>’ html = Html() dom = html.feed(data)
for ind in dom.find(‘p’, (‘style’, ‘color:green’)): print ind
Or
for ind in dom.find(‘p’, (‘style’, [‘color:green’, ‘color:red’])): print ind
Output.
<p style=”color:green” > beta.</p>
-
find_once
(tag=None, select=None, order=1)[source]¶ ” It returns the nth (order) ocurrence from the tag matching with the attributes from select
-
find_all
(tag=None, select=None, every=1, start=1)[source]¶ ” It returns all ocurrences from the tag matching with the attributes from select
-
find_with_root
(name, *args)[source]¶ Like Root.find but returns its parent tag.
from ehp import *
html = Html() dom = html.feed(‘’‘<body> <p> alpha </p> <p> beta </p> </body>’‘’)
for root, ind in dom.find_with_root(‘p’): root.remove(ind)
print dom
It would output.
<body > </body>
-
by_id
(id_value)[source]¶ It is a shortcut for finding an object whose attribute ‘id’ matches id.
Example:
data = ‘<a><b id=”foo”></b></a>’ html = Html() dom = html.feed(data)
print dom.byid(‘foo’) print dom.byid(‘bar’)
It should print.
<b id=”foo” ></b> None
-
take
(*args)[source]¶ It returns the first object whose one of its attributes matches (key0, value0), (key1, value1), … .
Example:
data = ‘<a><b id=”foo” size=”1”></b></a>’ html = Html() dom = html.feed(data)
print dom.take((‘id’, ‘foo’)) print dom.take((‘id’, ‘foo’), (‘size’, ‘2’))
-
match
(*args)[source]¶ It returns a sequence of objects whose attributes match. (key0, value0), (key1, value1), … .
Example:
data = ‘<a size=”1”><b size=”1”></b></a>’ html = Html() dom = html.feed(data)
for ind in dom.match((‘size’, ‘1’)): print ind
It would print.
<b size=”1” ></b> <a size=”1” ><b size=”1” ></b></a>
-
match_with_root
(*args)[source]¶ Like Root.match but with its parent tag.
Example:
from ehp import *
html = Html() dom = html.feed(‘’‘<body> <p style=”color:black”> xxx </p> <p style = “color:black”> mmm </p></body>’‘’)
for root, ind in dom.match_with_root((‘style’, ‘color:black’)): del ind.attr[‘style’]
item = dom.fst(‘body’) item.attr[‘style’] = ‘color:black’
print dom
Output.
<body style=”color:black” > <p > xxx </p> <p > mmm </p></body>
-
join
(delim, *args)[source]¶ It joins all the objects whose name appears in args.
Example 1:
html = Html() data = ‘<a><b> This is cool. </b><b> That is. </b></a>’ dom = html.feed(data)
print dom.join(‘’, ‘b’) print type(dom.join(‘b’))
It would print.
<b > This is cool. </b><b > That is. </b> <type ‘str’>
Example 2:
html = Html() data = ‘<a><b> alpha</b><c>beta</c> <b>gamma</a>’ dom = html.feed(data)
print dom.join(‘’, ‘b’, ‘c’)
It would print.
<b > alpha</b><c >beta</c><b >gamma</b>
Example 3:
html = Html() data = ‘<a><b>alpha</b><c>beta</c><b>gamma</a>’ dom = html.feed(data)
print dom.join(‘n’, DATA)
It would print.
alpha beta gamma
-
fst
(name, *args)[source]¶ It returns the first object whose name matches.
Example 1:
html = Html() data = ‘<body> <em> Cool. </em></body>’ dom = html.feed(data)
print dom.fst(‘em’)
It outputs.
<em > Cool. </em>
Example 2:
data = ‘<body> <p> alpha. </p> <p style=”color:green”> beta.</p> </body>’ html = Html() dom = html.feed(data)
for ind in dom.find(‘p’, (‘style’, ‘color:green’)): print ind
print dom.fst(‘p’, (‘style’, ‘color:green’)) print dom.fst_with_root(‘p’, (‘style’, ‘color:green’))
Output:
<p style=”color:green” > beta.</p> <p style=”color:green” > beta.</p> (<ehp.Tag object at 0xb7216c0c>, <ehp.Tag object at 0xb7216d24>)
-
fst_with_root
(name, *args)[source]¶ Like fst but returns its item parent.
Example:
html = Html() data = ‘<body> <em> Cool. </em></body>’ dom = html.feed(data)
root, item dom.fst_with_root(‘em’) root.insert_after(item, Tag(‘p’)) print root
It outputs.
<body > <em > Cool. </em><p ></p></body>
For another similar example, see help(Root.fst)
-
text
()[source]¶ It returns all objects whose name matches DATA. It basically returns a string corresponding to all asci characters that are inside a xml/html tag.
Example:
html = Html() data = ‘<body><em>This is all the text.</em></body>’ dom = html.feed(data)
print dom.fst(‘em’).text()
It outputs.
This is all the text.
Notice that if you call text() on an item with children then it returns all the printable characters for that node.
-
sail_with_root
()[source]¶ This one works like sail(), however it yields the tag’s parents as well as the child tag.
For an example, see help(Root.remove).
-
walk
()[source]¶ Like sail but carries name and attr.
Example:
html = Html() data = ‘<body> <em> This is all the text.</em></body>’ dom = html.feed(data)
for ind, name, attr in dom.walk(): print ‘TAG:’, ind print ‘NAME:’, name print ‘ATTR:’, attr
It should print.
TAG: NAME: 1 ATTR: TAG: This is all the text. NAME: 1 ATTR: TAG: <em > This is all the text.</em> NAME: em ATTR: TAG: <body > <em > This is all the text.</em></body> NAME: body ATTR:
-
walk_with_root
()[source]¶ Like walk but carries root.
Example:
html = Html() data = ‘<body><em>alpha</em></body>’ dom = html.feed(data)
for (root, name, attr), (ind, name, attr) in dom.walk_with_root(): print root, name, ind, name
Output:
<em >alpha</em> 1 alpha 1 <body ><em >alpha</em></body> em <em >alpha</em> em <body ><em >alpha</em></body> body <body ><em >alpha</em></body> body
-
-
class
burst.parser.ehp.
Tag
(name, attr=None)[source]¶ Bases:
burst.parser.ehp.Root
This class’s instances represent xml/html tags under the form: <name key=”value” …> … </name>.
It holds useful methods for parsing xml/html documents.
-
class
burst.parser.ehp.
Data
(data)[source]¶ Bases:
burst.parser.ehp.Root
The pythonic representation of data that is inside xml/html documents.
All data that is not a xml/html token is represented by this class in the structure of the document.
Example:
html = Html() data = ‘<body><em>alpha</em></body>’ dom = html.feed(data)
x = dom.fst(‘em’)
# x holds a Data instance.
type(x[0]) print x[0]
Output:
<class ‘ehp.Data’> alpha
The Data instances are everywhere in the document, when the tokenizer finds them between the xml/html tags it builds up the structure identically to the document.
-
text
()[source]¶ It returns all objects whose name matches DATA. It basically returns a string corresponding to all asci characters that are inside a xml/html tag.
Example:
html = Html() data = ‘<body><em>This is all the text.</em></body>’ dom = html.feed(data)
print dom.fst(‘em’).text()
It outputs.
This is all the text.
Notice that if you call text() on an item with children then it returns all the printable characters for that node.
-
-
class
burst.parser.ehp.
XTag
(name, attr=None)[source]¶ Bases:
burst.parser.ehp.Root
This tag is the representation of html’s tags in XHTML style like <img src=”t.gif” /> It is tags which do not have children.
-
class
burst.parser.ehp.
Meta
(data)[source]¶ Bases:
burst.parser.ehp.Root
-
class
burst.parser.ehp.
Code
(data)[source]¶ Bases:
burst.parser.ehp.Root
-
class
burst.parser.ehp.
Amp
(data)[source]¶ Bases:
burst.parser.ehp.Root
-
class
burst.parser.ehp.
Pi
(data)[source]¶ Bases:
burst.parser.ehp.Root
-
class
burst.parser.ehp.
Comment
(data)[source]¶ Bases:
burst.parser.ehp.Root
-
class
burst.parser.ehp.
Tree
[source]¶ Bases:
object
The engine class.
-
class
burst.parser.ehp.
Html
[source]¶ Bases:
burst.parser.HTMLParser.HTMLParser
The tokenizer class.
burst.parser.markupbase module¶
Shared support for scanning document type declarations in HTML and XHTML.
This module is used as a foundation for the HTMLParser and sgmllib modules (indirectly, for htmllib as well). It has no documented public API and should not be used directly.
Submodules¶
burst.burst module¶
burst.client module¶
burst.filtering module¶
burst.ordereddict module¶
-
class
burst.ordereddict.
OrderedDict
(*args, **kwds)[source]¶ Bases:
dict
,UserDict.DictMixin
Backport of
collections.OrderedDict
for Python 2.6 (Kodi 16)-
popitem
() → (k, v), remove and return some (key, value) pair as a[source]¶ 2-tuple; but raise KeyError if D is empty.
-
setdefault
(k[, d]) → D.get(k,d), also set D[k]=d if k not in D¶
-
update
([E, ]**F) → None. Update D from dict/iterable E and F.¶ If E present and has a .keys() method, does: for k in E: D[k] = E[k] If E present and lacks .keys() method, does: for (k, v) in E: D[k] = v In either case, this is followed by: for k in F: D[k] = F[k]
-
pop
(k[, d]) → v, remove specified key and return the corresponding value.¶ If key is not found, d is returned if given, otherwise KeyError is raised
-
values
() → list of D's values¶
-
items
() → list of D's (key, value) pairs, as 2-tuples¶
-
iterkeys
() → an iterator over the keys of D¶
-
itervalues
() → an iterator over the values of D¶
-
iteritems
() → an iterator over the (key, value) items of D¶
-
burst.provider module¶
burst.utils module¶
Credits¶
- @elgatito for all the updates with Elementum
- @mancuniancol for all his work on Magnetic, this add-on wouldn’t have been possible without him.
- All the alpha and beta testers that led to the first stable release.