diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index ed75f53..4d44d0d 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -44,9 +44,7 @@ jobs: path: Plugger.bundle - name: Install Python 2.7 - uses: actions/setup-python@v4 - with: - python-version: '2.7' + uses: LizardByte/.github/actions/setup_python2@nightly - name: Set up Python 2.7 Dependencies working-directory: Plugger.bundle diff --git a/.github/workflows/localize.yml b/.github/workflows/localize.yml index d05080a..c516bd5 100644 --- a/.github/workflows/localize.yml +++ b/.github/workflows/localize.yml @@ -6,7 +6,7 @@ on: branches: [nightly] paths: # prevents workflow from running unless these files change - '.github/workflows/localize.yml' - - 'Contents/Scripts/plugger.po' + - 'Contents/Strings/plugger.po' - 'Contents/Code/**.py' - 'Contents/Resources/web/templates/**' workflow_dispatch: @@ -27,8 +27,8 @@ jobs: - name: Set up Python Dependencies run: | - python -m pip install --upgrade pip setuptools - python -m pip install -r requirements.txt + python -m pip install --upgrade pip setuptools requests + python -m pip install -r requirements.txt # requests is required to install python-plexapi - name: Update Strings run: | @@ -40,14 +40,14 @@ jobs: git config --global pager.diff false # print the git diff - git diff Contents/Scripts/plugger.po + git diff Contents/Strings/plugger.po # set the variable with minimal output, replacing `\t` with ` ` - OUTPUT=$(git diff --numstat locale/retroarcher.po | sed -e "s#\t# #g") + OUTPUT=$(git diff --numstat Contents/Strings/plugger.po | sed -e "s#\t# #g") echo "git_diff=${OUTPUT}" >> $GITHUB_ENV - name: git reset - if: ${{ env.git_diff == '1 1 Contents/Scripts/plugger.po' }} # only run if more than 1 line changed + if: ${{ env.git_diff == '1 1 Contents/Strings/plugger.po' }} # only run if more than 1 line changed run: | git reset --hard @@ -59,7 +59,7 @@ jobs: uses: peter-evans/create-pull-request@v4 with: add-paths: | - Contents/Scripts/*.po + Contents/Strings/*.po token: ${{ secrets.GH_BOT_TOKEN }} # must trigger PR tests commit-message: New localization template branch: localize/update diff --git a/.github/workflows/python-tests.yml b/.github/workflows/python-tests.yml index 2248c74..55c5e1b 100644 --- a/.github/workflows/python-tests.yml +++ b/.github/workflows/python-tests.yml @@ -19,9 +19,7 @@ jobs: uses: actions/checkout@v3 - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: '2.7' + uses: LizardByte/.github/actions/setup_python2@nightly - name: Install python dependencies shell: bash @@ -30,8 +28,10 @@ jobs: python -m pip --no-python-version-warning --disable-pip-version-check install --upgrade \ pip setuptools requests python -m pip --no-python-version-warning --disable-pip-version-check install -r requirements-dev.txt - python -m pip --no-python-version-warning --disable-pip-version-check install -r requirements.txt + python -m pip --no-python-version-warning --disable-pip-version-check install \ + --target=./Contents/Libraries/Shared -r requirements.txt --no-warn-script-location - name: Test with pytest + shell: bash # our Python 2.7 setup action doesn't support PowerShell run: | python -m pytest -v diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 086d61f..a05ea65 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -11,6 +11,12 @@ build: os: ubuntu-20.04 tools: python: "2.7" + jobs: + pre_build: + - python ./scripts/build_plist.py + post_build: + - rstcheck -r . # lint rst files + # - rstfmt --check --diff -w 120 . # check rst formatting # Build documentation in the docs/ directory with Sphinx sphinx: @@ -25,4 +31,3 @@ python: install: - requirements: requirements.txt # plugin requirements - requirements: requirements-dev.txt # docs requirements - system_packages: true diff --git a/Contents/Code/const.py b/Contents/Code/const.py index 8184096..892c633 100644 --- a/Contents/Code/const.py +++ b/Contents/Code/const.py @@ -9,10 +9,20 @@ else: # the code is running outside of Plex from plexhints.core_kit import Core # core kit -bundle_identifier = 'dev.lizardbyte.plugger' +# plex constants app_support_directory = Core.app_support_path +plex_base_url = 'http://127.0.0.1:32400' +plex_token = os.environ.get('PLEXTOKEN') plugin_directory = os.path.join(app_support_directory, 'Plug-ins') plugin_logs_directory = os.path.join(app_support_directory, 'Logs', 'PMS Plugin Logs') +plugin_support_directory = os.path.join(app_support_directory, 'Plug-in Support') +plugin_support_caches_directory = os.path.join(plugin_support_directory, 'Caches') +plugin_support_data_directory = os.path.join(plugin_support_directory, 'Data') +plugin_support_databases_directory = os.path.join(plugin_support_directory, 'Databases') +plugin_support_metadata_combination_directory = os.path.join(plugin_support_directory, 'Metadata Combination') +plugin_support_preferences_directory = os.path.join(plugin_support_directory, 'Preferences') system_plugins_directory = Core.bundled_plugins_path -plex_base_url = 'http://127.0.0.1:32400' -plex_token = os.environ.get('PLEXTOKEN') + +# plugger constants +bundle_identifier = 'dev.lizardbyte.plugger' +plugger_data_directory = os.path.join(plugin_support_data_directory, bundle_identifier) diff --git a/Contents/Code/plugin_manager.py b/Contents/Code/plugin_manager.py new file mode 100644 index 0000000..63378d6 --- /dev/null +++ b/Contents/Code/plugin_manager.py @@ -0,0 +1,58 @@ +# plex debugging +try: + import plexhints # noqa: F401 +except ImportError: + pass +else: # the code is running outside of Plex + from plexhints.log_kit import Log # log kit + +# local imports +from const import plugger_data_directory, plugin_directory + +# servers version newer than 1.13 cannot view plugin routes, maybe we can do something with this later +# https://www.reddit.com/r/PleX/comments/ig64mz/comment/jhk5jbu/?utm_source=share&utm_medium=web2x&context=3 + + +def initialize_install(plugin_data): + # type: (dict) -> bool + """ + Initialize the plugin installation process. + + Parses the plugin data for further processing depending on the conditions. + + Parameters + ---------- + plugin_data : dict + The plugin data to process. + + Returns + ------- + bool + Whether or not the plugin was successfully installed/migrated/updated. + """ + Log.Debug("{}: {}".format("plugger_support_directory", plugger_data_directory)) + Log.Debug("{}: {}".format("plugin_directory", plugin_directory)) + + Log.Debug('Initializing plugin installation process for "{}"'.format(plugin_data['plugin']['full_name'])) + for k, v in plugin_data.items(): + Log.Debug("{}: {}".format(k, v)) + return True + + +def uninstall_plugin(plugin_name): + # type: (str) -> bool + """ + Uninstall a plugin. + + Parameters + ---------- + plugin_name : str + The name of the plugin to uninstall. + + Returns + ------- + bool + Whether or not the plugin was successfully uninstalled. + """ + Log.Debug("Uninstalling plugin: {}".format(plugin_name)) + return True diff --git a/Contents/Code/webapp.py b/Contents/Code/webapp.py index d9d671c..bbfb8e4 100644 --- a/Contents/Code/webapp.py +++ b/Contents/Code/webapp.py @@ -22,19 +22,24 @@ from flask_babel import Babel import polib import requests +from werkzeug.utils import secure_filename # local imports from const import bundle_identifier, plex_base_url, plex_token, plugin_directory, plugin_logs_directory, \ system_plugins_directory import plugin_manager +bundle_path = Core.bundle_path +if bundle_path.endswith('test.bundle'): + # use current directory instead, to allow for testing outside of Plex + bundle_path = os.getcwd() # setup flask app app = Flask( import_name=__name__, - root_path=os.path.join(Core.bundle_path, 'Contents', 'Resources', 'web'), - static_folder=os.path.join(Core.bundle_path, 'Contents', 'Resources', 'web'), - template_folder=os.path.join(Core.bundle_path, 'Contents', 'Resources', 'web', 'templates') + root_path=os.path.join(bundle_path, 'Contents', 'Resources', 'web'), + static_folder=os.path.join(bundle_path, 'Contents', 'Resources', 'web'), + template_folder=os.path.join(bundle_path, 'Contents', 'Resources', 'web', 'templates') ) # remove extra lines rendered jinja templates @@ -50,7 +55,7 @@ configure_jinja=True ) -app.config['BABEL_TRANSLATION_DIRECTORIES'] = os.path.join(Core.bundle_path, 'Contents', 'Strings') +app.config['BABEL_TRANSLATION_DIRECTORIES'] = os.path.join(bundle_path, 'Contents', 'Strings') # setup logging for flask Log.Info('Adding flask log handlers to plex plugin logger') @@ -159,13 +164,13 @@ def stop_server(): @app.route('/', methods=["GET"]) -@app.route('/home/', methods=["GET"]) +@app.route('/home', methods=["GET"]) def home(): # type: () -> render_template """ Serve the webapp home page. - .. todo:: This documentation needs to be improved. + This page is where most of the functionality for Plugger is provided. Returns ------- @@ -208,11 +213,14 @@ def image(img): >>> image('favicon.ico') """ directory = os.path.join(app.static_folder, 'images') - filename = img + filename = os.path.basename(secure_filename(filename=img)) # sanitize the input if os.path.isfile(os.path.join(directory, filename)): - file_extension = filename.split('.')[-1] - return send_from_directory(directory=directory, filename=filename, mimetype=mime_type_map[file_extension]) + file_extension = filename.rsplit('.', 1)[-1] + if file_extension in mime_type_map: + return send_from_directory(directory=directory, filename=filename, mimetype=mime_type_map[file_extension]) + else: + return Response(response='Invalid file type', status=400, mimetype='text/plain') else: return Response(response='Image not found', status=404, mimetype='text/plain') @@ -392,7 +400,7 @@ def log_stream(plugin_identifier): return Response(combined_log, mimetype="text/plain", content_type="text/event-stream") -@app.route('/status/', methods=["GET"]) +@app.route('/status', methods=["GET"]) def status(): # type: () -> dict """ @@ -452,7 +460,7 @@ def thumbnail(plugin_identifier): mimetype=mime_type_map[image_extension]) -@app.route("/translations/", methods=["GET"]) +@app.route("/translations", methods=["GET"]) def translations(): # type: () -> Response """ diff --git a/Contents/DefaultPrefs.json b/Contents/DefaultPrefs.json index b4ee560..43ab2ba 100644 --- a/Contents/DefaultPrefs.json +++ b/Contents/DefaultPrefs.json @@ -2,7 +2,7 @@ { "id": "enum_locale", "type": "enum", - "label": "Locale", + "label": "Web UI Locale", "default": "en", "values": [ "de", diff --git a/Contents/Resources/web/templates/home.html b/Contents/Resources/web/templates/home.html index 79f8fa9..3ce543f 100644 --- a/Contents/Resources/web/templates/home.html +++ b/Contents/Resources/web/templates/home.html @@ -101,7 +101,7 @@