├── .checkignore ├── .codecov.yml ├── .github └── workflows │ ├── publish-addon.yml │ └── test-addon.yml ├── .gitignore ├── .travis.yml ├── Readme.md ├── addon.xml ├── docs ├── Makefile ├── _autosummary │ └── simpleplugin.rst ├── actions_routing.rst ├── api.rst ├── cached.rst ├── conf.py ├── debug.rst ├── example.rst ├── get_url.rst ├── gettext.rst ├── index.rst ├── links.rst ├── log.rst ├── make.bat ├── scrapers.rst ├── settings.rst ├── storage.rst └── using.rst ├── requirements.txt ├── resources └── language │ └── English │ └── strings.po ├── script.module.simpleplugin3 ├── addon.xml ├── changelog.txt ├── libs │ └── simpleplugin.py └── license.txt ├── setup.py └── tests.py /.checkignore: -------------------------------------------------------------------------------- 1 | tests.py 2 | -------------------------------------------------------------------------------- /.codecov.yml: -------------------------------------------------------------------------------- 1 | ignore: 2 | - "tests.py" 3 | -------------------------------------------------------------------------------- /.github/workflows/publish-addon.yml: -------------------------------------------------------------------------------- 1 | name: Publish add-on 2 | 3 | on: 4 | push: 5 | branches: [ kodi-release ] 6 | 7 | jobs: 8 | publish: 9 | 10 | runs-on: ubuntu-latest 11 | 12 | steps: 13 | - uses: actions/checkout@v2 14 | - name: Set up Python 3.8 15 | uses: actions/setup-python@v1 16 | with: 17 | python-version: 3.8 18 | - name: Install addon checker 19 | run: | 20 | pip install -q kodi-addon-checker 21 | - name: Check with addon-checker 22 | run: | 23 | kodi-addon-checker --branch krypton script.module.simpleplugin3 24 | - name: Install addon submitter 25 | run: | 26 | pip install -q git+https://github.com/xbmc/kodi-addon-submitter.git 27 | - name: Submit addon 28 | run: | 29 | submit-addon -r repo-scrapers -b krypton -m -s --pull-request script.module.simpleplugin3 30 | env: 31 | GH_USERNAME: vlmaksime 32 | GH_TOKEN: ${{ secrets.GH_TOKEN }} 33 | EMAIL: vl.maksime@gmail.com 34 | -------------------------------------------------------------------------------- /.github/workflows/test-addon.yml: -------------------------------------------------------------------------------- 1 | name: Test add-on 2 | 3 | on: 4 | push: 5 | branches: [ develop, master ] 6 | pull_request: 7 | branches: [ develop, master ] 8 | 9 | jobs: 10 | test: 11 | 12 | runs-on: ubuntu-latest 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | python-version: [2.7, 3.8] 17 | env: 18 | PYTHONIOENCODING: 'UTF-8' 19 | PYTHON: ${{ matrix.python-version }} 20 | steps: 21 | - uses: actions/checkout@v2 22 | - name: Set up Python ${{ matrix.python-version }} 23 | uses: actions/setup-python@v2 24 | with: 25 | python-version: ${{ matrix.python-version }} 26 | - name: Install dependencies 27 | run: | 28 | python -m pip install --upgrade pip 29 | python -m pip install flake8 codecov mock 30 | if [ -f requirements.txt ]; then pip install -r requirements.txt; fi 31 | - name: Lint with flake8 32 | run: | 33 | # stop the build if there are Python syntax errors or undefined names 34 | flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics 35 | # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide 36 | flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics 37 | - name: Generate coverage report 38 | run: | 39 | coverage run tests.py 40 | coverage xml 41 | - name: Upload coverage to Codecov 42 | uses: codecov/codecov-action@v2 43 | with: 44 | env_vars: PYTHON 45 | flags: unittests 46 | verbose: true 47 | 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio 4 | 5 | *.iml 6 | 7 | ## Directory-based project format: 8 | .idea/ 9 | # if you remove the above rule, at least ignore the following: 10 | 11 | # User-specific stuff: 12 | # .idea/workspace.xml 13 | # .idea/tasks.xml 14 | # .idea/dictionaries 15 | 16 | # Sensitive or high-churn files: 17 | # .idea/dataSources.ids 18 | # .idea/dataSources.xml 19 | # .idea/sqlDataSources.xml 20 | # .idea/dynamic.xml 21 | # .idea/uiDesigner.xml 22 | 23 | # Gradle: 24 | # .idea/gradle.xml 25 | # .idea/libraries 26 | 27 | # Mongo Explorer plugin: 28 | # .idea/mongoSettings.xml 29 | 30 | ## File-based project format: 31 | *.ipr 32 | *.iws 33 | 34 | ## Plugin-specific files: 35 | 36 | # IntelliJ 37 | /out/ 38 | 39 | # mpeltonen/sbt-idea plugin 40 | .idea_modules/ 41 | 42 | # JIRA plugin 43 | atlassian-ide-plugin.xml 44 | 45 | # Crashlytics plugin (for Android Studio and IntelliJ) 46 | com_crashlytics_export_strings.xml 47 | crashlytics.properties 48 | crashlytics-build.properties 49 | ### Python template 50 | # Byte-compiled / optimized / DLL files 51 | __pycache__/ 52 | *.py[cod] 53 | *$py.class 54 | 55 | # C extensions 56 | *.so 57 | 58 | # ========================= 59 | # Eclipse Specific GitIgnore 60 | # ========================= 61 | *.pydevproject 62 | .project 63 | .metadata 64 | bin/** 65 | tmp/** 66 | tmp/**/* 67 | *.tmp 68 | *.bak 69 | *.swp 70 | *~.nib 71 | local.properties 72 | .classpath 73 | .settings/ 74 | .loadpath 75 | 76 | # Distribution / packaging 77 | .Python 78 | .venv/ 79 | env/ 80 | build/ 81 | develop-eggs/ 82 | dist/ 83 | downloads/ 84 | eggs/ 85 | .eggs/ 86 | lib/ 87 | lib64/ 88 | parts/ 89 | sdist/ 90 | var/ 91 | *.egg-info/ 92 | .installed.cfg 93 | *.egg 94 | 95 | # PyInstaller 96 | # Usually these files are written by a python script from a template 97 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 98 | *.manifest 99 | *.spec 100 | 101 | # Installer logs 102 | pip-log.txt 103 | pip-delete-this-directory.txt 104 | 105 | # Unit test / coverage reports 106 | htmlcov/ 107 | .tox/ 108 | .coverage 109 | .coverage.* 110 | .cache 111 | nosetests.xml 112 | coverage.xml 113 | *,cover 114 | 115 | # Translations 116 | *.mo 117 | *.pot 118 | 119 | # Django stuff: 120 | *.log 121 | 122 | # Sphinx documentation 123 | docs/_build/ 124 | 125 | # PyBuilder 126 | target/ 127 | 128 | # Custom 129 | 130 | _docs/ 131 | *.cmd 132 | *.zip 133 | publish.py 134 | venv/ 135 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - "2.7" 4 | - "3.7" 5 | env: 6 | global: 7 | - ADDON_ID=script.module.simpleplugin3 8 | install: pip install codecov mock future 9 | script: coverage run tests.py 10 | after_success: codecov 11 | before_deploy: 12 | - pip install Sphinx 13 | - wget https://raw.githubusercontent.com/romanvm/travis_scripts/master/deploy_addon.py 14 | - pip install -q git+https://github.com/romanvm/kodi-addon-submitter.git 15 | - submit-addon -s -z -m $ADDON_ID 16 | - export RELEASE_ZIP=$(ls *.zip) 17 | deploy: 18 | - provider: releases 19 | api_key: $GH_TOKEN 20 | file_glob: true 21 | file: $RELEASE_ZIP 22 | skip_cleanup: true 23 | on: 24 | tags: true 25 | python: "3.7" 26 | # Deploy to my Kodi repo 27 | - provider: script 28 | skip_cleanup: true 29 | script: python deploy_addon.py -r 30 | on: 31 | tags: true 32 | python: "2.7" 33 | # Publish docs to GH Pages 34 | - provider: script 35 | skip_cleanup: true 36 | script: python deploy_addon.py -d 37 | on: 38 | branch: master 39 | python: "2.7" 40 | notifications: 41 | email: false 42 | -------------------------------------------------------------------------------- /Readme.md: -------------------------------------------------------------------------------- 1 | # SimplePlugin micro-framework for Kodi plugins 2 | 3 | ## The Project Is Suspended! 4 | 5 | Unfortunately, at this moment I have don't have time or desire to develop 6 | or maintain this project. 7 | This may change in the future but now I suspend the project until further notice. 8 | It means that from now on the project won't receive any updates and any new issues 9 | will be ignored. Fell free to do with the code whatever you like within GPL v.3 10 | terms and conditions. 11 | 12 | [![Build Status](https://travis-ci.org/romanvm/script.module.simpleplugin.svg?branch=master)](https://travis-ci.org/romanvm/script.module.simpleplugin) 13 | [![codecov.io](https://codecov.io/github/romanvm/script.module.simpleplugin/coverage.svg?branch=master)](https://codecov.io/github/romanvm/script.module.simpleplugin?branch=master) 14 | 15 | SimplePlugin micro-framework simplifies creating addons and content plugins for [Kodi](www.kodi.tv) mediacenter. 16 | It was inspired by [xbmcswift2](https://github.com/jbeluch/xbmcswift2) and has some similar features 17 | but SimplePlugin has different concept. Its 2 main goals are simplicity and support for 18 | both content plugins and general purpose addons. It supports routing plugin 19 | calls using "pretty" URLs or URL query strings. 20 | 21 | ## Important Information! 22 | 23 | `Plugin` class in SimplePlugin v.3.x is not compatible with earlier versions! 24 | Previously `Plugin` class supported defining content listings as Python lists 25 | of dictionaries with necessary properties. However, such excessive abstraction has 26 | proved to be brittle and prone to breakage with Kodi Python API changes. So 27 | now this abstraction has been removed and media content listings must be defined 28 | with `xbmcplugin` module functions. That is why SimplePlugin v.3.x has 29 | a different addon ID (`script.module.simpleplugin3`) sot that 30 | not to break existing plugins that depend on it. 31 | For SimplePlugin v.2.x code see `legacy` branch. 32 | 33 | ## Main Features 34 | 35 | * Automated plugin call routing based on "pretty" URLs or URL query strings 36 | using function decorators. 37 | * Convenience methods for simplified access to addon/plugin parameters and settings. 38 | * Persistent dictionary-like storage for storing addon's data. 39 | * Caching decorator that allows to cache function return data for a specified amount time, 40 | for example, to reduce the frequency of polling data from some website. 41 | * GNU Gettext emulation for simplified addon GUI localization: you can use 42 | English source strings in your Python code instead of non-obvious numeric string codes. 43 | * Compatible with Python 3 for future Kodi versions. 44 | 45 | ## Minimal Plugin Example with "Pretty" URL Routing 46 | 47 | ```python 48 | import xbmcgui 49 | import xbmcplugin 50 | from simpleplugin import RoutedPlugin 51 | 52 | plugin = RoutedPlugin() 53 | 54 | # Free video sample is provided by www.vidsplay.com 55 | 56 | @plugin.route('/') 57 | def root(): 58 | """ 59 | Root virtual folder 60 | 61 | This is a mandatory item. 62 | """ 63 | li = xbmcgui.ListItem('My Videos') 64 | li.setArt({'thumb': 'DefaultFolder.png'}) 65 | # URL: plugin://plugin.video.foo/subfolder/ 66 | url = plugin.url_for('subfolder') 67 | xbmcplugin.addDirectoryItem(plugin.handle, url, li, isFolder=True) 68 | xbmcplugin.endOfDirectory(plugin.handle) 69 | 70 | 71 | @plugin.route('/subfolder') 72 | def subfolder(): 73 | """Virtual subfolder""" 74 | li = xbmcgui.ListItem('Ocean Birds') 75 | li.setArt({'thumb': 'http://www.vidsplay.com/vids/ocean_birds.jpg'}) 76 | li.setProperty('isPlayable', 'true') 77 | url = plugin.url_for('play', video='http://www.vidsplay.com/vids/ocean_birds.mp4') 78 | xbmcplugin.addDirectoryItem(plugin.handle, url, li, isFolder=False) 79 | xbmcplugin.endOfDirectory(plugin.handle) 80 | 81 | 82 | # An action can take an optional argument. 83 | @plugin.route('/play/