├── .editorconfig ├── .github ├── plugin-repo-labels.yaml ├── release-drafter.adoc ├── release-drafter.yml ├── renovate.json └── workflows │ ├── build.yaml │ ├── bump-version.yaml │ ├── changelog.yaml │ ├── command-dispatch.yaml │ ├── command-rebase.yaml │ ├── publish-unstable.yaml │ ├── publish.yaml │ ├── scan-codeql.yaml │ ├── sync-labels.yaml │ └── test.yaml ├── .gitignore ├── .gitmodules ├── README.md ├── build_all.sh ├── build_plugin.sh ├── show_drafts.sh ├── show_issues.sh ├── show_pullrequests.sh └── update_submodules.py /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: https://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | [*] 7 | indent_style = space 8 | indent_size = 4 9 | end_of_line = lf 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | 14 | [*.{yaml,yml,json}] 15 | tab_width = 2 16 | indent_size = 2 17 | -------------------------------------------------------------------------------- /.github/plugin-repo-labels.yaml: -------------------------------------------------------------------------------- 1 | # A central configuration of labels that should get propagated across all repos with a label-sync workflow 2 | 3 | # General Purpose Labels 4 | # 5 | # Labels applicable for the general development workflow 6 | - name: major-feature 7 | color: '003F00' 8 | description: This PR introduces a major new feature 9 | aliases: 10 | - major-feature 11 | - major-enhancement 12 | 13 | - name: major-bug 14 | color: 'FF1E0D' 15 | description: This PR fixes a major bug 16 | 17 | - name: deprecated 18 | color: 'FEC111' 19 | description: This PR marks a feature, function or other public API element as deprecated 20 | 21 | - name: removed 22 | color: 'd93f0b' 23 | description: This PR removes a feature, function or other public API element 24 | 25 | - name: reverted 26 | color: 'f05032' 27 | description: This PR reverts a commit or multiple commits 28 | aliases: 29 | - revert 30 | 31 | - name: breaking 32 | color: 'B60205' 33 | description: This PR introduces breaking changes 34 | 35 | - name: feature 36 | color: '164916' 37 | description: This PR or Issue requests or introduces a new feature 38 | aliases: 39 | - feature 40 | - enhancement 41 | 42 | - name: bug 43 | color: 'd73a4a' 44 | description: This PR or Issue describes or fixes something that isn't working 45 | aliases: 46 | - bug 47 | - fix 48 | - bugfix 49 | - regression 50 | 51 | - name: documentation 52 | color: '006699' 53 | description: This PR or Issue aims to improve or add to documentation 54 | 55 | - name: tests 56 | color: '25A162' 57 | description: This PR adds or imposes tests (e.g. coverage, quality, ...) 58 | aliases: 59 | - test 60 | - tests 61 | 62 | 63 | # Repository Maintenance Labels 64 | # 65 | # Labels used for PRs and Issues relevant for repo maintenance 66 | - name: wontfix 67 | color: 'a2eeef' 68 | description: This Issue contains a request or 'bug' that wont be fixed (e.g. out-of-scope, not-an-issue, ...) 69 | 70 | - name: duplicate 71 | color: 'cfd3d7' 72 | description: This Issue or PR is a duplicate of an existing Issue or PR 73 | 74 | - name: help wanted 75 | color: '008672' 76 | description: This Issue or PR requires extra attention and/or requires external help 77 | aliases: 78 | - help wanted 79 | - help-wanted 80 | 81 | - name: good first issue 82 | color: '7057ff' 83 | description: This Issue contains a requirement easy to be picked up by project newcomers 84 | aliases: 85 | - good first issue 86 | - good-first-issue 87 | 88 | - name: confirmed 89 | color: 'a5e569' 90 | description: This Issue describes a bug that has been confirmed by a org member 91 | 92 | - name: invalid 93 | color: 'e4e669' 94 | description: This Issue describes an invalid request or bug report 95 | 96 | - name: question 97 | color: 'd876e3' 98 | description: This Issue contains a question 99 | 100 | - name: blocked 101 | color: '8e0900' 102 | description: This PR is blocked due to a commented reason 103 | 104 | - name: chore 105 | color: '36566F' 106 | description: This PR contains repository maintenance changes 107 | 108 | - name: dependencies 109 | color: '1D76DB' 110 | description: This PR updates or changes a dependency file 111 | aliases: 112 | - dependency 113 | - dependencies 114 | 115 | - name: github-actions 116 | color: '000000' 117 | description: This PR updates or changes GH Actions used in this repo 118 | aliases: 119 | - github_actions 120 | 121 | - name: nuget 122 | color: '004880' 123 | description: This PR updates or changes some NuGet dependencies 124 | 125 | - name: ci 126 | color: 'FFFF09' 127 | description: This PR updates or changes something CI related 128 | aliases: 129 | - ci 130 | - build 131 | 132 | - name: release-prep 133 | color: 'e0e0e0' 134 | description: This PR is a meta PR to prepare for the next release 135 | 136 | # Release Drafter Labels 137 | # 138 | # these labels are used to control certain features of Release Drafter 139 | - name: skip-changelog 140 | color: 'e0e0e0' 141 | description: This PR gets ignored by the Release Drafter workflow 142 | -------------------------------------------------------------------------------- /.github/release-drafter.adoc: -------------------------------------------------------------------------------- 1 | [[release-drafter]] 2 | = Release Drafter 3 | :toc: 4 | :toc-placement: preamble 5 | :toclevels: 3 6 | 7 | link:https://github.com/toolmantim/release-drafter[Release Drafter] is a tool and GitHub app which helps to automate the management of releases notes. 8 | This tool generates changelog drafts using pull request metadata (commit headers, links, etc.) and then suggest a changelog draft in GitHub Releases. 9 | 10 | This page provides information about how to use it. 11 | 12 | == Usage 13 | 14 | Despite the availability of Release Drafter as a GitHub app it is preferred to use the GitHub Action approach. 15 | The reason behind this is that the GitHub app does not produce any logs which would be available to plugin maintainers, 16 | and hence make it more difficult to troubleshoot errors if they occur. 17 | 18 | === Enabling Release Drafter GitHub Action in a Repository 19 | 20 | Have a look to the sample configuration available in the link:https://github.com/jellyfin/jellyfin-plugin-ldapauth/blob/master/.github/workflows/update-release-draft.yml[LDAP-Auth Plugin]. 21 | 22 | === Configuring Release Drafter 23 | 24 | After enabling RD, it needs to be configured in `.github/release-drafter.yml` in the master branch of your repository. 25 | The Jellyfin project provides a link:./release-drafter.yml[Global Configuration file], so a minimal configuration looks like this one: 26 | 27 | [source,yml] 28 | ---- 29 | _extends: jellyfin-meta-plugins 30 | #OPTIONAL: if your plugin uses a more suphisticated versioning update this acordingly 31 | # name-template: Version $NEXT_MINOR_VERSION 32 | # tag-template: v$NEXT_MAJOR_VERSION 33 | # version-template: $MAJOR 34 | 35 | #FIXME: overwrite the template so that the you dont have to manually update the download links 36 | # when releasing (see the example in the LDAP-Auth plugin mentioned above) 37 | # template: | 38 | # 39 | # 40 | # 41 | # ## :sparkles: What's New 42 | # 43 | # $CHANGES 44 | ---- 45 | 46 | All global settings can be overridden in repositories. 47 | Or you can write your own configuration from scratch if needed. 48 | See the link:https://github.com/toolmantim/release-drafter/blob/master/README.md[Release Drafter Documentation] for guidelines. 49 | If a change you need is a common use-case for Jellyfin, it is recommended to submit a pull request to the link:./release-drafter.yml[Global Configuration file] 50 | 51 | ==== Global Configuration Notes 52 | 53 | There are some considerations about the default configuration: 54 | 55 | * Jellyfin plugins can use different versioning formats. 56 | Release Drafter defaults to link:https://semver.org/[semver], but the majority of Jellyfin plugins use only the major version number. 57 | We use it as a default in the global configuration, but it can be overridden (e.g. `version-template: $MAJOR.$MINOR.$PATCH`) 58 | * Next version number will be used by default as a next release name. 59 | Another naming template can be defined by a `name-template` property. (e.g. `name-template: My Plugin v$NEXT_PATCH_VERSION`) 60 | * The `tag-template` is the template for the tag of the draft release, 61 | if you create a tag according to this template before releasing the draft it will be pre-selected for the release. 62 | It also is templated in as the release tag if you creat a release from the draft manually, but can be overwritten. (e.g. `v$NEXT_PATCH_VERSION`) 63 | * Finally, the `template` property itself represents the Markdown body of the GitHub Release. 64 | It has a default value provided by the template found within this repo, but should bew overwritten based on this template to include a download link. 65 | (if you are unsure of what this means have a look at a plugin already using it e.g. link:https://github.com/jellyfin/jellyfin-plugin-ldapauth/blob/master/.github/release-drafter.yml[LDAP-Auth Plugin]) 66 | 67 | === Releasing a Plugin with Release Drafter 68 | 69 | 1. Make sure that all pull requests in the release are properly labeled. 70 | See the link:./release-drafter.yml[Global Configuration file] for available labels 71 | 2. (optional) crate a git tag locally and push it to your plugin repo 72 | 3. Go to `${YOUR_REPO}/releases` and click "Edit" on the draft release. 73 | 4. Edit the tag, point it to a tag or a release commit created by the common release flow 74 | ** Tags represent a text field with auto-completion. Tag names can be also copy-pasted from `${YOUR_REPO}/tags` 75 | ** Recent commits can be selected from a dropdown 76 | ** (optional) if you pushed a tag manually you should see the text *Existing tag* 77 | 5. Edit the release name, if needed 78 | 6. Review and copy-edit the changelog 79 | ** First release draft will likely contain all history from the beginning of the repository, 80 | you will need to remove entries corresponding to PRs included in prior releases. 81 | If all new PRs are categorized, just delete everything before the first header. 82 | ** Release drafter is designed to add one entry per pull request. 83 | If a pull request includes multiple changes to be noted, manual editing will be needed 84 | 7. Click the _Publish_ button 85 | 86 | == Links 87 | 88 | * link:https://github.com/toolmantim/release-drafter/blob/master/README.md[Release Drafter Documentation] 89 | * link:https://github.com/jenkinsci/.github/blob/master/.github/release-drafter.adoc[Reference used for this Readme] -------------------------------------------------------------------------------- /.github/release-drafter.yml: -------------------------------------------------------------------------------- 1 | # Configuration for Release Drafter: https://github.com/toolmantim/release-drafter 2 | name-template: 'Version $NEXT_MAJOR_VERSION' 3 | # Most plugins within the Jellyfin Org uses a single-digit versioning. Can be replaced by semver: $MAJOR.$MINOR.$PATCH 4 | # https://github.com/release-drafter/release-drafter#next-version-variables 5 | tag-template: 'v$NEXT_MAJOR_VERSION' 6 | version-template: '$MAJOR' 7 | category-template: '### $TITLE' 8 | 9 | # Emoji reference: https://gitmoji.carloscuesta.me/ 10 | categories: 11 | - title: ':boom: Breaking changes' 12 | labels: 13 | - breaking 14 | - title: ':fire: Removed' 15 | labels: 16 | - removed 17 | - title: ':rewind: Reverted Changes' 18 | labels: 19 | - revert 20 | - reverted 21 | - title: ':rocket: Major features and improvements' 22 | labels: 23 | - major-enhancement 24 | - major-feature 25 | - title: ':ambulance: Major bug fixes' 26 | labels: 27 | - major-bug 28 | - title: ':wastebasket:️ Deprecated' 29 | label: deprecated 30 | - title: ':tada: New features and improvements' 31 | labels: 32 | - enhancement 33 | - feature 34 | - title: ':bug: Bug Fixes' 35 | labels: 36 | - bug 37 | - fix 38 | - bugfix 39 | - regression 40 | - title: ':white_check_mark: Tests' 41 | labels: 42 | - test 43 | - tests 44 | - title: ':gear: Code or Repo Maintenance' 45 | labels: 46 | - chore 47 | - cleanup 48 | - title: ':memo: Documentation updates' 49 | labels: 50 | - documentation 51 | - title: ':arrow_up: Dependency updates' 52 | labels: 53 | - dependencies # Default label used by Dependabot 54 | - dependency 55 | - title: ':construction_worker: CI & build changes' 56 | labels: 57 | - ci 58 | - build 59 | exclude-labels: 60 | - no-changelog 61 | - skip-changelog 62 | - invalid 63 | 64 | autolabeler: 65 | - label: ci 66 | files: 67 | - '.github/workflows/*' 68 | - '.github/dependabot.yml' 69 | branch: 70 | - '/ci\/.+/' 71 | - label: documentation 72 | files: 73 | - '*.md' 74 | branch: 75 | - '/docs?\/.+/' 76 | - label: bug 77 | branch: 78 | - '/fix\/.+/' 79 | title: 80 | - '/fix/i' 81 | - label: chore 82 | branch: 83 | - '/chore\/.+/' 84 | title: 85 | - '/chore/i' 86 | - label: feature 87 | branch: 88 | - '/feature\/.+/' 89 | 90 | template: |- 91 | 92 | 93 | 94 | ## :sparkles: What's New 95 | 96 | $CHANGES 97 | 98 | -------------------------------------------------------------------------------- /.github/renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "https://docs.renovatebot.com/renovate-schema.json", 3 | "extends": [ 4 | "github>jellyfin/.github//renovate-presets/default", 5 | ":dependencyDashboard" 6 | ], 7 | "packageRules": [ 8 | { 9 | "description": "Auto update the Git submodules of this repository and auto merge the branches", 10 | "matchManagers": ["git-submodules"], 11 | "addLabels": ["git-submodules"], 12 | "automerge": true, 13 | "ignoreTests": true, 14 | "automergeType": "branch" 15 | } 16 | ], 17 | "git-submodules": { 18 | "enabled": true 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.github/workflows/build.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | dotnet-version: 5 | required: false 6 | default: "8.0.x" 7 | description: "The .NET version to setup for the build" 8 | type: string 9 | dotnet-target: 10 | required: false 11 | default: "net8.0" 12 | description: "The .NET target to set for JPRM" 13 | type: string 14 | 15 | jobs: 16 | build: 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout Repository 20 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 21 | 22 | - name: Setup .NET 23 | uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0 24 | with: 25 | dotnet-version: "${{ inputs.dotnet-version }}" 26 | 27 | - name: Build Jellyfin Plugin 28 | uses: oddstr13/jellyfin-plugin-repository-manager@9497a0a499416cc572ed2e07a391d9f943a37b4d # v1.1.1 29 | id: jprm 30 | with: 31 | dotnet-target: "${{ inputs.dotnet-target }}" 32 | 33 | - name: Upload Artifact 34 | uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4 35 | with: 36 | name: build-artifact 37 | retention-days: 30 38 | if-no-files-found: error 39 | path: ${{ steps.jprm.outputs.artifact }} 40 | -------------------------------------------------------------------------------- /.github/workflows/bump-version.yaml: -------------------------------------------------------------------------------- 1 | # DEPRECATED: Please use / rely on the changelog workflow as that works with protected branches 2 | 3 | on: 4 | workflow_call: 5 | inputs: 6 | csproj-name: 7 | required: true 8 | type: string 9 | csproj-folder: 10 | required: false 11 | type: string 12 | is-unstable: 13 | required: false 14 | default: false 15 | type: boolean 16 | default-branch: 17 | required: false 18 | default: "master" 19 | description: "The branch to commit the version bump to" 20 | type: string 21 | commiter-name: 22 | required: false 23 | default: "jellyfin-bot" 24 | description: "This param overwrites the version bump committing git user.name" 25 | type: string 26 | commiter-email: 27 | required: false 28 | default: "team@jellyfin.org" 29 | description: "This param overwrites the version bump committing git user.email" 30 | type: string 31 | 32 | 33 | jobs: 34 | bump-version: 35 | runs-on: ubuntu-latest 36 | if: ${{ ! inputs.isUnstable }} 37 | steps: 38 | - name: Checkout Repository 39 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 40 | 41 | - name: Read current version 42 | run: |- 43 | echo "CURRENT_VERSION=$(yq eval '.version' build.yaml)" 44 | echo "CURRENT_VERSION=$(yq eval '.version' build.yaml)" >> $GITHUB_ENV 45 | 46 | - name: Set next version 47 | run: |- 48 | # ensure even a version in schema 'x.y.z.b' is supported, yet only inc and persists the 'x' value further 49 | C_VERSION=${CURRENT_VERSION%%.*} 50 | CS_PROJ_NAME="${{ inputs.csproj-name }}" 51 | CS_PROJ_FOLDER="${{ inputs.csproj-folder }}" 52 | 53 | export NEXT_VERSION=$(( ${C_VERSION} + 1 )) 54 | echo "NEXT_VERSION=${NEXT_VERSION}" 55 | echo "NEXT_VERSION=${NEXT_VERSION}" >> $GITHUB_ENV 56 | 57 | yq eval '.version = env(NEXT_VERSION)' -i build.yaml 58 | sed -i ${CS_PROJ_FOLDER:-$CS_PROJ_NAME}/${CS_PROJ_NAME}.csproj \ 59 | -e "s;.*;${NEXT_VERSION}.0.0.0;" \ 60 | -e "s;.*;${NEXT_VERSION}.0.0.0;" 61 | 62 | - name: Commit bump 63 | run: |- 64 | git config user.name "${{ inputs.commiter-name }}" 65 | git config user.email "${{ inputs.commiter-email }}" 66 | git commit -am "chore: prepare for next release (v${NEXT_VERSION})" 67 | git push origin "HEAD:refs/heads/${{ inputs.default-branch }}" 68 | -------------------------------------------------------------------------------- /.github/workflows/changelog.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | repository-name: 5 | required: true 6 | type: string 7 | commiter-name: 8 | required: false 9 | default: "jellyfin-bot" 10 | description: "This param overwrites the version bump committing git user.name" 11 | type: string 12 | commiter-email: 13 | required: false 14 | default: "team@jellyfin.org" 15 | description: "This param overwrites the version bump committing git user.email" 16 | type: string 17 | secrets: 18 | token: 19 | required: true 20 | 21 | jobs: 22 | update_release_draft: 23 | runs-on: ubuntu-latest 24 | if: ${{ github.repository == inputs.repository-name }} 25 | 26 | steps: 27 | # Drafts your next Release notes as Pull Requests are merged into "master" 28 | - name: Update Draft 29 | uses: release-drafter/release-drafter@3f0f87098bd6b5c5b9a36d49c41d998ea58f9348 # v6.0.0 30 | id: draft 31 | env: 32 | GITHUB_TOKEN: ${{ secrets.token }} 33 | 34 | - name: Set-up Environment 35 | run: |- 36 | TAG="${{ steps.draft.outputs.tag_name }}" 37 | echo "VERSION=${TAG#v}" >> $GITHUB_ENV 38 | cat << EOF | grep -P '^([*-] |###)' > cl.md 39 | ${{ steps.draft.outputs.body }} 40 | EOF 41 | sed -i -r 's/^(#+) (:.*:)? *(.*)$/\n\1 \3 \1/' cl.md 42 | sed -i -r 's/^\*/-/' cl.md 43 | echo "CHANGELOG<> $GITHUB_ENV 44 | cat cl.md >> $GITHUB_ENV 45 | echo "EOF" >> $GITHUB_ENV 46 | echo "HAS_CHANGES=$(grep -qie 'No changes$' cl.md && echo false || echo true)" >> $GITHUB_ENV 47 | rm cl.md 48 | echo "ABI_VERSION=$(curl -s https://api.jellyfin.org/openapi/jellyfin-openapi-stable.json | jq -r '.info.version').0" >> $GITHUB_ENV 49 | 50 | - name: Checkout Repository 51 | if: ${{ env.HAS_CHANGES == 'true' }} 52 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 53 | 54 | - name: Update build.yaml 55 | if: ${{ env.HAS_CHANGES == 'true' }} 56 | run: |- 57 | if [[ -f Directory.Build.props ]]; then 58 | # https://stackoverflow.com/a/57510475 59 | # https://docs.microsoft.com/en-us/visualstudio/msbuild/customize-your-build?view=vs-2022 60 | sed -i Directory.Build.props \ 61 | -e "s;.*;${VERSION}.0.0.0;" \ 62 | -e "s;.*;${VERSION}.0.0.0;" \ 63 | -e "s;.*;${VERSION}.0.0.0;" 64 | fi 65 | 66 | yq eval '.version = env(VERSION) | .targetAbi = env(ABI_VERSION) | .changelog = strenv(CHANGELOG) | .changelog style="literal"' -i build.yaml 67 | 68 | - name: Commit Changes 69 | if: ${{ env.HAS_CHANGES == 'true' }} 70 | run: |- 71 | git config user.name "${{ inputs.commiter-name }}" 72 | git config user.email "${{ inputs.commiter-email }}" 73 | git checkout -b prepare-${{ env.VERSION }} 74 | git commit -am "Bump version to ${{ env.VERSION }}" 75 | git push -f origin prepare-${{ env.VERSION }} 76 | 77 | - name: Create or Update PR 78 | if: ${{ env.HAS_CHANGES == 'true' }} 79 | uses: k3rnels-actions/pr-update@7d7d8852095b87e6fa255ced7433f1d79737e0b1 # v2.1.0 80 | with: 81 | token: ${{ secrets.token }} 82 | pr_title: Prepare for release ${{ steps.draft.outputs.tag_name }} 83 | pr_source: prepare-${{ env.VERSION }} 84 | pr_labels: 'release-prep,skip-changelog' 85 | pr_body: |- 86 | :robot: This is a generated PR to update version and changelog in `build.yaml`. 87 | --- 88 | ${{ env.CHANGELOG }} 89 | -------------------------------------------------------------------------------- /.github/workflows/command-dispatch.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | secrets: 4 | token: 5 | required: true 6 | 7 | jobs: 8 | launcher: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: Command Dispatch 12 | uses: peter-evans/slash-command-dispatch@13bc09769d122a64f75aa5037256f6f2d78be8c4 # v4.0.0 13 | with: 14 | token: ${{ secrets.token }} 15 | reaction-token: ${{ secrets.token }} 16 | permission: write 17 | issue-type: pull-request 18 | commands: |- 19 | rebase 20 | update-prep 21 | -------------------------------------------------------------------------------- /.github/workflows/command-rebase.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | rebase-head: 5 | required: true 6 | type: string 7 | repository-full-name: 8 | required: true 9 | type: string 10 | comment-id: 11 | required: true 12 | type: string 13 | secrets: 14 | token: 15 | required: true 16 | 17 | jobs: 18 | rebase: 19 | runs-on: ubuntu-latest 20 | steps: 21 | - name: Rebase PR 22 | uses: peter-evans/rebase@87c3fd9344792e51ab1c7494c3369620c84ed852 # v3.1.0 23 | id: rebase 24 | with: 25 | head: ${{ inputs.rebase-head }} 26 | 27 | - name: Add Success Reaction 28 | if: ${{ steps.rebase.outputs.rebased-count == 1 }} 29 | uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0 30 | with: 31 | token: ${{ secrets.token }} 32 | repository: ${{ inputs.repository-full-name }} 33 | comment-id: ${{ inputs.comment-id }} 34 | reaction-type: hooray 35 | 36 | - name: Add Failure Reaction 37 | if: ${{ steps.rebase.outputs.rebased-count == 0 || failure() }} 38 | uses: peter-evans/create-or-update-comment@71345be0265236311c031f5c7866368bd1eff043 # v4.0.0 39 | with: 40 | token: ${{ secrets.token }} 41 | repository: ${{ inputs.repository-full-name }} 42 | comment-id: ${{ inputs.comment-id }} 43 | reaction-type: confused, -1 44 | -------------------------------------------------------------------------------- /.github/workflows/publish-unstable.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | dotnet-version: 5 | required: false 6 | default: "9.0.x" 7 | description: "The .NET version to setup for the build" 8 | type: string 9 | dotnet-target: 10 | required: false 11 | default: "net9.0" 12 | description: "The .NET target to set for JPRM" 13 | type: string 14 | secrets: 15 | deploy-host: 16 | required: true 17 | deploy-user: 18 | required: true 19 | deploy-key: 20 | required: true 21 | token: 22 | required: true 23 | 24 | jobs: 25 | build: 26 | runs-on: ubuntu-latest 27 | steps: 28 | - name: Checkout Repository 29 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 30 | with: 31 | ref: 'unstable' 32 | 33 | - name: Setup .NET 34 | uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0 35 | with: 36 | dotnet-version: "${{ inputs.dotnet-version }}" 37 | 38 | - name: Update prerelease dependencies 39 | id: unstable 40 | run: | 41 | dotnet nuget add source --username jellyfin-bot --password ${{ secrets.token }} --store-password-in-clear-text --name jellyfin-pre "https://nuget.pkg.github.com/jellyfin/index.json" 42 | dotnet tool install --global dotnet-outdated-tool 43 | dotnet outdated -pre Always -u -inc Jellyfin 44 | 45 | - name: Generate version number using date and run number 46 | id: version-creator 47 | run: | 48 | pluginVersion=`yq '.version' build.yaml | tr -d '"'` 49 | buildDay=`date +%y%m` 50 | runNum=$GITHUB_RUN_NUMBER 51 | ver="${pluginVersion}.${buildDay}.${runNum}.0" 52 | echo "PLUGIN_VERSION=$ver" >> $GITHUB_OUTPUT 53 | 54 | - name: Build Jellyfin Plugin 55 | uses: oddstr13/jellyfin-plugin-repository-manager@9497a0a499416cc572ed2e07a391d9f943a37b4d # v1.1.1 56 | id: jprm 57 | with: 58 | dotnet-target: "${{ inputs.dotnet-target }}" 59 | version: ${{ steps.version-creator.outputs.PLUGIN_VERSION }} 60 | 61 | - name: Upload Artifact 62 | uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 63 | with: 64 | name: build-artifact 65 | retention-days: 30 66 | if-no-files-found: error 67 | path: ${{ steps.jprm.outputs.artifact }} 68 | 69 | upload: 70 | needs: 71 | - build 72 | runs-on: ubuntu-latest 73 | steps: 74 | - name: Download Artifact 75 | uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 76 | with: 77 | name: build-artifact 78 | 79 | - name: Ensure Destination Path Exists 80 | uses: appleboy/ssh-action@7eaf76671a0d7eec5d98ee897acda4f968735a17 # v1.2.0 81 | if: ${{ contains(github.repository, 'jellyfin/') }} 82 | with: 83 | host: ${{ secrets.deploy-host }} 84 | username: ${{ secrets.deploy-user }} 85 | key: ${{ secrets.deploy-key }} 86 | script_stop: true 87 | script: |- 88 | mkdir -p "/srv/incoming/plugin/${{ github.repository }}/${{ inputs.version }}" || exit 1 89 | 90 | - name: Upload Jellyfin Plugin Repository Assets 91 | uses: burnett01/rsync-deployments@0dc935cdecc5f5e571865e60d2a6cdc673704823 # tag=5.2 92 | if: ${{ contains(github.repository, 'jellyfin/') }} 93 | with: 94 | switches: -vrptz 95 | path: ./*.zip 96 | remote_path: /srv/incoming/plugin/${{ github.repository }}/${{ inputs.version }} 97 | remote_host: ${{ secrets.deploy-host }} 98 | remote_user: ${{ secrets.deploy-user }} 99 | remote_key: ${{ secrets.deploy-key }} 100 | 101 | publish: 102 | needs: 103 | - upload 104 | runs-on: ubuntu-latest 105 | if: ${{ contains(github.repository, 'jellyfin/') }} 106 | env: 107 | JELLYFIN_REPO: "/srv/repository/main/plugin-unstable/manifest.json" 108 | JELLYFIN_REPO_URL: "https://repo.jellyfin.org/files/plugin-unstable/" 109 | steps: 110 | - name: Update Plugin Manifest 111 | uses: appleboy/ssh-action@7eaf76671a0d7eec5d98ee897acda4f968735a17 # v1.2.0 112 | with: 113 | host: ${{ secrets.deploy-host }} 114 | username: ${{ secrets.deploy-user }} 115 | key: ${{ secrets.deploy-key }} 116 | script_stop: true 117 | envs: JELLYFIN_REPO,JELLYFIN_REPO_URL 118 | script: |- 119 | lockfile="/run/lock/jprm.lock" 120 | pushd "/srv/incoming/plugin/${{ github.repository }}/${{ inputs.version }}" || exit 1 121 | ( 122 | flock -x 300 123 | sudo /usr/local/bin/jprm --verbosity=debug repo add --url="${JELLYFIN_REPO_URL}" "${JELLYFIN_REPO}" ./*.zip || exit 1 124 | ) 300>${lockfile} 125 | popd || exit 1 126 | rm -r "/srv/incoming/plugin/${{ github.repository }}/${{ inputs.version }}" || exit 1 127 | -------------------------------------------------------------------------------- /.github/workflows/publish.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | version: 5 | required: true 6 | type: string 7 | is-unstable: 8 | required: false 9 | default: false 10 | type: boolean 11 | dotnet-version: 12 | required: false 13 | default: "8.0.x" 14 | description: "The .NET version to setup for the build" 15 | type: string 16 | dotnet-target: 17 | required: false 18 | default: "net8.0" 19 | description: "The .NET target to set for JPRM" 20 | type: string 21 | secrets: 22 | deploy-host: 23 | required: true 24 | deploy-user: 25 | required: true 26 | deploy-key: 27 | required: true 28 | 29 | 30 | jobs: 31 | build: 32 | runs-on: ubuntu-latest 33 | steps: 34 | - name: Checkout Repository 35 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 36 | 37 | - name: Setup .NET 38 | uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0 39 | with: 40 | dotnet-version: "${{ inputs.dotnet-version }}" 41 | 42 | - name: Build Jellyfin Plugin 43 | uses: oddstr13/jellyfin-plugin-repository-manager@9497a0a499416cc572ed2e07a391d9f943a37b4d # v1.1.1 44 | id: jprm 45 | with: 46 | dotnet-target: "${{ inputs.dotnet-target }}" 47 | 48 | - name: Upload Artifact 49 | uses: actions/upload-artifact@65c4c4a1ddee5b72f698fdd19549f0f0fb45cf08 # v4.6.0 50 | with: 51 | name: build-artifact 52 | retention-days: 30 53 | if-no-files-found: error 54 | path: ${{ steps.jprm.outputs.artifact }} 55 | 56 | upload: 57 | needs: 58 | - build 59 | runs-on: ubuntu-latest 60 | steps: 61 | - name: Download Artifact 62 | uses: actions/download-artifact@fa0a91b85d4f404e444e00e005971372dc801d16 # v4.1.8 63 | with: 64 | name: build-artifact 65 | 66 | - name: Prepare GH Release Assets 67 | run: |- 68 | for file in ./*; do 69 | md5sum ${file#./} >> ${file%.*}.md5 70 | sha256sum ${file#./} >> ${file%.*}.sha256 71 | done 72 | ls -l 73 | 74 | - name: Upload GH Release Assets 75 | uses: shogo82148/actions-upload-release-asset@8482bd769644976d847e96fb4b9354228885e7b4 # v1.7.8 76 | with: 77 | upload_url: ${{ github.event.release.upload_url }} 78 | asset_path: ./* 79 | 80 | - name: Ensure Destination Path Exists 81 | uses: appleboy/ssh-action@7eaf76671a0d7eec5d98ee897acda4f968735a17 # v1.2.0 82 | if: ${{ contains(github.repository, 'jellyfin/') }} 83 | with: 84 | host: ${{ secrets.deploy-host }} 85 | username: ${{ secrets.deploy-user }} 86 | key: ${{ secrets.deploy-key }} 87 | script_stop: true 88 | script: |- 89 | mkdir -p "/srv/incoming/plugin/${{ github.repository }}/${{ inputs.version }}" || exit 1 90 | 91 | - name: Upload Jellyfin Plugin Repository Assets 92 | uses: burnett01/rsync-deployments@0dc935cdecc5f5e571865e60d2a6cdc673704823 # tag=5.2 93 | if: ${{ contains(github.repository, 'jellyfin/') }} 94 | with: 95 | switches: -vrptz 96 | path: ./*.zip 97 | remote_path: /srv/incoming/plugin/${{ github.repository }}/${{ inputs.version }} 98 | remote_host: ${{ secrets.deploy-host }} 99 | remote_user: ${{ secrets.deploy-user }} 100 | remote_key: ${{ secrets.deploy-key }} 101 | 102 | publish: 103 | needs: 104 | - upload 105 | runs-on: ubuntu-latest 106 | if: ${{ contains(github.repository, 'jellyfin/') }} 107 | env: 108 | JELLYFIN_REPO: "/srv/repository/main/plugin/manifest.json" 109 | JELLYFIN_REPO_URL: "https://repo.jellyfin.org/files/plugin/" 110 | steps: 111 | - name: Update Plugin Manifest 112 | uses: appleboy/ssh-action@7eaf76671a0d7eec5d98ee897acda4f968735a17 # v1.2.0 113 | with: 114 | host: ${{ secrets.deploy-host }} 115 | username: ${{ secrets.deploy-user }} 116 | key: ${{ secrets.deploy-key }} 117 | script_stop: true 118 | envs: JELLYFIN_REPO,JELLYFIN_REPO_URL 119 | script: |- 120 | lockfile="/run/lock/jprm.lock" 121 | pushd "/srv/incoming/plugin/${{ github.repository }}/${{ inputs.version }}" || exit 1 122 | ( 123 | flock -x 300 124 | sudo /usr/local/bin/jprm --verbosity=debug repo add --url="${JELLYFIN_REPO_URL}" "${JELLYFIN_REPO}" ./*.zip || exit 1 125 | ) 300>${lockfile} 126 | popd || exit 1 127 | rm -r "/srv/incoming/plugin/${{ github.repository }}/${{ inputs.version }}" || exit 1 128 | -------------------------------------------------------------------------------- /.github/workflows/scan-codeql.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | repository-name: 5 | required: true 6 | type: string 7 | dotnet-version: 8 | required: false 9 | default: "8.0.x" 10 | description: "The .NET version to setup for the build" 11 | type: string 12 | 13 | jobs: 14 | analyze: 15 | name: Analyze 16 | runs-on: ubuntu-latest 17 | if: ${{ github.repository == inputs.repository-name }} 18 | 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | language: [ 'csharp' ] 23 | 24 | steps: 25 | - name: Checkout repository 26 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 27 | 28 | - name: Setup .NET 29 | uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0 30 | with: 31 | dotnet-version: "${{ inputs.dotnet-version }}" 32 | 33 | - name: Initialize CodeQL 34 | uses: github/codeql-action/init@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 35 | with: 36 | languages: ${{ matrix.language }} 37 | queries: +security-and-quality 38 | 39 | - name: Autobuild 40 | uses: github/codeql-action/autobuild@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 41 | 42 | - name: Perform CodeQL Analysis 43 | uses: github/codeql-action/analyze@b6a472f63d85b9c78a3ac5e89422239fc15e9b3c # v3.28.1 44 | -------------------------------------------------------------------------------- /.github/workflows/sync-labels.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | secrets: 4 | token: 5 | required: true 6 | 7 | jobs: 8 | labels: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: EndBug/label-sync@52074158190acb45f3077f9099fea818aa43f97a # v2.3.3 13 | with: 14 | config-file: https://raw.githubusercontent.com/jellyfin/jellyfin-meta-plugins/master/.github/plugin-repo-labels.yaml 15 | delete-other-labels: true 16 | token: ${{ secrets.token }} 17 | -------------------------------------------------------------------------------- /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | on: 2 | workflow_call: 3 | inputs: 4 | dotnet-version: 5 | required: false 6 | default: "8.0.x" 7 | description: "The .NET version to setup for the build" 8 | type: string 9 | 10 | jobs: 11 | test: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout Repository 15 | uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 16 | 17 | - name: Setup .NET 18 | uses: actions/setup-dotnet@87b7050bc53ea08284295505d98d2aa94301e852 # v4.2.0 19 | with: 20 | dotnet-version: "${{ inputs.dotnet-version }}" 21 | 22 | - name: Install dependencies 23 | run: dotnet restore 24 | 25 | - name: Build 26 | run: dotnet build --configuration Release --no-restore 27 | 28 | - name: Test 29 | run: dotnet test --no-restore --verbosity normal 30 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | artifacts/ 2 | test_repo/ 3 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "jellyfin-plugin-template"] 2 | path = jellyfin-plugin-template 3 | url = https://github.com/jellyfin/jellyfin-plugin-template 4 | [submodule "jellyfin-plugin-trakt"] 5 | path = jellyfin-plugin-trakt 6 | url = https://github.com/jellyfin/jellyfin-plugin-trakt 7 | [submodule "jellyfin-plugin-ldapauth"] 8 | path = jellyfin-plugin-ldapauth 9 | url = https://github.com/jellyfin/jellyfin-plugin-ldapauth 10 | [submodule "jellyfin-plugin-reports"] 11 | path = jellyfin-plugin-reports 12 | url = https://github.com/jellyfin/jellyfin-plugin-reports 13 | [submodule "jellyfin-plugin-bookshelf"] 14 | path = jellyfin-plugin-bookshelf 15 | url = https://github.com/jellyfin/jellyfin-plugin-bookshelf 16 | [submodule "jellyfin-plugin-opensubtitles"] 17 | path = jellyfin-plugin-opensubtitles 18 | url = https://github.com/jellyfin/jellyfin-plugin-opensubtitles 19 | [submodule "jellyfin-plugin-tvheadend"] 20 | path = jellyfin-plugin-tvheadend 21 | url = https://github.com/jellyfin/jellyfin-plugin-tvheadend 22 | [submodule "jellyfin-plugin-playbackreporting"] 23 | path = jellyfin-plugin-playbackreporting 24 | url = https://github.com/jellyfin/jellyfin-plugin-playbackreporting 25 | [submodule "jellyfin-plugin-tmdbboxsets"] 26 | path = jellyfin-plugin-tmdbboxsets 27 | url = https://github.com/jellyfin/jellyfin-plugin-tmdbboxsets 28 | [submodule "jellyfin-plugin-fanart"] 29 | path = jellyfin-plugin-fanart 30 | url = https://github.com/jellyfin/jellyfin-plugin-fanart 31 | [submodule "jellyfin-plugin-nextpvr"] 32 | path = jellyfin-plugin-nextpvr 33 | url = https://github.com/jellyfin/jellyfin-plugin-nextpvr 34 | [submodule "jellyfin-plugin-kodisyncqueue"] 35 | path = jellyfin-plugin-kodisyncqueue 36 | url = https://github.com/jellyfin/jellyfin-plugin-kodisyncqueue 37 | [submodule "jellyfin-plugin-artwork"] 38 | path = jellyfin-plugin-artwork 39 | url = https://github.com/jellyfin/jellyfin-plugin-artwork.git 40 | branch = master 41 | [submodule "jellyfin-plugin-anisearch"] 42 | path = jellyfin-plugin-anisearch 43 | url = https://github.com/jellyfin/jellyfin-plugin-anisearch.git 44 | branch = master 45 | [submodule "jellyfin-plugin-anilist"] 46 | path = jellyfin-plugin-anilist 47 | url = https://github.com/jellyfin/jellyfin-plugin-anilist.git 48 | branch = master 49 | [submodule "jellyfin-plugin-anidb"] 50 | path = jellyfin-plugin-anidb 51 | url = https://github.com/jellyfin/jellyfin-plugin-anidb.git 52 | branch = master 53 | [submodule "jellyfin-plugin-kitsu"] 54 | path = jellyfin-plugin-kitsu 55 | url = https://github.com/jellyfin/jellyfin-plugin-kitsu.git 56 | branch = master 57 | [submodule "jellyfin-plugin-tvmaze"] 58 | path = jellyfin-plugin-tvmaze 59 | url = https://github.com/jellyfin/jellyfin-plugin-tvmaze.git 60 | branch = master 61 | [submodule "jellyfin-plugin-tvdb"] 62 | path = jellyfin-plugin-tvdb 63 | url = https://github.com/jellyfin/jellyfin-plugin-tvdb.git 64 | branch = master 65 | [submodule "jellyfin-plugin-coverartarchive"] 66 | path = jellyfin-plugin-coverartarchive 67 | url = https://github.com/jellyfin/jellyfin-plugin-coverartarchive.git 68 | branch = master 69 | [submodule "jellyfin-plugin-webhook"] 70 | path = jellyfin-plugin-webhook 71 | url = https://github.com/jellyfin/jellyfin-plugin-webhook.git 72 | branch = master 73 | [submodule "jellyfin-plugin-opds"] 74 | path = jellyfin-plugin-opds 75 | url = https://github.com/jellyfin/jellyfin-plugin-opds.git 76 | branch = master 77 | [submodule "jellyfin-plugin-sessioncleaner"] 78 | path = jellyfin-plugin-sessioncleaner 79 | url = https://github.com/jellyfin/jellyfin-plugin-sessioncleaner.git 80 | branch = master 81 | [submodule "jellyfin-plugin-imvdb"] 82 | path = jellyfin-plugin-imvdb 83 | url = https://github.com/jellyfin/jellyfin-plugin-imvdb.git 84 | branch = master 85 | [submodule "jellyfin-plugin-simkl"] 86 | path = jellyfin-plugin-simkl 87 | url = https://github.com/jellyfin/jellyfin-plugin-simkl.git 88 | branch = master 89 | [submodule "jellyfin-plugin-vgmdb"] 90 | path = jellyfin-plugin-vgmdb 91 | url = https://github.com/jellyfin/jellyfin-plugin-vgmdb.git 92 | branch = master 93 | [submodule "jellyfin-plugin-discogs"] 94 | path = jellyfin-plugin-discogs 95 | url = https://github.com/jellyfin/jellyfin-plugin-discogs.git 96 | branch = master 97 | [submodule "jellyfin-plugin-dlna"] 98 | path = jellyfin-plugin-dlna 99 | url = https://github.com/jellyfin/jellyfin-plugin-dlna.git 100 | branch = master 101 | [submodule "jellyfin-plugin-subtitleextract"] 102 | path = jellyfin-plugin-subtitleextract 103 | url = https://github.com/jellyfin/jellyfin-plugin-subtitleextract.git 104 | branch = master 105 | [submodule "jellyfin-plugin-intros"] 106 | path = jellyfin-plugin-intros 107 | url = https://github.com/jellyfin/jellyfin-plugin-intros.git 108 | branch = master 109 | [submodule "jellyfin-plugin-transcodekiller"] 110 | path = jellyfin-plugin-transcodekiller 111 | url = https://github.com/jellyfin/jellyfin-plugin-transcodekiller.git 112 | branch = master 113 | [submodule "jellyfin-plugin-chapter-segments"] 114 | path = jellyfin-plugin-chapter-segments 115 | url = https://github.com/jellyfin/jellyfin-plugin-chapter-segments.git 116 | branch = master 117 | [submodule "jellyfin-plugin-lrclib"] 118 | path = jellyfin-plugin-lrclib 119 | url = https://github.com/jellyfin/jellyfin-plugin-lrclib.git 120 | branch = master 121 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Plugin tools 2 | ============ 3 | 4 | Dependencies 5 | ------------ 6 | 7 | - [hub](https://hub.github.com/) 8 | - [jprm](https://pypi.org/project/jprm/) (building) 9 | - dotnet (building) 10 | - git 11 | - bash 12 | - python3 13 | 14 | Tools 15 | ----- 16 | 17 | - `build_all.sh` 18 | Builds (and publishes) all plugins. 19 | - `build_plugin.sh` 20 | Builds (and publishes) a single plugin. 21 | - `show_drafts.sh` 22 | Lists draft releases prepared by release-drafter. 23 | - `show_issues.sh` 24 | Lists all open issues on the plugin repositories. 25 | - `show_pullrequests.sh` 26 | Lists all open pull-requests on the plugin repositories. 27 | - `update_submodules.py` 28 | Updates sub-modules, adds new plugins from the org, and removes archived/moved ones. 29 | -------------------------------------------------------------------------------- /build_all.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #set -x 3 | MY=$(dirname $(realpath -s "${0}")) 4 | 5 | export ARTIFACT_DIR="${MY}/artifacts" 6 | mkdir -p "${ARTIFACT_DIR}" 7 | 8 | DEFAULT_REPO_DIR="${MY}/test_repo" 9 | DEFAULT_REPO_URL="http://localhost:8080" 10 | 11 | export JELLYFIN_REPO=${JELLYFIN_REPO:-$DEFAULT_REPO_DIR} 12 | export JELLYFIN_REPO_URL=${JELLYFIN_REPO_URL:-$DEFAULT_REPO_URL} 13 | 14 | export VERSION_SUFFIX=$(date -u +%y%m.%d%H.%M%S) 15 | 16 | FAILED=() 17 | 18 | for plugin in $(find . -maxdepth 1 -mindepth 1 -type d -name 'jellyfin-plugin-*' | sort); do 19 | name=$(basename $plugin) 20 | if [ "$name" = "jellyfin-plugin-meta" ]; then 21 | continue 22 | fi 23 | pushd $plugin > /dev/null 24 | echo -e "\n##### ${name} #####" 25 | 26 | bash $MY/build_plugin.sh || { 27 | FAILED+=("$name") 28 | } 29 | 30 | popd > /dev/null 31 | done 32 | 33 | if [ ! ${#FAILED[@]} -eq 0 ]; then 34 | echo -e "\n\nThe following plugins failed to compile:" > /dev/stderr 35 | for plugin in "${FAILED[@]}"; do 36 | echo " - $plugin" > /dev/stderr 37 | done 38 | 39 | exit 1 40 | fi 41 | -------------------------------------------------------------------------------- /build_plugin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2020 - Odd Strabo 4 | # 5 | # 6 | # The Unlicense 7 | # ============= 8 | # 9 | # This is free and unencumbered software released into the public domain. 10 | # 11 | # Anyone is free to copy, modify, publish, use, compile, sell, or 12 | # distribute this software, either in source code form or as a compiled 13 | # binary, for any purpose, commercial or non-commercial, and by any 14 | # means. 15 | # 16 | # In jurisdictions that recognize copyright laws, the author or authors 17 | # of this software dedicate any and all copyright interest in the 18 | # software to the public domain. We make this dedication for the benefit 19 | # of the public at large and to the detriment of our heirs and 20 | # successors. We intend this dedication to be an overt act of 21 | # relinquishment in perpetuity of all present and future rights to this 22 | # software under copyright law. 23 | # 24 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 25 | # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 26 | # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 27 | # IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR 28 | # OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 29 | # ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 30 | # OTHER DEALINGS IN THE SOFTWARE. 31 | # 32 | # For more information, please refer to 33 | # 34 | 35 | MY=$(dirname $(realpath -s "${0}")) 36 | JPRM="jprm" 37 | 38 | DEFAULT_REPO_DIR="${MY}/test_repo" 39 | DEFAULT_REPO_URL="http://localhost:8080" 40 | 41 | PLUGIN=${1:-${PLUGIN:-.}} 42 | 43 | ARTIFACT_DIR=${ARTIFACT_DIR:-"${MY}/artifacts"} 44 | mkdir -p "${ARTIFACT_DIR}" 45 | 46 | JELLYFIN_REPO=${JELLYFIN_REPO:-${DEFAULT_REPO_DIR}} 47 | JELLYFIN_REPO_URL=${JELLYFIN_REPO_URL:-${DEFAULT_REPO_URL}} 48 | 49 | # Each segment of the version is a 16bit number. 50 | # Max number is 65535. 51 | VERSION_SUFFIX=${VERSION_SUFFIX:-$(date -u +%y%m.%d%H.%M%S)} 52 | 53 | meta_version=$(grep -Po '^ *version: * "*\K[^"$]+' "${PLUGIN}/build.yaml") 54 | VERSION=${VERSION:-$(echo $meta_version | sed 's/\.[0-9]*\.[0-9]*\.[0-9]*$/.'"$VERSION_SUFFIX"'/')} 55 | 56 | # !!! VERSION IS OVERWRITTEN HERE 57 | #VERSION="${meta_version}" 58 | 59 | find "${PLUGIN}" -name project.assets.json -exec rm -v '{}' ';' 60 | 61 | zipfile=$($JPRM --verbosity=debug plugin build "${PLUGIN}" --output="${ARTIFACT_DIR}" --version="${VERSION}") && { 62 | $JPRM --verbosity=debug repo add --url=${JELLYFIN_REPO_URL} "${JELLYFIN_REPO}" "${zipfile}" 63 | } 64 | exit $? 65 | -------------------------------------------------------------------------------- /show_drafts.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rstrip_ver() { 4 | if [ -z "$1" ]; then 5 | grep -Po "^.*?(?=(\.0\.0\.0|\.0\.0|\.0)?$)" 6 | else 7 | echo $1 | grep -Po "^.*?(?=(\.0\.0\.0|\.0\.0|\.0)?$)" 8 | fi 9 | } 10 | 11 | esc=$(printf '\033') 12 | colorize_changelog() { 13 | #1 pr number 14 | #2 list char 15 | #3 pr submitter 16 | sed -r -e "s/\\((#[0-9]+)\)/(${esc}[32m\1${esc}[0m)/g" \ 17 | -e "s/^\s*[*+-]\s*/ ${esc}[1;30m-${esc}[0m /g" \ 18 | -e "s/@([^ ]+)$/${esc}[1;30m@${esc}[0;36m\1${esc}[0m/gi" 19 | } 20 | 21 | 22 | IFS=$'\n' 23 | for name in $(git submodule foreach --quiet 'basename $PWD'); do 24 | pushd $name > /dev/null 25 | draft="$(hub release --include-drafts -L2 -f 'SOF:%S%n%T%n%t%n%U%n%b%nEOF%n' --color=always | sed -n -e '/SOF:draft/,/EOF/p' | sed -e '1d' -e '$d')" 26 | 27 | if [ ! -z "$draft" ]; then 28 | IFS=$'\n' parts=(${draft}) 29 | 30 | tag="${parts[0]}" 31 | title="${parts[1]}" 32 | url="${parts[2]}" 33 | IFS=$'\n' description="${parts[*]:3}" 34 | 35 | echo 36 | echo -e "\e[1m$name\e[0m: $title\n \e[34m$url\e[0m" 37 | 38 | changes=$(echo "$description" | grep -Po '^\s*\K\*.*$' ) 39 | 40 | meta_version=$(grep -Po "version: ?[\"']?\K.*(?=[\"']$)" build.yaml | rstrip_ver) 41 | draft_version=$(echo $tag | grep -Po 'v\K.*' | rstrip_ver) 42 | 43 | if [ "$meta_version" != "$draft_version" ]; then 44 | echo -e " \e[1;31mVersion bump needed!" 45 | echo -e " \e[0;31mDraft is for v\e[0m\e[1m$draft_version\e[0;31m, but build.yaml specifies v\e[0m\e[1m$meta_version\e[0m" 46 | fi 47 | 48 | echo "$changes" | colorize_changelog 49 | fi 50 | popd > /dev/null 51 | done 52 | -------------------------------------------------------------------------------- /show_issues.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git submodule foreach \ 4 | hub issue --format='%sC%>(8)%i%Creset %t% l%n%Cblue% U%Creset%n' --color=always 5 | -------------------------------------------------------------------------------- /show_pullrequests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | git submodule foreach \ 4 | hub pr list --format='%pC%>(8)%i%Creset %t% l%n%Cblue% U%Creset%n' --color=always 5 | -------------------------------------------------------------------------------- /update_submodules.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import os 3 | import subprocess 4 | import requests 5 | import time 6 | 7 | 8 | try: 9 | subprocess.run(["git", "diff", "--staged", "--quiet", "--exit-code"], check=True) 10 | except subprocess.SubprocessError: 11 | print("Error: You have staged changes!") 12 | exit(1) 13 | 14 | available = [] 15 | fetched = [] 16 | failed = [] 17 | removed = [] 18 | added = [] 19 | 20 | 21 | def update(_name, url=None): 22 | if not os.path.exists(_name): 23 | print("Adding {} @ {}".format(_name, url)) 24 | subprocess.run(["git", "submodule", "add", "--force", "-b", "master", url, _name], check=True) 25 | added.append(_name) 26 | subprocess.run(["git", "submodule", "update", "--init", "--remote", "--checkout", "--force", _name], check=True) 27 | 28 | subprocess.run(["git", "fetch", "--all", "--tags"], cwd=_name, check=True) 29 | subprocess.run(["git", "checkout", "-f", "-B", "master", "origin/master"], cwd=_name, check=True) 30 | subprocess.run(["git", "add", _name], check=True) 31 | fetched.append(_name) 32 | 33 | 34 | def remove(_name): 35 | if os.path.exists(_name): 36 | print("Removing {}".format(_name)) 37 | subprocess.run(["git", "rm", _name], check=True) 38 | removed.append(_name) 39 | 40 | 41 | page_num = 1 42 | per_page = 100 43 | PAGINATION_URL = "https://api.github.com/orgs/jellyfin/repos?sort=created&per_page={per}&page={page}" 44 | 45 | next = PAGINATION_URL.format(per=per_page, page=page_num) 46 | 47 | while next: 48 | resp = requests.get(next) 49 | repos = resp.json() 50 | 51 | page_num += 1 52 | next = PAGINATION_URL.format(per=per_page, page=page_num) 53 | if len(repos) < per_page: 54 | next = None 55 | 56 | for repo in repos: 57 | _name = repo.get("name") 58 | url = repo.get("clone_url") 59 | if _name.startswith("jellyfin-plugin-"): 60 | available.append(_name) 61 | try: 62 | update(_name, url) 63 | pass 64 | except Exception as e: 65 | failed.append((_name, e)) 66 | 67 | 68 | for repo in os.listdir("."): 69 | if repo in fetched: 70 | continue 71 | 72 | if not os.path.isdir(repo): 73 | continue 74 | 75 | if not repo.startswith("jellyfin-plugin-"): 76 | continue 77 | 78 | try: 79 | if not repo in available: 80 | remove(repo) 81 | except Exception as e: 82 | failed.append((repo, e)) 83 | 84 | 85 | if failed: 86 | print("The following repositories failed to update:") 87 | for repo, e in failed: 88 | print(repo, e) 89 | 90 | commit_message = ["Updated plugin submodules"] 91 | 92 | if added: 93 | commit_message.append("") 94 | commit_message.append("Added") 95 | commit_message.append("-----") 96 | commit_message.append("") 97 | for plugin in added: 98 | commit_message.append("- {}".format(plugin)) 99 | 100 | if removed: 101 | commit_message.append("") 102 | commit_message.append("Removed") 103 | commit_message.append("-------") 104 | commit_message.append("") 105 | for plugin in removed: 106 | commit_message.append("- {}".format(plugin)) 107 | 108 | subprocess.run(["git", "commit", "-m", "\n".join(commit_message)]) 109 | --------------------------------------------------------------------------------