├── .coveragerc ├── .gitignore ├── .gitmodules ├── .landscape.yml ├── .travis.yml ├── AUTHORS ├── CHANGES ├── CONTRIBUTING ├── LICENSE ├── MANIFEST.in ├── README.md ├── codecov.yml ├── docs ├── Makefile ├── api.rst ├── caching.rst ├── commandline.rst ├── conf.py ├── index.rst ├── installation.rst ├── item.rst ├── make.bat ├── patterns.rst ├── poweredby.rst ├── quickstart.rst ├── routing.rst ├── tutorial.rst └── upgrading.rst ├── fabfile.py ├── kodiswift ├── __init__.py ├── actions.py ├── cli │ ├── __init__.py │ ├── app.py │ ├── cli.py │ ├── console.py │ ├── create.py │ └── data │ │ ├── addon.py │ │ ├── addon.xml │ │ └── resources │ │ ├── __init__.py │ │ ├── language │ │ └── English │ │ │ └── strings.po │ │ └── lib │ │ └── __init__.py ├── common.py ├── constants.py ├── listitem.py ├── logger.py ├── mockxbmc │ ├── __init__.py │ ├── polib.py │ ├── utils.py │ ├── xbmc.py │ ├── xbmcaddon.py │ ├── xbmcgui.py │ ├── xbmcplugin.py │ └── xbmcvfs.py ├── module.py ├── plugin.py ├── request.py ├── storage.py ├── urls.py └── xbmcmixin.py ├── setup.py └── tests ├── __init__.py ├── cli ├── __init__.py ├── test_app.py ├── test_cli.py ├── test_console.py └── test_create.py ├── data ├── plugin │ ├── addon.xml │ └── resources │ │ └── language │ │ └── English │ │ └── strings.po └── plugin_no_strings_po │ ├── addon.xml │ └── resources │ └── language │ └── English │ └── strings.xml ├── test_actions.py ├── test_common.py ├── test_constants.py ├── test_listitem.py ├── test_module.py ├── test_plugin.py ├── test_request.py ├── test_storage.py ├── test_urls.py ├── test_xbmcmixin.py └── utils.py /.coveragerc: -------------------------------------------------------------------------------- 1 | [run] 2 | omit = 3 | fabfile.py 4 | setup.py 5 | tests/**/*.py 6 | tests/*.py 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | load-dev-env.sh 2 | *.pyo 3 | *.pyc 4 | *.swp 5 | *.swo 6 | dist/ 7 | build/ 8 | docs/_build/ 9 | TODO 10 | .idea 11 | .coverage 12 | .cache 13 | kodiswift.egg-info/ 14 | tests/__pycache__/ 15 | tests/cli/__pycache__/ 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/docs/_themes"] 2 | path = docs/_themes 3 | url = https://github.com/mitsuhiko/flask-sphinx-themes.git 4 | -------------------------------------------------------------------------------- /.landscape.yml: -------------------------------------------------------------------------------- 1 | doc-warnings: no 2 | test-warnings: no 3 | strictness: veryhigh 4 | autodetect: yes 5 | ignore-paths: 6 | - docs 7 | ignore-patterns: 8 | - (^|/)docs(/|$) 9 | - setup\.py 10 | - fabfile\.py 11 | - polib\.py 12 | - _compat\.py 13 | python-targets: 14 | - 2 15 | pyflakes: 16 | disable: 17 | - F401 18 | pylint: 19 | disable: 20 | - too-few-public-methods 21 | - too-many-instance-attributes 22 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | # Config file for automatic testing at travis-ci.org 2 | language: python 3 | 4 | python: 5 | - "2.7" 6 | 7 | before_install: 8 | - pip install codecov pytest-cov 9 | 10 | # command to install dependencies, e.g. pip install -r requirements.txt --use-mirrors 11 | install: 12 | - pip install --use-mirrors mock nose 13 | 14 | # command to run tests, e.g. python setup.py test 15 | script: 16 | - py.test --cov=./ 17 | 18 | after_success: 19 | - codecov 20 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | kodiswift is a fork of xbmcswift2 which was written and maintained by 2 | Jonathan Beluch and various contributors. The current project is being 3 | developed and maintained by Aaron Frase: 4 | 5 | Development Lead 6 | ```````````````` 7 | 8 | - Aaron Frase 9 | - Jonathan Beluch 10 | 11 | Patches and Suggestions 12 | ``````````````````````` 13 | 14 | - Vladimir Kravets (@vkravets) 15 | - Tristan Fischer (sphere@dersphere.de) 16 | - beenje 17 | - takoi 18 | - cancan101 19 | - ulion 20 | - moedje 21 | - jindaxia 22 | - PanderMusubi 23 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 0.0.8 2 | ===== 3 | - Set `listitem.is_folder` to `False` when setting `listitem.is_playable` to `True`. 4 | 5 | 0.0.7 6 | ===== 7 | 8 | - Made `listitem.playable` use it's own property to allow `is_folder` and `playable` to be independent 9 | 10 | 0.0.6 11 | ===== 12 | 13 | - Make sure list item has 'as_tuple' method 14 | 15 | 0.0.5 16 | ===== 17 | 18 | - Add xbmcvfs mock 19 | - Added listdir to xbmcvfs 20 | - Exclude tests from distribute package 21 | - Fix issue when path sets as icon for listitem object 22 | - Add test for plugin.set_resolved_url() 23 | - Add check of played 24 | - set_resolved_url test check playable 25 | - Improve mock of xbmc, to use xbmc libraries addons in python path 26 | - Fixed failing TestResolvedUrl test 27 | 28 | 0.0.4 29 | ===== 30 | 31 | - Merge pull request #6 More robust test before manipulation of item 32 | - Merge pull request #8 Fix notify 33 | 34 | 0.0.3 35 | ===== 36 | 37 | - Merge pull request #5 fix storage error on Windows 38 | 39 | 0.0.2 40 | ===== 41 | 42 | - Merge pull request #3 fix set_setting 43 | 44 | 0.0.1 45 | ===== 46 | 47 | - Initial fork of xbmcswift2 48 | - Code cleanup 49 | - Added art property to ListItem 50 | - Deprecated non-pythonic ListItem properties in favor of more pythonic ones 51 | - Re-wrote PersistentStorage and TimedStorage 52 | -------------------------------------------------------------------------------- /CONTRIBUTING: -------------------------------------------------------------------------------- 1 | First of all, thanks! 2 | 3 | Here are a few guidelines to help you on your way: 4 | 5 | 1. Fork the repo. Typically patches should be based on the develop branch 6 | rather than master. Merges into master are reserved for releases. 7 | 8 | 2. Run tests from the root of the directory with `python -m unittest discover`. 9 | 10 | 3. Add a test for your change. Only refactoring and documentation changes 11 | require no new tests. If you are adding functionality or fixing a bug, we 12 | need a test! 13 | 14 | 4. Make the tests pass. 15 | 16 | 5. Push to your fork and submit a pull request. 17 | 18 | 19 | To test your changes to kodiswift within Kodi, you can use `fab 20 | local_release:eden`. This will create a local copy of Kodi specific 21 | distribution of kodiswift. You can then copy this folder into your 22 | ~/.kodi/addons folder. 23 | 24 | Syntax should follow pep8 guidelines wherever possible. 25 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include kodiswift/cli/data * 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | kodiswift 2 | ========= 3 | 4 | [![Build Status](https://travis-ci.org/afrase/kodiswift.svg?branch=master)](https://travis-ci.org/Sinap/kodiswift) 5 | [![codecov](https://codecov.io/gh/afrase/kodiswift/branch/master/graph/badge.svg)](https://codecov.io/gh/Sinap/kodiswift) 6 | [![Code Health](https://landscape.io/github/afrase/kodiswift/master/landscape.svg?style=flat)](https://landscape.io/github/Sinap/kodiswift/master) 7 | 8 | A micro framework to enable rapid development of Kodi plugins. 9 | 10 | 11 | ## Features 12 | * Run the addon from the command line *or* within Kodi without changing any 13 | code. 14 | * Helper libraries to make common Kodi API operations easy, like adding items, 15 | getting settings, creating temporary files, etc. 16 | * Handles all the url parsing involved in plugin routing. No need to deal with 17 | complicated URLs and query strings. 18 | 19 | ## Documentation 20 | 21 | TODO: Clean up documentation. 22 | 23 | ## Upgrading from xbmcswift2 24 | 25 | This project is a fork of xbmcswift2. The APIs in the current release 26 | are the same as xbmcswift2 but with added listitem properties and 27 | other enhancements. 28 | 29 | ## Contributing 30 | 31 | Bugs, patches and suggestions are all welcome. I'm working on adding tests and 32 | getting better coverage. Please ensure that your patches include tests as well 33 | as updates to the documentation. Thanks! 34 | -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | ignore: 3 | - tests/.* 4 | - kodiswift/mockxbmc/.* 5 | - fabfile.py 6 | - setup.py 7 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 14 | # the i18n builder cannot share the environment and doctrees with the others 15 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 16 | 17 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 18 | 19 | help: 20 | @echo "Please use \`make ' where is one of" 21 | @echo " html to make standalone HTML files" 22 | @echo " dirhtml to make HTML files named index.html in directories" 23 | @echo " singlehtml to make a single large HTML file" 24 | @echo " pickle to make pickle files" 25 | @echo " json to make JSON files" 26 | @echo " htmlhelp to make HTML files and a HTML help project" 27 | @echo " qthelp to make HTML files and a qthelp project" 28 | @echo " devhelp to make HTML files and a Devhelp project" 29 | @echo " epub to make an epub" 30 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 31 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 32 | @echo " text to make text files" 33 | @echo " man to make manual pages" 34 | @echo " texinfo to make Texinfo files" 35 | @echo " info to make Texinfo files and run them through makeinfo" 36 | @echo " gettext to make PO message catalogs" 37 | @echo " changes to make an overview of all changed/added/deprecated items" 38 | @echo " linkcheck to check all external links for integrity" 39 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 40 | 41 | clean: 42 | -rm -rf $(BUILDDIR)/* 43 | 44 | html: 45 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 46 | @echo 47 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 48 | 49 | dirhtml: 50 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 51 | @echo 52 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 53 | 54 | singlehtml: 55 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 56 | @echo 57 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 58 | 59 | pickle: 60 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 61 | @echo 62 | @echo "Build finished; now you can process the pickle files." 63 | 64 | json: 65 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 66 | @echo 67 | @echo "Build finished; now you can process the JSON files." 68 | 69 | htmlhelp: 70 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 71 | @echo 72 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 73 | ".hhp project file in $(BUILDDIR)/htmlhelp." 74 | 75 | qthelp: 76 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 77 | @echo 78 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 79 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 80 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/XBMCSwift.qhcp" 81 | @echo "To view the help file:" 82 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/XBMCSwift.qhc" 83 | 84 | devhelp: 85 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 86 | @echo 87 | @echo "Build finished." 88 | @echo "To view the help file:" 89 | @echo "# mkdir -p $$HOME/.local/share/devhelp/XBMCSwift" 90 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/XBMCSwift" 91 | @echo "# devhelp" 92 | 93 | epub: 94 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 95 | @echo 96 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 97 | 98 | latex: 99 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 100 | @echo 101 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 102 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 103 | "(use \`make latexpdf' here to do that automatically)." 104 | 105 | latexpdf: 106 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 107 | @echo "Running LaTeX files through pdflatex..." 108 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 109 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 110 | 111 | text: 112 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 113 | @echo 114 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 115 | 116 | man: 117 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 118 | @echo 119 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 120 | 121 | texinfo: 122 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 123 | @echo 124 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 125 | @echo "Run \`make' in that directory to run these through makeinfo" \ 126 | "(use \`make info' here to do that automatically)." 127 | 128 | info: 129 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 130 | @echo "Running Texinfo files through makeinfo..." 131 | make -C $(BUILDDIR)/texinfo info 132 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 133 | 134 | gettext: 135 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 136 | @echo 137 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 138 | 139 | changes: 140 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 141 | @echo 142 | @echo "The overview file is in $(BUILDDIR)/changes." 143 | 144 | linkcheck: 145 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 146 | @echo 147 | @echo "Link check complete; look for any errors in the above output " \ 148 | "or in $(BUILDDIR)/linkcheck/output.txt." 149 | 150 | doctest: 151 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 152 | @echo "Testing of doctests in the sources finished, look at the " \ 153 | "results in $(BUILDDIR)/doctest/output.txt." 154 | -------------------------------------------------------------------------------- /docs/api.rst: -------------------------------------------------------------------------------- 1 | .. _api: 2 | 3 | API 4 | === 5 | 6 | .. module:: kodiswift 7 | 8 | Covers every method of kodiswift 9 | 10 | Plugin Object 11 | ------------- 12 | 13 | .. autoclass:: Plugin 14 | :members: 15 | :inherited-members: 16 | 17 | 18 | ListItem 19 | -------- 20 | 21 | .. autoclass:: ListItem 22 | :members: 23 | :undoc-members: 24 | :inherited-members: 25 | 26 | Request 27 | ------- 28 | 29 | .. autoclass:: Request 30 | :members: 31 | :inherited-members: 32 | 33 | 34 | Actions 35 | ------- 36 | 37 | .. automodule:: kodiswift.actions 38 | :members: 39 | 40 | 41 | Extended API 42 | ------------ 43 | 44 | .. module:: kodiswift 45 | 46 | Module 47 | `````` 48 | 49 | .. autoclass:: Module 50 | :members: 51 | :inherited-members: 52 | 53 | 54 | TimedStorage 55 | ```````````` 56 | 57 | .. autoclass:: TimedStorage 58 | :members: 59 | :inherited-members: 60 | -------------------------------------------------------------------------------- /docs/caching.rst: -------------------------------------------------------------------------------- 1 | .. _caching: 2 | 3 | 4 | Caching and Storage 5 | =================== 6 | 7 | kodiswift offers a few options for caching and storage to help improve the 8 | user experience of your addon. swift offers a simple storage mechanism that 9 | allows you to store arbitraty python objects to use between requests. 10 | 11 | .. warning:: 12 | 13 | The current implementation of kodiswift's storage is very basic and is not 14 | thread safe. If your addon does background calls via the context menu and 15 | manipulates storages in these backgound threads, you might run into some 16 | issues. 17 | 18 | Storing Arbitraty Python Objects 19 | -------------------------------- 20 | 21 | All caches/storage objects in kodiswift act like python dictionaries. So to 22 | get a cache, simply call the ``get_storage`` method. 23 | 24 | .. sourcecode:: python 25 | 26 | people = plugin.get_storage('people') 27 | 28 | # now we can use people like a regular dict 29 | people['jon'] = 'developer' 30 | people.update({'dave': 'accountant'}) 31 | 32 | people.items() 33 | # [('jon', 'developer'), ('dave', 'accountant')] 34 | 35 | Caches are automatically persisted to disk each time an addon finishes 36 | execution. If you would like to sync the cache to disk manually, you can call 37 | ``cache.sync()`` directly. However, this is not normally necessary. 38 | 39 | 40 | File Formats 41 | ------------ 42 | 43 | By default, caches are saved to disk in the pickle format. This is convenient 44 | since it can store Python objects. However, you can also pass 'csv' or 'json' 45 | for the ``file_format`` keyword arg to the get_storage call. 46 | 47 | 48 | Expiration's 49 | ------------ 50 | 51 | Caches also offer an optional argument, ``TTL``, which is the max lifetime for 52 | objects specified in minutes. 53 | 54 | .. sourcecode:: python 55 | 56 | people = plugin.get_storage('people', TTL=24) 57 | 58 | Caching Decorator 59 | ----------------- 60 | 61 | kodiswift provides a convenient caching decorator to automatically cache the 62 | output of a function. For example, suppose we have a function ``get_api_data``, 63 | that goes out to a remote API and fetches lots of data. If the website only 64 | updates the API once a day, it doesn't make sense to make this request every 65 | time the addon is run. So we can use the caching decorator with a TTL argument. 66 | 67 | .. sourcecode:: python 68 | 69 | @plugin.cached(TTL=60*24) 70 | def get_api_data(); 71 | # make remote request 72 | data = get_remote_data() 73 | return data 74 | 75 | The default TTL is 1 day if not provided. 76 | 77 | 78 | Caching Views 79 | ------------- 80 | 81 | It's also possible to cache views (functions decorated with 82 | ``plugin.route()``). To simplify addon code, there is a special decorator 83 | called ``cached_route``. All of the arguments to cached_route are the same as 84 | the regular ``route`` decorator. Currently, it is not possible to specify a TTL 85 | for this decorator; it defaults to 24 hours. 86 | 87 | .. sourcecode:: python 88 | 89 | @plugin.cached_route('/') 90 | def main_menu(); 91 | # do stuff 92 | 93 | .. warning:: This is only currently possible for views that return lists of 94 | dictionaries. If you call plugin.finish() you *cannot* currently 95 | cache the view. See the below section 'Caveats' for more 96 | information. 97 | 98 | .. warning:: It is currently only possible to attach a single cached_route to a 99 | view. If you have multiple routes on a given view, try refactoring 100 | some logic out to a new function that can be cached, instead of 101 | using the cached_route decorator. 102 | Caveats 103 | ------- 104 | 105 | The caching features of kodiswift are still young and thus have some potential 106 | problems to be aware of. 107 | 108 | * First, if you are calling ``plugin.finish`` from a view, it is not currently 109 | possible to cache the view. This is because there are a few side effects 110 | which happen in ``finish`` which would not be cached. If this is the case, 111 | perhaps you can move some functionality in your view into a new function, and 112 | cache that result instead. 113 | 114 | * Ensure variables are part of your method signature. If you cache a given 115 | function, ensure that all possible inputs are in your method signature. 116 | kodiswift uses the arguments passed to your function as the unique key for 117 | the cache. Therefore it's possible to cache different return values for 118 | different inputs for a function. But if you check some global state from 119 | inside your function, the caching logic will have no knowlege of this and 120 | will return the *wrong* result. 121 | 122 | * Currently, caches can grow very large since they do not automatically purge 123 | themselves based on filesize. Depending on what you are caching, you might 124 | need to introduce some logic to clear the cache. 125 | 126 | .. sourcecode:: python 127 | 128 | cache = plugin.get_cache('people') 129 | cache.clear() 130 | cache.sync() 131 | 132 | * It's advisable to include caching as the final step in your development 133 | process. If you are still developing your addon, occasionally incorrect 134 | return values can be cached which will cause you headaches. 135 | -------------------------------------------------------------------------------- /docs/commandline.rst: -------------------------------------------------------------------------------- 1 | .. _commandline: 2 | 3 | 4 | Running kodiswift on the Command Line 5 | ===================================== 6 | 7 | 8 | Commands 9 | -------- 10 | 11 | When running kodiswift from the command line, there are two commands 12 | available, *create* and *run*. *create* is a script that will create the basic 13 | scaffolding and necessary files for an Kodi addon and personalize it by asking 14 | you a few questions. *run* enables you to debug your addon on the command line. 15 | 16 | To see the command line help, simply execute ``kodiswift -h``. Both of the 17 | commands are explained further below. 18 | 19 | 20 | create 21 | ~~~~~~ 22 | 23 | To create a new addon, change your current working directory to a location 24 | where you want your addon folder to be created. Then execute ``kodiswift 25 | create``. After answering a few questions, you should have the basic addon 26 | structure in place. 27 | 28 | run 29 | ~~~ 30 | 31 | When running an addon on the command line, there are three different run modes 32 | available, once_, interactive_, and crawl_. 33 | 34 | There is also a second positional argument, ``url``, which is optional. By 35 | default, kodiswift will run the root URL of your addon (a path of '/'), e.g. 36 | ``plugin://plugin.video.academicearth/``. This is the same default URL that 37 | Kodi uses when you first enter an addon. You can gather URLs from the output of 38 | kodiswift. 39 | 40 | The options ``-q`` and ``-v`` decrease and increase the logging level. 41 | 42 | .. note:: 43 | 44 | To enable running on the command line, kodiswift attempts to mock a 45 | portion of the Kodi python bindings. Certain functions behave properly like 46 | looking up strings. However, if a function has not been implemented, 47 | kodiswift lets the function call pass silently to avoid exceptions and 48 | allow the plugin to run in a limited fashion. This is why you'll often see 49 | WARNING log messages when running on the command line. 50 | 51 | If you plan on using the command line to develop your addons, you should 52 | always import the xbmc modules from kodiswift:: 53 | 54 | from kodiswift import xbmcgui 55 | 56 | kodiswift will correctly import the proper module based on the 57 | environment. When running in Kodi, it will import the actual modules, and 58 | when running on the command line it will import mocked modules without 59 | error. 60 | 61 | 62 | once 63 | ____ 64 | 65 | Executes the addon once then quits. Useful for testing when used 66 | with the optional ``url`` argument.:: 67 | 68 | $ kodiswift run once # you can omit the once argument as it is the default 69 | 70 | ------------------------------------------------------------ 71 | # Label Path 72 | ------------------------------------------------------------ 73 | [0] Subjects (plugin://plugin.video.academicearth/subjects/) 74 | ------------------------------------------------------------ 75 | 76 | 77 | $ kodiswift run once plugin://plugin.video.academicearth/subjects/ 78 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 79 | # Label Path 80 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 81 | [ 0] ACT (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Fact/) 82 | [ 1] Accounting (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Faccounting/) 83 | [ 2] Algebra (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Falgebra/) 84 | [ 3] Anthropology (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Fanthropology/) 85 | [ 4] Applied CompSci (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Fapplied-computer-science/) 86 | ... 87 | 88 | 89 | interactive 90 | ___________ 91 | 92 | Allows the user to step through their addon using an interactive session. This 93 | is meant to mimic the basic Kodi interface of clicking on a listitem, which 94 | then brings up a new directory listing. After each listing is displayed the 95 | user will be prompted for a listitem to select. There will always be a ``..`` 96 | option to return to the previous directory (except for the initial URL).:: 97 | 98 | $ kodiswift run interactive 99 | ------------------------------------------------------------ 100 | # Label Path 101 | ------------------------------------------------------------ 102 | [0] Subjects (plugin://plugin.video.academicearth/subjects/) 103 | ------------------------------------------------------------ 104 | Choose an item or "q" to quit: 0 105 | 106 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 107 | # Label Path 108 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 109 | [ 0] .. (plugin://plugin.video.academicearth/) 110 | [ 1] ACT (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Fact/) 111 | [ 2] Accounting (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Faccounting/) 112 | [ 3] Algebra (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Falgebra/) 113 | [ 4] Anthropology (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Fanthropology/) 114 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 115 | Choose an item or "q" to quit: 1 116 | 117 | ----------------------------------------------------------------------------------------------------------------------------------------------- 118 | # Label Path 119 | ----------------------------------------------------------------------------------------------------------------------------------------------- 120 | [0] .. (plugin://plugin.video.academicearth/subjects/) 121 | [1] ACT - Science Test Prep (plugin://plugin.video.academicearth/courses/http%3A%2F%2Fwww.academicearth.org%2Fcourses%2Fact-science-test-prep/) 122 | ----------------------------------------------------------------------------------------------------------------------------------------------- 123 | 124 | 125 | crawl 126 | _____ 127 | 128 | Used to crawl every available path in your addon. In between each request the 129 | user will be prompted to hit Enter to continue.:: 130 | 131 | $ kodiswift run crawl 2>/dev/null 132 | ------------------------------------------------------------ 133 | # Label Path 134 | ------------------------------------------------------------ 135 | [0] Subjects (plugin://plugin.video.academicearth/subjects/) 136 | ------------------------------------------------------------ 137 | Enter to continue or "q" to quit 138 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 139 | # Label Path 140 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 141 | [ 0] ACT (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Fact/) 142 | [ 1] Accounting (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Faccounting/) 143 | [ 2] Algebra (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Falgebra/) 144 | [ 3] Anthropology (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Fanthropology/) 145 | [ 4] Applied CompSci (plugin://plugin.video.academicearth/subjects/http%3A%2F%2Fwww.academicearth.org%2Fsubjects%2Fapplied-computer-science/) 146 | ---------------------------------------------------------------------------------------------------------------------------------------------------------- 147 | Enter to continue or "q" to quit 148 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 149 | # Label Path 150 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 151 | [ 0] A Cultural and Scientific Survey of the Eye and Vision (plugin://plugin.video.academicearth/courses/http%3A%2F%2Fwww.academicearth.org%2Fcourses%2Fa-cultural-and-scientific-survey-of-the-eye-and-vision/) 152 | [ 1] Autism and Related Disorders (plugin://plugin.video.academicearth/courses/http%3A%2F%2Fwww.academicearth.org%2Fcourses%2Fautism-and-related-disorders/) 153 | [ 2] Biology (plugin://plugin.video.academicearth/courses/http%3A%2F%2Fwww.academicearth.org%2Fcourses%2Fbiology/) 154 | [ 3] Core Science - Biochemistry I (plugin://plugin.video.academicearth/courses/http%3A%2F%2Fwww.academicearth.org%2Fcourses%2Fcore-science---biochemistry-i/) 155 | [ 4] Darwin's Legacy (plugin://plugin.video.academicearth/courses/http%3A%2F%2Fwww.academicearth.org%2Fcourses%2Fdarwins-legacy/) 156 | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- 157 | Enter to continue or "q" to quit 158 | 159 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # Kodi Swift documentation build configuration file, created by 4 | # sphinx-quickstart on Sat Jan 21 15:24:10 2012. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | 16 | # If extensions (or modules to document with autodoc) are in another directory, 17 | # add these directories to sys.path here. If the directory is relative to the 18 | # documentation root, use os.path.abspath to make it absolute, like shown here. 19 | sys.path.insert(0, os.path.join(os.path.abspath('.'), '..')) 20 | 21 | # -- General configuration ----------------------------------------------------- 22 | 23 | # If your documentation needs a minimal Sphinx version, state it here. 24 | #needs_sphinx = '1.0' 25 | 26 | # Add any Sphinx extension module names here, as strings. They can be extensions 27 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 28 | extensions = ['sphinx.ext.autodoc', 'sphinx.ext.doctest', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode'] 29 | 30 | # Add any paths that contain templates here, relative to this directory. 31 | templates_path = ['_templates'] 32 | 33 | # The suffix of source filenames. 34 | source_suffix = '.rst' 35 | 36 | # The encoding of source files. 37 | #source_encoding = 'utf-8-sig' 38 | 39 | # The master toctree document. 40 | master_doc = 'index' 41 | 42 | # General information about the project. 43 | project = u'Kodi Swift' 44 | copyright = u'2012, Jonathan Beluch' 45 | 46 | # The version info for the project you're documenting, acts as replacement for 47 | # |version| and |release|, also used in various other places throughout the 48 | # built documents. 49 | # 50 | # The short X.Y version. 51 | version = '1.0' 52 | # The full version, including alpha/beta/rc tags. 53 | release = '1.0.1' 54 | 55 | # The language for content autogenerated by Sphinx. Refer to documentation 56 | # for a list of supported languages. 57 | #language = None 58 | 59 | # There are two options for replacing |today|: either, you set today to some 60 | # non-false value, then it is used: 61 | #today = '' 62 | # Else, today_fmt is used as the format for a strftime call. 63 | #today_fmt = '%B %d, %Y' 64 | 65 | # List of patterns, relative to source directory, that match files and 66 | # directories to ignore when looking for source files. 67 | exclude_patterns = ['_build'] 68 | 69 | # The reST default role (used for this markup: `text`) to use for all documents. 70 | #default_role = None 71 | 72 | # If true, '()' will be appended to :func: etc. cross-reference text. 73 | #add_function_parentheses = True 74 | 75 | # If true, the current module name will be prepended to all description 76 | # unit titles (such as .. function::). 77 | #add_module_names = True 78 | 79 | # If true, sectionauthor and moduleauthor directives will be shown in the 80 | # output. They are ignored by default. 81 | #show_authors = False 82 | 83 | # The name of the Pygments (syntax highlighting) style to use. 84 | pygments_style = 'sphinx' 85 | 86 | # A list of ignored prefixes for module index sorting. 87 | #modindex_common_prefix = [] 88 | 89 | 90 | # -- Options for HTML output --------------------------------------------------- 91 | 92 | # Add _themes to path 93 | sys.path.append(os.path.abspath('_themes')) 94 | 95 | # The theme to use for HTML and HTML Help pages. See the documentation for 96 | # a list of builtin themes. 97 | #html_theme = 'default' 98 | html_theme = 'flask' 99 | 100 | # Theme options are theme-specific and customize the look and feel of a theme 101 | # further. For a list of options available for each theme, see the 102 | # documentation. 103 | #html_theme_options = {} 104 | 105 | # Add any paths that contain custom themes here, relative to this directory. 106 | #html_theme_path = [] 107 | html_theme_path = ['_themes'] 108 | 109 | # The name for this set of Sphinx documents. If None, it defaults to 110 | # " v documentation". 111 | #html_title = None 112 | 113 | # A shorter title for the navigation bar. Default is the same as html_title. 114 | #html_short_title = None 115 | 116 | # The name of an image file (relative to this directory) to place at the top 117 | # of the sidebar. 118 | #html_logo = None 119 | 120 | # The name of an image file (within the static path) to use as favicon of the 121 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 122 | # pixels large. 123 | #html_favicon = None 124 | 125 | # Add any paths that contain custom static files (such as style sheets) here, 126 | # relative to this directory. They are copied after the builtin static files, 127 | # so a file named "default.css" will overwrite the builtin "default.css". 128 | html_static_path = ['_static'] 129 | 130 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 131 | # using the given strftime format. 132 | #html_last_updated_fmt = '%b %d, %Y' 133 | 134 | # If true, SmartyPants will be used to convert quotes and dashes to 135 | # typographically correct entities. 136 | #html_use_smartypants = True 137 | 138 | # Custom sidebar templates, maps document names to template names. 139 | #html_sidebars = {} 140 | 141 | # Additional templates that should be rendered to pages, maps page names to 142 | # template names. 143 | #html_additional_pages = {} 144 | 145 | # If false, no module index is generated. 146 | #html_domain_indices = True 147 | 148 | # If false, no index is generated. 149 | #html_use_index = True 150 | 151 | # If true, the index is split into individual pages for each letter. 152 | #html_split_index = False 153 | 154 | # If true, links to the reST sources are added to the pages. 155 | #html_show_sourcelink = True 156 | 157 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 158 | #html_show_sphinx = True 159 | 160 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 161 | #html_show_copyright = True 162 | 163 | # If true, an OpenSearch description file will be output, and all pages will 164 | # contain a tag referring to it. The value of this option must be the 165 | # base URL from which the finished HTML is served. 166 | #html_use_opensearch = '' 167 | 168 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 169 | #html_file_suffix = None 170 | 171 | # Output file base name for HTML help builder. 172 | htmlhelp_basename = 'XBMCSwiftdoc' 173 | 174 | 175 | # -- Options for LaTeX output -------------------------------------------------- 176 | 177 | latex_elements = { 178 | # The paper size ('letterpaper' or 'a4paper'). 179 | #'papersize': 'letterpaper', 180 | 181 | # The font size ('10pt', '11pt' or '12pt'). 182 | #'pointsize': '10pt', 183 | 184 | # Additional stuff for the LaTeX preamble. 185 | #'preamble': '', 186 | } 187 | 188 | # Grouping the document tree into LaTeX files. List of tuples 189 | # (source start file, target name, title, author, documentclass [howto/manual]). 190 | latex_documents = [ 191 | ('index', 'XBMCSwift.tex', u'Kodi Swift Documentation', 192 | u'Jonathan Beluch', 'manual'), 193 | ] 194 | 195 | # The name of an image file (relative to this directory) to place at the top of 196 | # the title page. 197 | #latex_logo = None 198 | 199 | # For "manual" documents, if this is true, then toplevel headings are parts, 200 | # not chapters. 201 | #latex_use_parts = False 202 | 203 | # If true, show page references after internal links. 204 | #latex_show_pagerefs = False 205 | 206 | # If true, show URL addresses after external links. 207 | #latex_show_urls = False 208 | 209 | # Documents to append as an appendix to all manuals. 210 | #latex_appendices = [] 211 | 212 | # If false, no module index is generated. 213 | #latex_domain_indices = True 214 | 215 | 216 | # -- Options for manual page output -------------------------------------------- 217 | 218 | # One entry per manual page. List of tuples 219 | # (source start file, name, description, authors, manual section). 220 | man_pages = [ 221 | ('index', 'kodiswift', u'Kodi Swift Documentation', 222 | [u'Jonathan Beluch'], 1) 223 | ] 224 | 225 | # If true, show URL addresses after external links. 226 | #man_show_urls = False 227 | 228 | 229 | # -- Options for Texinfo output ------------------------------------------------ 230 | 231 | # Grouping the document tree into Texinfo files. List of tuples 232 | # (source start file, target name, title, author, 233 | # dir menu entry, description, category) 234 | texinfo_documents = [ 235 | ('index', 'XBMCSwift', u'Kodi Swift Documentation', 236 | u'Jonathan Beluch', 'XBMCSwift', 'One line description of project.', 237 | 'Miscellaneous'), 238 | ] 239 | 240 | # Documents to append as an appendix to all manuals. 241 | #texinfo_appendices = [] 242 | 243 | # If false, no module index is generated. 244 | #texinfo_domain_indices = True 245 | 246 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 247 | #texinfo_show_urls = 'footnote' 248 | -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | 2 | Welcome to kodiswift's documentation! 3 | ===================================== 4 | 5 | Welcome to the documentation for kodiswift. kodiswift is a small framework to 6 | ease development of Kodi addons. Whether you are an experienced addon 7 | developer, or just coding your first addon, you'll find benefits to using kodiswift. 8 | 9 | This documentation is divided into several parts. If you are new, you should 10 | start with the :ref:`installation` and then move on to :ref:`quickstart`. If 11 | you would prefer a more detailed walkthrough, try the :ref:`tutorial`. 12 | 13 | To get a deeper understanding of kodiswift, check out :ref:`routing`, 14 | :ref:`caching` and the complete :ref:`api` reference. For specific code 15 | samples, check out :ref:`patterns`. If you are upgrading from kodiswift, check 16 | out the :ref:`upgrading` page. 17 | 18 | For a list of Kodi addons which use kodiswift, see :ref:`poweredby`. 19 | 20 | 21 | Basic Info 22 | ---------- 23 | 24 | .. toctree:: 25 | :maxdepth: 2 26 | 27 | installation 28 | quickstart 29 | tutorial 30 | item 31 | commandline 32 | 33 | Advanced User Guide 34 | ------------------- 35 | 36 | .. toctree:: 37 | :maxdepth: 2 38 | 39 | routing 40 | caching 41 | patterns 42 | 43 | 44 | API Reference 45 | ------------- 46 | 47 | .. toctree:: 48 | :maxdepth: 2 49 | 50 | api 51 | 52 | 53 | Other Notes 54 | ----------- 55 | 56 | .. toctree:: 57 | :maxdepth: 2 58 | 59 | upgrading 60 | poweredby 61 | -------------------------------------------------------------------------------- /docs/installation.rst: -------------------------------------------------------------------------------- 1 | .. _installation: 2 | 3 | Installation 4 | ============ 5 | 6 | .. note:: 7 | 8 | The purpose of kodiswift is to have the ability to run the addon on the 9 | command line as well as in Kodi. This means that we will have to install 10 | kodiswift twice, once for the command line and once as an Kodi addon. 11 | 12 | The Kodi version of kodiswift is a specially packaged version of the main 13 | release. It excludes some CLI code and tests. It also contains Kodi 14 | required files like addon.xml. 15 | 16 | The easiest way to get the most recent version of kodiswift for Kodi is to 17 | install an addon that requires kodiswift. You can find a list of such addons 18 | on the :ref:`poweredby` page. The other options is download the current Kodi 19 | distribution from https://github.com/jbeluch/kodiswift-xbmc-dist/tags and 20 | unpack it into your addons folder. 21 | 22 | Now, on to installing kodiswift for use on the command line. 23 | 24 | virtualenv 25 | ---------- 26 | 27 | Virtualenv is an awesome tool that enables clean installation and removal of 28 | python libraries into a sequestered environment. Using a virtual environment 29 | means that when you install a library, it doesn't pollute your system-wide 30 | python installation. This makes it possible to install different versions of a 31 | library in different environments and they will never conflict. It's a good 32 | habit to get into when doing python development. So, first we're going to 33 | install virtualenv. 34 | 35 | If you already have pip installed, you can simply:: 36 | 37 | $ sudo pip install virtualenv 38 | 39 | or if you only have easy_install:: 40 | 41 | $ sudo easy_install virtualenv 42 | 43 | I also like to use some helpful virtualenv scripts, so install 44 | virtualenv-wrapper as well:: 45 | 46 | $ sudo pip install virtualenv-wrapper 47 | 48 | Creating a Virtual Environment 49 | ------------------------------ 50 | 51 | Now we can create our virtualenv:: 52 | 53 | $ mkvirtualenv kodiswift 54 | 55 | When this completes, your prompt should now be prefixed by `(kodiswift)`. The 56 | new prompt signals that we are now working within our virtualenv. Any libraries 57 | that we install via pip will only be available in this environment. Now we'll 58 | install kodiswift:: 59 | 60 | $ pip install kodiswift 61 | 62 | Everything should be good to go. When you would like to work on your project 63 | in the future, issue the following command to start your virtual env:: 64 | 65 | $ workon kodiswift 66 | 67 | and to deactive the virtualenv:: 68 | 69 | $ deactivate 70 | 71 | You should check out the :ref:`commandline` page next. 72 | -------------------------------------------------------------------------------- /docs/item.rst: -------------------------------------------------------------------------------- 1 | .. _item: 2 | 3 | 4 | The ListItem 5 | ============ 6 | 7 | kodiswift prefers to represent Kodi list items as plain python dictionaries as 8 | much as possible. Views return lists of dictionaries, where each dict 9 | represents an Kodi listitem. The list of valid keys in an item dict can always 10 | be validated by reviewing the available arguments to 11 | :meth:`kodiswift.ListItem.from_dict`. However, we'll go into more detail here. 12 | 13 | Valid keys in an item dict are: 14 | 15 | * `label`_ 16 | * `label2`_ 17 | * `icon`_ 18 | * `thumbnail`_ 19 | * `path`_ 20 | * `selected`_ 21 | * `info`_ 22 | * `properties`_ 23 | * `context_menu`_ 24 | * `replace_context_menu`_ 25 | * `is_playable`_ 26 | * `info_type`_ 27 | * `stream_info`_ 28 | 29 | label 30 | ----- 31 | 32 | A required string. Used as the main display label for the list item. 33 | 34 | 35 | label2 36 | ------ 37 | 38 | A string. Used as the alternate display label for the list item. 39 | 40 | 41 | icon 42 | ---- 43 | 44 | A path to an icon image. 45 | 46 | 47 | thumbnail 48 | --------- 49 | 50 | A path to a thumbnail image. 51 | 52 | 53 | path 54 | ---- 55 | 56 | A required string. 57 | 58 | For non-playable items, this is typically a URL for a different path in the 59 | same addon. To derive URLs for other views within your addon, use 60 | :meth:`kodiswift.Plugin.url_for`. 61 | 62 | For playable items, this is typically a URL to a remote media file. (One 63 | exception, is if you are using the set_resolved_url pattern, the URL will be 64 | playable but will also call back into your addon.) 65 | 66 | 67 | selected 68 | -------- 69 | 70 | A boolean which will set the item as selected. False is default. 71 | 72 | 73 | info 74 | ---- 75 | 76 | A dictionary of key/values of metadata information about the item. See the 77 | `Kodi docs 78 | `_ for 79 | a list of valid info items. Keys are always strings but values should be the 80 | correct type required by Kodi. 81 | 82 | Also, see the related `info_type`_ key. 83 | 84 | 85 | properties 86 | ---------- 87 | 88 | A dict of properties, similar to info-labels. See 89 | `ListItem documentation `_ for 90 | more information. 91 | 92 | 93 | context_menu 94 | ------------ 95 | 96 | A list of tuples, where each tuple is of length 2. The tuple should be (label, 97 | action) where action is a string representing a built-in Kodi function. See the 98 | `Kodi documentation 99 | `_ 100 | for more details and `Using the Context Menu` for some example code. 101 | 102 | 103 | replace_context_menu 104 | -------------------- 105 | 106 | Used in conjunction with `context_menu`. A boolean indicating whether to 107 | replace the existing context menu with the passed context menu items. Defaults 108 | to False. 109 | 110 | 111 | is_playable 112 | ----------- 113 | 114 | A boolean indicating whether the item dict is a playable item. False indicates 115 | that the item is a directory item. Use True when the path is a direct media 116 | URL, or a URL that calls back to your addon where set_resolved_url will be 117 | used. 118 | 119 | 120 | info_type 121 | --------- 122 | 123 | Used in conjunction with `info`. The default value is usually configured 124 | automatically from your addon.xml. See 125 | `setInfo documentation `_ for 126 | valid values. 127 | 128 | 129 | stream_info 130 | ----------- 131 | 132 | A dict where each key is a stream type and each value is another dict of stream 133 | values. See 134 | `addStreamInfo documentation `_ 135 | for more information. 136 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. linkcheck to check all external links for integrity 37 | echo. doctest to run all doctests embedded in the documentation if enabled 38 | goto end 39 | ) 40 | 41 | if "%1" == "clean" ( 42 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 43 | del /q /s %BUILDDIR%\* 44 | goto end 45 | ) 46 | 47 | if "%1" == "html" ( 48 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 49 | if errorlevel 1 exit /b 1 50 | echo. 51 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 52 | goto end 53 | ) 54 | 55 | if "%1" == "dirhtml" ( 56 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 57 | if errorlevel 1 exit /b 1 58 | echo. 59 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 60 | goto end 61 | ) 62 | 63 | if "%1" == "singlehtml" ( 64 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 68 | goto end 69 | ) 70 | 71 | if "%1" == "pickle" ( 72 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished; now you can process the pickle files. 76 | goto end 77 | ) 78 | 79 | if "%1" == "json" ( 80 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished; now you can process the JSON files. 84 | goto end 85 | ) 86 | 87 | if "%1" == "htmlhelp" ( 88 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can run HTML Help Workshop with the ^ 92 | .hhp project file in %BUILDDIR%/htmlhelp. 93 | goto end 94 | ) 95 | 96 | if "%1" == "qthelp" ( 97 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 98 | if errorlevel 1 exit /b 1 99 | echo. 100 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 101 | .qhcp project file in %BUILDDIR%/qthelp, like this: 102 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\XBMCSwift.qhcp 103 | echo.To view the help file: 104 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\XBMCSwift.ghc 105 | goto end 106 | ) 107 | 108 | if "%1" == "devhelp" ( 109 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 110 | if errorlevel 1 exit /b 1 111 | echo. 112 | echo.Build finished. 113 | goto end 114 | ) 115 | 116 | if "%1" == "epub" ( 117 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 118 | if errorlevel 1 exit /b 1 119 | echo. 120 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 121 | goto end 122 | ) 123 | 124 | if "%1" == "latex" ( 125 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 129 | goto end 130 | ) 131 | 132 | if "%1" == "text" ( 133 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The text files are in %BUILDDIR%/text. 137 | goto end 138 | ) 139 | 140 | if "%1" == "man" ( 141 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 145 | goto end 146 | ) 147 | 148 | if "%1" == "texinfo" ( 149 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 150 | if errorlevel 1 exit /b 1 151 | echo. 152 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 153 | goto end 154 | ) 155 | 156 | if "%1" == "gettext" ( 157 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 158 | if errorlevel 1 exit /b 1 159 | echo. 160 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 161 | goto end 162 | ) 163 | 164 | if "%1" == "changes" ( 165 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 166 | if errorlevel 1 exit /b 1 167 | echo. 168 | echo.The overview file is in %BUILDDIR%/changes. 169 | goto end 170 | ) 171 | 172 | if "%1" == "linkcheck" ( 173 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 174 | if errorlevel 1 exit /b 1 175 | echo. 176 | echo.Link check complete; look for any errors in the above output ^ 177 | or in %BUILDDIR%/linkcheck/output.txt. 178 | goto end 179 | ) 180 | 181 | if "%1" == "doctest" ( 182 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 183 | if errorlevel 1 exit /b 1 184 | echo. 185 | echo.Testing of doctests in the sources finished, look at the ^ 186 | results in %BUILDDIR%/doctest/output.txt. 187 | goto end 188 | ) 189 | 190 | :end 191 | -------------------------------------------------------------------------------- /docs/patterns.rst: -------------------------------------------------------------------------------- 1 | .. _patterns: 2 | 3 | 4 | Patterns 5 | ======== 6 | 7 | 8 | Caching 9 | ------- 10 | 11 | View Caching 12 | ```````````` 13 | 14 | Use the :meth:`~kodiswift.Plugin.cached_route` decorator instead of the normal 15 | `route` decorator. This will cache the results of your view for 24 hours. 16 | 17 | *NOTE:* You must be returning a list of plain dictionaries from your view and 18 | cannot return plugin.finish(). This is due to a current limitation in the cache 19 | which doesn't keep track of side effects such as a call to plugin.finish. If 20 | you need to call plugin.finish() because you are passing non-default arguments, 21 | then see the next example which uses plugin.cached(). 22 | 23 | .. sourcecode:: python 24 | 25 | @plugin.cached_route('/subjects/', options={'url': full_url('subjects')}) 26 | def show_subjects(url): 27 | '''Lists available subjects found on the website''' 28 | html = htmlify(url) 29 | subjects = html.findAll('a', {'class': 'subj-links'}) 30 | 31 | items = [{ 32 | 'label': subject.div.string.strip(), 33 | 'path': plugin.url_for('show_topics', url=full_url(subject['href'])), 34 | } for subject in subjects] 35 | return items 36 | 37 | General Function Caching 38 | ```````````````````````` 39 | 40 | To cache the results of any function call, simply use the 41 | :meth:`~kodiswift.Plugin.cached` decorator. Keep in mind that the function name 42 | along with the args and kwargs used to call the function are used as the cache 43 | key. If your function depends on any variables in outer scope which could 44 | affect the return value, you should pass in those variables explictly as args 45 | to ensure a different cache entry is created. 46 | 47 | .. sourcecode:: python 48 | 49 | @plugin.cached() 50 | def get_api_data(): 51 | return download_data() 52 | 53 | Storing Arbitrary Objects 54 | ````````````````````````` 55 | 56 | You can always create your own persistent storage using 57 | :meth:`~kodiswift.Plugin.get_storage`. The returned storage acts like a 58 | dictionary, however it is automatically persisted to disk. 59 | 60 | .. sourcecode:: python 61 | 62 | storage = plugin.get_storage('people') 63 | storage['jon'] = {'vehicle': 'bike'} 64 | storage['dave'] # Throws KeyError 65 | storage.get('dave') # Returns None 66 | storage.clear() # Clears all items from the storage 67 | 68 | Adding pagination 69 | ----------------- 70 | 71 | If you are scraping a website that uses pagination, it's possible to present 72 | the same interface in Kodi without having to scrape all of the pages up front. 73 | To accomplish this, we are going to create our own *Next* and *Previous* list 74 | items which go the next and previous page of results respectively. We're also 75 | going to take advantage of a parameter option that gets passed to Kodi, 76 | `updateListing`. If we pass True for this parameter, then every time the use 77 | clicks the Next item, the URL won't be added to history. This enables the ".." 78 | list item to go to the correct parent directory, instead of the previous page. 79 | 80 | Some example code: 81 | 82 | .. sourcecode:: python 83 | 84 | @plugin.route('/videos/') 85 | def show_videos(page='1'): 86 | page = int(page) # all url params are strings by default 87 | videos, next_page = get_videos(page) 88 | items = [make_item(video) for video in videos] 89 | 90 | if next_page: 91 | items.insert(0, { 92 | 'label': 'Next >>', 93 | 'path': plugin.url_for('show_videos', page=str(page + 1)) 94 | }) 95 | 96 | if page > 1: 97 | items.insert(0, { 98 | 'label': '<< Previous', 99 | 'path': plugin.url_for('show_videos', page=str(page - 1)) 100 | }) 101 | 102 | return plugin.finish(items, update_listing=True) 103 | 104 | The first thing to notice about our view, is that it takes a page number as a 105 | URL parameter. We then pass the page number to the API call, get_videos(), to 106 | return the correct data based on the current page. Then we create our own 107 | previous/next list items depending on the current page. Lastly, we are 108 | returning the result of the call to plugin.finish(). By default, when you 109 | normally return a list of dicts, plugin.finish() is called for you. However, in 110 | this case we need to pass the update_listing=True parameter so we must call it 111 | explictly. 112 | 113 | Setting update_listing to True, notifies Kodi that we are paginating, and that 114 | every new page should *not* be a new entry in the history. 115 | 116 | 117 | Reusing views with multiple routes 118 | ---------------------------------- 119 | 120 | It is possible to decorate views with more than one route. This becomes useful 121 | if you are parsing different URLs that share the same parsing code. In order to 122 | unambiguously use :meth:`~kodiswift.Plugin.url_for`, you need to pass a value 123 | for the name keyword argument. When calling ``url_for``, you pass this 124 | specified name instead of the name of the actual function. 125 | 126 | If the decorated method requires arguments, it is possible to pass these as 127 | default keyword arguments to the ``route`` decorator. Also, the function itself 128 | can use python's default argument syntax. 129 | 130 | .. sourcecode:: python 131 | 132 | @plugin.route('/movies/', name='show_movie_genres') 133 | @plugin.route('/silents/', name='show_silent_genres', options={'path': 'index.php/silent-films-menu'}) 134 | @plugin.route('/serials/', name='show_serials', options={'path': 'index.php/serials'}) 135 | def show_genres(path='movies'): 136 | pass 137 | 138 | 139 | Adding sort methods 140 | ------------------- 141 | 142 | Sort methods enable the user to sort a directory listing in different ways. You 143 | can see the available sort methods `here 144 | `_, or 145 | by doing ``dir(kodiswift.SortMethod)``. The simplest way to add sort methods to 146 | your views is to call plugin.finish() with a sort_methods argument and return 147 | the result from your view (this is what kodiswift does behind the scenes 148 | normally). 149 | 150 | .. sourcecode:: python 151 | 152 | @plugin.route('/movies') 153 | def show_movies(): 154 | movies = api.get_movies() 155 | items = [create_item(movie) for movie in movies] 156 | return plugin.finish(items, sort_methods=['playlist_order', 'title', 'date']) 157 | 158 | See :meth:`kodiswift.Plugin.finish` for more information. 159 | 160 | 161 | Playing RTMP urls 162 | ----------------- 163 | 164 | If we need to play an RTMP url, we can use :meth:`kodiswift.Plugin.play_video`. 165 | 166 | .. sourcecode:: python 167 | 168 | @plugin.route('/live/') 169 | def watch_live(): 170 | item = { 171 | 'label': 'AlJazeera Live', 172 | 'path': 'rtmp://aljazeeraflashlivefs.fplive.net:1935/aljazeeraflashlive-live/aljazeera_english_1 live=true', 173 | } 174 | return plugin.play_video(item) 175 | 176 | 177 | Using settings 178 | -------------- 179 | 180 | how to use settings 181 | 182 | 183 | Using the Context Menu 184 | ---------------------- 185 | 186 | Kodi allows plugin to authors to update the context menu on a per list item 187 | basis. This allows you to add more functionality to your addons, as you can 188 | allow users other actions for a given item. One popular use for this feature is 189 | to create allow playable items to be added to custom playlists within the 190 | addon. (See the itunes_ or reddit-music_ addons for implementations). 191 | 192 | .. _itunes: https://github.com/dersphere/plugin.video.itunes_podcasts 193 | .. _reddit-music: https://github.com/jbeluch/xbmc-reddit-music 194 | 195 | In kodiswift, adding context menu items is accomplished by passing a value for 196 | the *context_menu* key in an item dict. The value should be a list of 2-tuples. 197 | Each tuple corresponds to a context menu item, and should be of the format 198 | (display_string, action) where action is a string corresponding to one of 199 | Kodi's `built-in functions`_. See `Kodi's documentation 200 | `_ 201 | for more information. 202 | 203 | .. _`built-in functions`: http://kodi.wiki/view/List_of_Built_In_Functions 204 | 205 | The most common actions are `Kodi.RunPlugin()` and `Kodi.Container.Update()`. 206 | RunPlugin takes a single argument, a URL for a plugin (you can create a URL 207 | with :meth:`kodiswift.Plugin.url_for`). Kodi will then run your plugin in a 208 | background thread, *it will not affect the current UI*. So, RunPlugin is good 209 | for any sort of background task. Update(), however will change the current UI 210 | directory, so is useful when data is updated and you need to refresh the 211 | screen. 212 | 213 | If you are using one of the two above built-ins, there are convenience 214 | functions in kodiswift in the actions module. 215 | 216 | Here is a quick example of updating the context menu. 217 | 218 | .. sourcecode:: python 219 | 220 | from kodiswift import actions 221 | 222 | @plugin.url('/favorites/add/') 223 | def add_to_favorites(url): 224 | # this is a background view 225 | ... 226 | 227 | def make_favorite_ctx(url) 228 | label = 'Add to favorites' 229 | new_url = plugin.url_for('add_to_favorites', url=url) 230 | return (label, actions.background(new_url)) 231 | 232 | 233 | @plugin.route('/movies') 234 | def show_movies() 235 | items = [{ 236 | ... 237 | 'context_menu': [ 238 | make_favorite_ctx(movie['url']), 239 | ], 240 | 'replace_context_menu': True, 241 | } for movie in movies] 242 | return items 243 | 244 | Sometimes the context_menu value can become very nested, so we've pulled out 245 | the logic into the ``make_favorite_ctx`` function. Notice also the use of the 246 | *replace_context_menu* key and the True value. This instructs Kodi to clear the 247 | context menu prior to adding your context menu items. By default, your context 248 | menu items are mixed in with the built in options. 249 | 250 | 251 | Using extra parameters in the query string 252 | ------------------------------------------ 253 | 254 | When calling :meth:`kodiswift.Plugin.url_for`, any keyword arguments passed 255 | that are not required for the specified view function will be added as query 256 | string arguments. 257 | 258 | A dict of query string parameters can be accessed from ``plugin.request.args``. 259 | 260 | Any arguments that are not instances of basestring will attempt to be preserved 261 | by pickling them before being encoded into the query string. This functionality 262 | isn't fully tested however, and Kodi does limit the length of URLs. If you need 263 | to preserve python objects between function calls, see the Caching_ patterns. 264 | 265 | 266 | Using Modules 267 | ------------- 268 | 269 | Modules are meant to be mini-addons. They have some basic functionality that 270 | is separate from the main plugin. In order to be used, they must be registered 271 | with a plugin. 272 | 273 | Creating an add to favorites plugin: 274 | 275 | .. sourcecode:: python 276 | 277 | from kodiswift import Module 278 | 279 | playlist = Module(__name__) 280 | 281 | @playlist.route('/add/') 282 | def add_to_playlist(): 283 | items = [playlist.qs_args] 284 | return playlist._plugin.add_to_playlist(items) 285 | 286 | Examples of plugins 287 | ``````````````````` 288 | 289 | * add to favorites 290 | * report to google form 291 | 292 | 293 | Testing with Nose 294 | ----------------- 295 | 296 | How to test with nose 297 | 298 | 299 | 300 | -------------------------------------------------------------------------------- /docs/poweredby.rst: -------------------------------------------------------------------------------- 1 | .. _poweredby: 2 | 3 | 4 | Addons Powered by kodiswift 5 | =========================== 6 | 7 | Want your addon included here? Send me an email at web@jonathanbeluch.com with 8 | your addon name and a link to a repository (Kodi's git repo is fine). 9 | 10 | ======================== ============================================================= 11 | Plugin Source 12 | ======================== ============================================================= 13 | `Academic Earth`_ https://github.com/jbeluch/xbmc-academic-earth 14 | `Documentary.net`_ https://github.com/jbeluch/plugin.video.documentary.net 15 | `VimCasts`_ https://github.com/jbeluch/xbmc-vimcasts 16 | `Radio`_ https://github.com/dersphere/plugin.audio.radio_de 17 | `Shoutcast 2`_ https://github.com/dersphere/plugin.audio.shoutcast 18 | `Cheezburger Network`_ https://github.com/dersphere/plugin.image.cheezburger_network 19 | `Apple Itunes Podcasts`_ https://github.com/dersphere/plugin.video.itunes_podcasts 20 | `MyZen.tv`_ https://github.com/dersphere/plugin.video.myzen_tv 21 | `Rofl.to`_ https://github.com/dersphere/plugin.video.rofl_to 22 | `Wimp`_ https://github.com/dersphere/plugin.video.wimp 23 | ======================== ============================================================= 24 | 25 | .. _Academic Earth: http://xbmcaddonbrowser.com/addons/frodo/plugin.video.academicearth/ 26 | .. _Documentary.net: http://xbmcaddonbrowser.com/addons/frodo/plugin.video.documentary.net/ 27 | .. _VimCasts: http://xbmcaddonbrowser.com/addons/frodo/plugin.video.vimcasts/ 28 | .. _Radio: http://xbmcaddonbrowser.com/addons/frodo/plugin.audio.radio_de/ 29 | .. _Shoutcast 2: http://xbmcaddonbrowser.com/addons/frodo/plugin.audio.shoutcast 30 | .. _Cheezburger Network: http://xbmcaddonbrowser.com/addons/frodo/plugin.image.cheezburger_network 31 | .. _Apple Itunes Podcasts: http://xbmcaddonbrowser.com/addons/frodo/plugin.video.itunes_podcasts 32 | .. _MyZen.tv: http://xbmcaddonbrowser.com/addons/frodo/plugin.video.myzen_tv 33 | .. _Rofl.to: http://xbmcaddonbrowser.com/addons/frodo/plugin.video.rofl_to 34 | .. _Wimp: http://xbmcaddonbrowser.com/addons/frodo/plugin.video.wimp 35 | -------------------------------------------------------------------------------- /docs/quickstart.rst: -------------------------------------------------------------------------------- 1 | .. _quickstart: 2 | 3 | Quickstart 4 | ========== 5 | 6 | If you haven't already installed kodiswift, head over to the `installation` 7 | page. 8 | 9 | The purpose of kodiswift is to empower plugin writers to develop and debug 10 | their plugins faster. This is faciliated by: 11 | 12 | * A bootstrap script to create an empty addon complete with folder structure 13 | and required files. 14 | 15 | * Seamless testing of addons by enabling an addon to be run on the command line 16 | or in Kodi. kodiswift handles mocking the xbmc python modules to ensure your 17 | addon will run (in a limited fashion) outside of Kodi *without* any code 18 | changes. 19 | 20 | * Basic URL routing code, so you can focus on writing the web parsing code 21 | specific to your plugin, and not deal with repeated boilerplate and url 22 | parsing. 23 | 24 | * A library of helpful functions and code patterns to enhance your addon's 25 | functionality. 26 | 27 | 28 | Introduction to Kodi Addons 29 | --------------------------- 30 | 31 | Before going any further, you should already be familiar with the general file 32 | structure and necessary files for an Kodi addon. If not, please spend a few 33 | minutes reading about addons in the Kodi wiki_. 34 | 35 | .. _wiki: http://kodi.wiki/view/Add-on_development 36 | 37 | 38 | Creating the Plugin Skeleton 39 | ---------------------------- 40 | 41 | kodiswift comes with a helpful console script that will create a plugin 42 | skeleton for you, including all the necessary folders and files to get started. 43 | Simply run `kodiswift create` and answer a few questions to personalize your 44 | addon. 45 | 46 | Below is an example session:: 47 | 48 | $ kodiswift create 49 | 50 | kodiswift - A micro-framework for creating Kodi plugins. 51 | xbmc@jonathanbeluch.com 52 | -- 53 | 54 | I'm going to ask you a few questions to get this project started. 55 | What is your plugin name? : Hello Kodi 56 | Enter your plugin id. [plugin.video.helloxbmc]: 57 | Enter parent folder (where to create project) [/private/tmp]: 58 | Enter provider name : Jonathan Beluch (jbel) 59 | Projects successfully created in /private/tmp/plugin.video.helloxbmc. 60 | Done. 61 | 62 | 63 | Hello Kodi 64 | ---------- 65 | 66 | If you navigate to the newly created folder ``plugin.video.helloxbmc``, you'll 67 | find an ``plugin.py`` exactly like the one below. 68 | 69 | .. sourcecode:: python 70 | 71 | from kodiswift import Plugin 72 | 73 | 74 | plugin = Plugin() 75 | 76 | 77 | @plugin.route('/') 78 | def index(): 79 | item = { 80 | 'label': 'Hello Kodi!', 81 | 'path': 'http://s3.amazonaws.com/KA-youtube-converted/JwO_25S_eWE.mp4/JwO_25S_eWE.mp4', 82 | 'is_playable': True 83 | } 84 | return [item] 85 | 86 | 87 | if __name__ == '__main__': 88 | plugin.run() 89 | 90 | The above code is a fully functioning Kodi addon (not that it does much!). So 91 | what does the code do? 92 | 93 | 1. After importing the Plugin class, we create our plugin instance. kodiswift 94 | will parse the proper addon name and id from the addon.xml file. 95 | 96 | 2. We are using the ``plugin.route`` decorator on the ``index`` function. This 97 | binds a url path of '/' to the index function. ('/' is the default URL 98 | path). 99 | 100 | Note: The url rule of '/' must always exist in a plugin. This is the default 101 | route when a plugin is first run. 102 | 103 | 3. The index function creates a single dict with some key/vals. This is how you 104 | create a listitem using kodiswift. At a minimum, most items have a ``path`` 105 | and ``label``. The ``is_playable`` flag tells Kodi that this is a media 106 | item, and not a URL which points back to an addon. 107 | 108 | 4. We return a list from the index function, that contains a single item. For a 109 | typical kodiswift view, this is the proper way to add list items. 110 | 111 | 5. We call ``plugin.run()`` to run our plugin. It is imperative that this line 112 | is inside the ``__name__`` guard. If it is not, your addon won't run 113 | correctly on the command line. 114 | 115 | 116 | Running Addons from the Command Line 117 | ------------------------------------ 118 | 119 | One of the shining points of kodiswift is the ability to run plugins from the 120 | command line. To do so, ensure your working directory is the root of your addon 121 | folder (where you addon.xml file is located) and execute ``kodiswift run``.:: 122 | 123 | $ kodiswift run 124 | 2012-05-02 19:02:37,785 - DEBUG - [kodiswift] Adding url rule "/" named "index" pointing to function "index" 125 | 2012-05-02 19:02:37,798 - DEBUG - [kodiswift] Dispatching / to once 126 | 2012-05-02 19:02:37,798 - INFO - [kodiswift] Request for "/" matches rule for function "index" 127 | ---------------------- 128 | # Label Path 129 | ---------------------- 130 | [0] Hello Kodi! (None) 131 | ---------------------- 132 | 133 | Right away we can see the output of our plugin. When running in the CLI, 134 | kodiswift prints log messages to STDERR, so you can hide them by appending 135 | ``2>/dev/null`` to the previous command.. Below the logs we can see a simple 136 | display of our listitems, in this case a single item. 137 | 138 | See :ref:`commandline` for a more detailed explanation of running on the command line. 139 | 140 | 141 | URL Routing 142 | ----------- 143 | 144 | Another advantage of using kodiswift, is its clean URL routing code. This 145 | means you don't have to write your own code to parse the URL provided by Kodi 146 | and route it to a specific function. kodiswift uses a a path passed to the 147 | :meth:`~kodiswift.Plugin.route` decorator to bind a URL to a function. For 148 | example, a route of ``/videos/`` will result in a URL of 149 | ``plugin://plugin.video.helloxbmc/videos/`` calling the decorated function. 150 | 151 | It's even possible to pass variables to functions from the URLs. You might 152 | have a function like this to list videos for a given category: 153 | 154 | .. sourcecode:: python 155 | 156 | @plugin.route('/categories//') 157 | def show_videos(category): 158 | '''Display videos for the provided category''' 159 | # An incoming URL of /categories/science/ would call this function and 160 | # category would have a value of 'science'. 161 | items = get_video_items(category) 162 | return plugin.finish(items) 163 | 164 | Currently, there is no type coercion, so all variables plucked from URLs will 165 | be strings. 166 | 167 | Now we have a way of directing incoming URLs to specific views. But how do we 168 | link list items to other views in our code? We'll modify our Hello Kodi addon: 169 | 170 | .. sourcecode:: python 171 | 172 | @plugin.route('/') 173 | def index(): 174 | items = [ 175 | {'label': 'Hola Kodi!', 'path': plugin.url_for('show_label', label='spanish')}, 176 | {'label': 'Bonjour Kodi!', 'path': plugin.url_for('show_label', label='french')}, 177 | ] 178 | return items 179 | 180 | 181 | @plugin.route('/labels/