├── .dockerignore ├── .github ├── .wordlist.txt ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── 1.bug_report.yml │ ├── 2.feature_request.yml │ └── config.yml ├── dependabot.yml ├── logo.png ├── pull_request_template.md └── workflows │ ├── copyright.yml │ ├── docker-develop.yml │ ├── docker-latest.yml │ ├── docker-version.yml │ ├── increment-build.yml │ ├── release-master.yml │ ├── release-notification.yml │ ├── tag-new-release.yml │ └── validate-pull.yml ├── .gitignore ├── .spellcheck.yml ├── Dockerfile ├── LICENSE ├── PART ├── README.md ├── VERSION ├── config └── example.env ├── overlay_reset.py ├── overlays ├── 1080P-DV.png ├── 1080P-HDR.png ├── 1080P.png ├── 480P-DV.png ├── 480P-HDR.png ├── 480P.png ├── 4K-DV.png ├── 4K-HDR.png ├── 4K.png ├── 576P-DV.png ├── 576P-HDR.png ├── 576P.png ├── 720P-DV.png ├── 720P-HDR.png ├── 720P.png ├── AAC.png ├── Amazon.png ├── Anniversary-Edition-Box.png ├── AppleTV.png ├── CSS-Families-Movies-Ribbon.png ├── Collectors-Edition-Box.png ├── Criterion-Box.png ├── DTS-ES.png ├── DTS-HD-HRA.png ├── DTS-HD-MA.png ├── DTS-HD.png ├── DTS-X.png ├── DTS.png ├── DV.png ├── Direct-Play.png ├── Directors-Cut-Box.png ├── Disney.png ├── Dolby-Atmos.png ├── Dolby-Digital-Plus-Atmos-Filepath.png ├── Dolby-Digital-Plus-Atmos.png ├── Dolby-Digital-Plus.png ├── Dolby-Digital.png ├── Dolby-TrueHD-Atmos.png ├── Dolby-TrueHD.png ├── Dual-Audio.png ├── Extended-Edition-Box.png ├── FLAC.png ├── Final-Cut-Box.png ├── HBO-Max.png ├── HDR.png ├── Hulu.png ├── IMAX-Box.png ├── IMAX-E-Box.png ├── IMDB-Top-250.png ├── IMDb-black.png ├── IMDb.png ├── International-Cut-Box.png ├── MC-Must-See-Movies-Ribbon.png ├── MP3.png ├── Mediastinger.png ├── Multi-Audio.png ├── Netflix.png ├── Opus.png ├── Oscars-Ribbon.png ├── PCM.png ├── Paramount.png ├── Peacock.png ├── RT-Cert-Fresh-Ribbon.png ├── RT-Cert-Fresh.png ├── Remastered-Box.png ├── Special-Edition-Box.png ├── TMDb.png ├── Theatrical-Cut-Box.png ├── Ultimate-Cut-Box.png ├── Uncut-Edition-Box.png ├── Unrated-Edition-Box.png ├── YouTube.png ├── css.png ├── flix-metacritic.png ├── flix-prime.png ├── metacritic-mustsee.png ├── rt-cert.png └── rt.png └── requirements.txt /.dockerignore: -------------------------------------------------------------------------------- 1 | **/dist 2 | **/build 3 | *.spec 4 | **/__pycache__ 5 | /.vscode 6 | **/log 7 | README.md 8 | LICENSE 9 | .gitignore 10 | .dockerignore 11 | .git 12 | .github 13 | *.psd 14 | config/**/* 15 | config 16 | Dockerfile 17 | venv 18 | .idea 19 | test.py -------------------------------------------------------------------------------- /.github/.wordlist.txt: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | Dockerhub 3 | dockerfiles 4 | env 5 | Kometa 6 | Plex 7 | repo 8 | TMDb 9 | URl 10 | walkthroughs -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: meisnate12 -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/1.bug_report.yml: -------------------------------------------------------------------------------- 1 | name: Bug Report 2 | description: Please do not use bug reports for support issues or feature requests. 3 | labels: ['status:not-yet-viewed', 'bug'] 4 | assignees: 'meisnate12' 5 | 6 | body: 7 | - type: markdown 8 | attributes: 9 | value: > 10 | **THIS IS NOT THE PLACE TO ASK FOR SUPPORT!** 11 | Please use [Kometa Discord](https://kometa.wiki/en/latest/discord/) and post your question under the `kometa-help` channel for support issues. 12 | - type: input 13 | id: version 14 | attributes: 15 | label: Version Number 16 | description: Can be found at the beginning of your log file 17 | placeholder: eg. 1.1.0 18 | validations: 19 | required: true 20 | - type: dropdown 21 | id: branch 22 | attributes: 23 | label: What branch are you on? 24 | options: 25 | - master 26 | - develop 27 | validations: 28 | required: true 29 | - type: textarea 30 | id: description 31 | attributes: 32 | label: Describe the Bug 33 | description: A clear and concise description of the bug. 34 | validations: 35 | required: true 36 | - type: input 37 | id: logs 38 | attributes: 39 | label: Logs 40 | description: > 41 | Please share the relevant log file with the error on [Gist](https://gist.github.com). 42 | placeholder: "https://gist.github.com" -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/2.feature_request.yml: -------------------------------------------------------------------------------- 1 | name: Feature Request 2 | description: Post here if you have an idea about how to improve the script. 3 | title: '[Feature]: ' 4 | labels: ['enhancement'] 5 | assignees: ['meisnate12'] 6 | 7 | body: 8 | - type: markdown 9 | attributes: 10 | value: > 11 | **THIS IS NOT THE PLACE TO ASK FOR SUPPORT!** 12 | Please use [Kometa Discord](https://kometa.wiki/en/latest/discord/) and post your question under the `kometa-help` channel for support issues. 13 | 14 | - type: textarea 15 | id: description 16 | attributes: 17 | label: Describe the Feature Request 18 | description: A clear and concise description of the feature request. 19 | validations: 20 | required: true -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Kometa Wiki 4 | url: https://kometa.wiki/en/latest/home/scripts/overlay-reset.html 5 | about: Please check the wiki to see if your question has already been answered. 6 | - name: Discord 7 | url: https://kometa.wiki/en/latest/discord/ 8 | about: Please use the Kometa Discord to ask for support. -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "pip" 9 | directory: "/" 10 | schedule: 11 | interval: "daily" 12 | target-branch: "develop" 13 | assignees: 14 | - "meisnate12" 15 | - package-ecosystem: github-actions 16 | directory: '/' 17 | schedule: 18 | interval: daily 19 | target-branch: "develop" 20 | assignees: 21 | - "meisnate12" 22 | ignore: 23 | - dependency-name: "salsify/action-detect-and-tag-new-version" 24 | -------------------------------------------------------------------------------- /.github/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/.github/logo.png -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | ## Description 2 | 3 | Please include a summary of the changes. 4 | 5 | ### Issues Fixed or Closed 6 | 7 | - Fixes #(issue) 8 | 9 | ## Type of Change 10 | 11 | Please delete options that are not relevant. 12 | 13 | - [ ] Bug fix (non-breaking change which fixes an issue) 14 | - [ ] New feature (non-breaking change which adds functionality) 15 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 16 | - [ ] Documentation change (non-code changes affecting only the wiki) 17 | - [ ] Infrastructure change (changes related to the github repo, build process, or the like) 18 | 19 | ## Checklist 20 | 21 | - [ ] My code was submitted to the develop branch of the repository. 22 | -------------------------------------------------------------------------------- /.github/workflows/copyright.yml: -------------------------------------------------------------------------------- 1 | name: Update Copyright Year 2 | 3 | on: 4 | schedule: 5 | - cron: '0 3 1 1 *' 6 | workflow_dispatch: 7 | 8 | jobs: 9 | update-copyright: 10 | runs-on: ubuntu-latest 11 | steps: 12 | 13 | - name: Get current year 14 | id: date 15 | run: echo "year=$(date +'%Y')" >> $GITHUB_OUTPUT 16 | 17 | - name: Create App Token 18 | uses: actions/create-github-app-token@v1 19 | id: app-token 20 | with: 21 | app-id: ${{ vars.APP_ID }} 22 | private-key: ${{ secrets.APP_TOKEN }} 23 | 24 | - name: Check Out Repo 25 | uses: actions/checkout@v4 26 | with: 27 | token: ${{ steps.app-token.outputs.token }} 28 | ref: develop 29 | 30 | - name: Update Copyright 31 | run: sed -i -E 's/(Copyright \(c\) ).+( meisnate12)/\1${{ steps.date.outputs.year }}\2/' LICENSE 32 | 33 | - name: Check Diff 34 | id: verify_diff 35 | run: | 36 | git diff --quiet . || echo "changed=true" >> $GITHUB_OUTPUT 37 | 38 | - name: Commit & Push Changes 39 | if: steps.verify_diff.outputs.changed == 'true' 40 | run: | 41 | git config --local user.email "action@github.com" 42 | git config --local user.name "GitHub Action" 43 | git add -A 44 | git commit -m "Copyright updated to ${{ steps.date.outputs.year }}" -a 45 | git push origin develop 46 | 47 | - name: Discord Failure Notification 48 | uses: Kometa-Team/discord-notifications@master 49 | if: failure() 50 | with: 51 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 52 | message: ${{ vars.BUILD_FAILURE_ROLE }} 53 | title: "${{ vars.REPO_NAME }}: ${{ vars.TEXT_COPYRIGHT }}" 54 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 55 | color: ${{ vars.COLOR_FAILURE }} 56 | username: ${{ vars.BOT_NAME }} 57 | avatar_url: ${{ vars.BOT_IMAGE }} 58 | author: ${{ vars.GIT_NAME }} 59 | author_icon_url: ${{ vars.GIT_IMAGE }} -------------------------------------------------------------------------------- /.github/workflows/docker-develop.yml: -------------------------------------------------------------------------------- 1 | name: Docker Develop Build 2 | 3 | on: 4 | workflow_run: 5 | workflows: ["Master Release"] 6 | types: 7 | - completed 8 | 9 | jobs: 10 | 11 | docker-build-develop: 12 | runs-on: ubuntu-latest 13 | steps: 14 | 15 | - name: Check Out Repo 16 | uses: actions/checkout@v4 17 | with: 18 | ref: develop 19 | 20 | - name: Login to Docker Hub 21 | uses: docker/login-action@v3 22 | with: 23 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 24 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 25 | 26 | - name: Set up QEMU 27 | uses: docker/setup-qemu-action@master 28 | with: 29 | platforms: all 30 | 31 | - name: Set up Docker Buildx 32 | id: buildx 33 | uses: docker/setup-buildx-action@v3 34 | 35 | - name: Build and push 36 | id: docker_build 37 | uses: docker/build-push-action@v6 38 | with: 39 | context: ./ 40 | file: ./Dockerfile 41 | build-args: | 42 | "BRANCH_NAME=develop" 43 | platforms: linux/amd64,linux/arm64 44 | push: true 45 | tags: ${{ vars.DOCKER_TEAM }}/${{ vars.DOCKER_REPO }}:develop 46 | cache-from: type=gha 47 | cache-to: type=gha,mode=max 48 | 49 | - name: Discord Success Notification 50 | uses: Kometa-Team/discord-notifications@master 51 | if: success() 52 | with: 53 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 54 | title: "${{ vars.NAME }} develop: ${{ vars.TEXT_SUCCESS }}" 55 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 56 | color: ${{ vars.COLOR_SUCCESS }} 57 | username: ${{ vars.BOT_NAME }} 58 | avatar_url: ${{ vars.BOT_IMAGE }} 59 | author: ${{ vars.DOCKER_NAME }} 60 | author_icon_url: ${{ vars.DOCKER_IMAGE }} 61 | 62 | - name: Discord Failure Notification 63 | uses: Kometa-Team/discord-notifications@master 64 | if: failure() 65 | with: 66 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 67 | message: ${{ vars.BUILD_FAILURE_ROLE }} 68 | title: "${{ vars.NAME }} develop: ${{ vars.TEXT_FAILURE }}" 69 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 70 | color: ${{ vars.COLOR_FAILURE }} 71 | username: ${{ vars.BOT_NAME }} 72 | avatar_url: ${{ vars.BOT_IMAGE }} 73 | author: ${{ vars.DOCKER_NAME }} 74 | author_icon_url: ${{ vars.DOCKER_IMAGE }} 75 | 76 | commit-notification: 77 | runs-on: ubuntu-latest 78 | needs: [ docker-build-develop ] 79 | if: ${{ success() }} 80 | steps: 81 | 82 | - name: Send Discord Commit Notification 83 | uses: Kometa-Team/discord-notifications@master 84 | with: 85 | webhook_id_token: ${{ secrets.DEVELOP_WEBHOOK }} 86 | title: Commits 87 | message: "${{ vars.DEVELOP_ROLE }} - An update to ${{ vars.NAME }} has been published and is available to users of the **develop** branch." 88 | commits: "true" 89 | color: ${{ vars.COLOR_SUCCESS }} 90 | username: ${{ vars.BOT_NAME }} 91 | avatar_url: ${{ vars.BOT_IMAGE }} 92 | author: ${{ vars.NAME }} Develop Release 93 | author_icon_url: ${{ vars.RELEASE_IMAGE }} 94 | -------------------------------------------------------------------------------- /.github/workflows/docker-latest.yml: -------------------------------------------------------------------------------- 1 | name: Docker Latest Build 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | 9 | docker-build-latest: 10 | runs-on: ubuntu-latest 11 | steps: 12 | 13 | - name: Check Out Repo 14 | uses: actions/checkout@v4 15 | 16 | - name: Login to Docker Hub 17 | uses: docker/login-action@v3 18 | with: 19 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 20 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 21 | 22 | - name: Set up QEMU 23 | uses: docker/setup-qemu-action@master 24 | with: 25 | platforms: all 26 | 27 | - name: Set up Docker Buildx 28 | id: buildx 29 | uses: docker/setup-buildx-action@v3 30 | 31 | - name: Build and push 32 | id: docker_build 33 | uses: docker/build-push-action@v6 34 | with: 35 | context: ./ 36 | file: ./Dockerfile 37 | platforms: linux/amd64,linux/arm64 38 | push: true 39 | tags: ${{ vars.DOCKER_TEAM }}/${{ vars.DOCKER_REPO }}:latest 40 | cache-from: type=gha 41 | cache-to: type=gha,mode=max 42 | 43 | - name: Discord Success Notification 44 | uses: Kometa-Team/discord-notifications@master 45 | if: success() 46 | with: 47 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 48 | title: "${{ vars.NAME }} latest: ${{ vars.TEXT_SUCCESS }}" 49 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 50 | color: ${{ vars.COLOR_SUCCESS }} 51 | username: ${{ vars.BOT_NAME }} 52 | avatar_url: ${{ vars.BOT_IMAGE }} 53 | author: ${{ vars.DOCKER_NAME }} 54 | author_icon_url: ${{ vars.DOCKER_IMAGE }} 55 | 56 | - name: Discord Failure Notification 57 | uses: Kometa-Team/discord-notifications@master 58 | if: failure() 59 | with: 60 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 61 | message: ${{ vars.BUILD_FAILURE_ROLE }} 62 | title: "${{ vars.NAME }} latest: ${{ vars.TEXT_FAILURE }}" 63 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 64 | color: ${{ vars.COLOR_FAILURE }} 65 | username: ${{ vars.BOT_NAME }} 66 | avatar_url: ${{ vars.BOT_IMAGE }} 67 | author: ${{ vars.DOCKER_NAME }} 68 | author_icon_url: ${{ vars.DOCKER_IMAGE }} -------------------------------------------------------------------------------- /.github/workflows/docker-version.yml: -------------------------------------------------------------------------------- 1 | name: Docker Version Build 2 | 3 | on: 4 | create: 5 | tags: 6 | - v* 7 | 8 | jobs: 9 | 10 | docker-build-version: 11 | if: ${{ startsWith(github.ref, 'refs/tags/v1') || startsWith(github.ref, 'refs/tags/v2') }} 12 | runs-on: ubuntu-latest 13 | steps: 14 | 15 | - name: Check Out Repo 16 | uses: actions/checkout@v4 17 | with: 18 | fetch-depth: 0 19 | 20 | - name: Login to Docker Hub 21 | uses: docker/login-action@v3 22 | with: 23 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 24 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 25 | 26 | - name: Set up QEMU 27 | uses: docker/setup-qemu-action@master 28 | with: 29 | platforms: all 30 | 31 | - name: Set up Docker Buildx 32 | id: buildx 33 | uses: docker/setup-buildx-action@v3 34 | 35 | - name: Get the version 36 | id: get_version 37 | run: echo "VERSION=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_OUTPUT 38 | 39 | - name: Build and push 40 | id: docker_build 41 | uses: docker/build-push-action@v6 42 | with: 43 | context: ./ 44 | file: ./Dockerfile 45 | platforms: linux/amd64,linux/arm64 46 | push: true 47 | tags: ${{ vars.DOCKER_TEAM }}/${{ vars.DOCKER_REPO }}:${{ steps.get_version.outputs.VERSION }} 48 | cache-from: type=gha 49 | cache-to: type=gha,mode=max 50 | 51 | - name: Discord Success Notification 52 | uses: Kometa-Team/discord-notifications@master 53 | if: success() 54 | with: 55 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 56 | title: "${{ vars.NAME }} ${{ steps.get_version.outputs.VERSION }}: ${{ vars.TEXT_SUCCESS }}" 57 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 58 | color: ${{ vars.COLOR_SUCCESS }} 59 | username: ${{ vars.BOT_NAME }} 60 | avatar_url: ${{ vars.BOT_IMAGE }} 61 | author: ${{ vars.DOCKER_NAME }} 62 | author_icon_url: ${{ vars.DOCKER_IMAGE }} 63 | 64 | - name: Discord Failure Notification 65 | uses: Kometa-Team/discord-notifications@master 66 | if: failure() 67 | with: 68 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 69 | message: ${{ vars.BUILD_FAILURE_ROLE }} 70 | title: "${{ vars.NAME }} ${{ steps.get_version.outputs.VERSION }}: ${{ vars.TEXT_FAILURE }}" 71 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 72 | color: ${{ vars.COLOR_FAILURE }} 73 | username: ${{ vars.BOT_NAME }} 74 | avatar_url: ${{ vars.BOT_IMAGE }} 75 | author: ${{ vars.DOCKER_NAME }} 76 | author_icon_url: ${{ vars.DOCKER_IMAGE }} 77 | 78 | - name: Create release 79 | uses: marvinpinto/action-automatic-releases@latest 80 | with: 81 | title: ${{ vars.NAME }} ${{ github.event.ref }} 82 | repo_token: ${{ secrets.PAT }} 83 | prerelease: false -------------------------------------------------------------------------------- /.github/workflows/increment-build.yml: -------------------------------------------------------------------------------- 1 | name: Increment Build 2 | 3 | on: 4 | pull_request_target: 5 | branches: [develop] 6 | types: [closed] 7 | 8 | jobs: 9 | 10 | verify-changes: 11 | runs-on: ubuntu-latest 12 | if: github.base_ref == 'develop' && github.event.pull_request.merged 13 | outputs: 14 | build: ${{ steps.list-changes.outputs.build }} 15 | steps: 16 | 17 | - name: Check Out Repo 18 | uses: actions/checkout@v4 19 | with: 20 | fetch-depth: 0 21 | ref: develop 22 | 23 | - name: Get changes 24 | id: get-changes 25 | run: echo "files=$(git diff --name-only HEAD^ | xargs)" >> $GITHUB_OUTPUT 26 | 27 | - name: List changed files 28 | id: list-changes 29 | run: | 30 | for file in ${{ steps.get-changes.outputs.files }}; do 31 | if [[ $file =~ ^(overlay_reset.py|requirements.txt|.dockerignore|Dockerfile).*$ ]] ; then 32 | echo "$file will trigger docker build" 33 | echo "build=true" >> $GITHUB_OUTPUT 34 | else 35 | echo "$file will not trigger docker build" 36 | fi 37 | done 38 | 39 | increment-build: 40 | runs-on: ubuntu-latest 41 | needs: [ verify-changes ] 42 | if: needs.verify-changes.outputs.build == 'true' 43 | outputs: 44 | version: ${{ steps.update-version.outputs.version }} 45 | build-value: ${{ steps.update-version.outputs.build-value }} 46 | commit-msg: ${{ steps.update-version.outputs.commit-msg }} 47 | commit-hash: ${{ steps.update-version.outputs.commit-hash }} 48 | commit-short: ${{ steps.update-version.outputs.commit-short }} 49 | pr-tag: ${{ steps.update-version.outputs.pr-tag }} 50 | steps: 51 | 52 | - name: Create App Token 53 | uses: actions/create-github-app-token@v1 54 | id: app-token 55 | with: 56 | app-id: ${{ vars.APP_ID }} 57 | private-key: ${{ secrets.APP_TOKEN }} 58 | 59 | - name: Check Out Repo 60 | uses: actions/checkout@v4 61 | with: 62 | token: ${{ steps.app-token.outputs.token }} 63 | ref: develop 64 | fetch-depth: 0 65 | 66 | - name: Update VERSION File 67 | id: update-version 68 | run: | 69 | branch_name=${{ github.event.pull_request.head.ref }} 70 | repo_name=${{ github.event.pull_request.head.repo.full_name }} 71 | base_name="${repo_name%/*}" 72 | if [[ "${branch_name}" =~ ^(master|develop)$ ]]; then 73 | pr_tag="${base_name}" 74 | else 75 | pr_tag="${branch_name}" 76 | fi 77 | echo "pr-tag=${pr_tag}" >> $GITHUB_OUTPUT 78 | 79 | value=$(cat VERSION) 80 | old_msg=$(git log -1 HEAD --pretty=format:%s) 81 | version="${value%-build*}" 82 | 83 | part_value=$(cat PART) 84 | 85 | if [[ "$value" == *"-"* ]]; then 86 | build_value="$((${value#*-build} + 1))" 87 | else 88 | build_value="1" 89 | fi 90 | 91 | new_value="${version}-build${build_value}" 92 | new_msg="[${build_value}] ${old_msg}" 93 | 94 | echo "version=${version}" >> $GITHUB_OUTPUT 95 | echo "build-value=${build_value}" >> $GITHUB_OUTPUT 96 | echo "commit-msg=${old_msg}" >> $GITHUB_OUTPUT 97 | echo "commit-hash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT 98 | echo "commit-short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT 99 | 100 | echo "$new_value" > "VERSION" 101 | echo "" > "PART" 102 | git config --local user.email "action@github.com" 103 | git config --local user.name "GitHub Action" 104 | git add VERSION 105 | git add PART 106 | git commit -m "${new_msg}" --amend 107 | git push origin develop --force-with-lease 108 | 109 | docker-build-develop: 110 | runs-on: ubuntu-latest 111 | needs: [ increment-build, verify-changes ] 112 | if: needs.verify-changes.outputs.build == 'true' 113 | steps: 114 | 115 | - name: Check Out Repo 116 | uses: actions/checkout@v4 117 | with: 118 | ref: develop 119 | 120 | - name: Login to Docker Hub 121 | uses: docker/login-action@v3 122 | with: 123 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 124 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 125 | 126 | - name: Set up QEMU 127 | uses: docker/setup-qemu-action@master 128 | with: 129 | platforms: all 130 | 131 | - name: Set up Docker Buildx 132 | id: buildx 133 | uses: docker/setup-buildx-action@v3 134 | 135 | - name: Build and Push 136 | id: docker_build 137 | uses: docker/build-push-action@v6 138 | with: 139 | context: ./ 140 | file: ./Dockerfile 141 | build-args: | 142 | "BRANCH_NAME=develop" 143 | platforms: linux/amd64,linux/arm64 144 | push: true 145 | tags: ${{ vars.DOCKER_TEAM }}/${{ vars.DOCKER_REPO }}:develop 146 | cache-from: type=gha 147 | cache-to: type=gha,mode=max 148 | 149 | - name: Discord Success Notification 150 | uses: Kometa-Team/discord-notifications@master 151 | if: success() 152 | with: 153 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 154 | title: "${{ vars.NAME }} develop: ${{ vars.TEXT_SUCCESS }}" 155 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 156 | color: ${{ vars.COLOR_SUCCESS }} 157 | username: ${{ vars.BOT_NAME }} 158 | avatar_url: ${{ vars.BOT_IMAGE }} 159 | author: ${{ vars.DOCKER_NAME }} 160 | author_icon_url: ${{ vars.DOCKER_IMAGE }} 161 | 162 | - name: Discord Failure Notification 163 | uses: Kometa-Team/discord-notifications@master 164 | if: failure() 165 | with: 166 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 167 | message: ${{ vars.BUILD_FAILURE_ROLE }} 168 | title: "${{ vars.NAME }} develop: ${{ vars.TEXT_FAILURE }}" 169 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 170 | color: ${{ vars.COLOR_FAILURE }} 171 | username: ${{ vars.BOT_NAME }} 172 | avatar_url: ${{ vars.BOT_IMAGE }} 173 | author: ${{ vars.DOCKER_NAME }} 174 | author_icon_url: ${{ vars.DOCKER_IMAGE }} 175 | 176 | commit-notification: 177 | runs-on: ubuntu-latest 178 | needs: [ increment-build, verify-changes, docker-build-develop ] 179 | if: ${{ success() && needs.verify-changes.outputs.build == 'true' }} 180 | steps: 181 | 182 | - name: Send Discord Commit Notification 183 | uses: Kometa-Team/discord-notifications@master 184 | with: 185 | webhook_id_token: ${{ secrets.DEVELOP_WEBHOOK }} 186 | title: ${{ vars.NAME }} ${{ needs.increment-build.outputs.version }} Build ${{ needs.increment-build.outputs.build-value }} 187 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/commit/${{ needs.increment-build.outputs.commit-hash }} 188 | description: ${{ needs.increment-build.outputs.commit-msg }} 189 | message: "<@&1079103365604184074> - An update to ${{ vars.NAME }} has been published and is available to users of the **develop** branch." 190 | color: ${{ vars.COLOR_SUCCESS }} 191 | username: ${{ vars.BOT_NAME }} 192 | avatar_url: ${{ vars.BOT_IMAGE }} 193 | author: ${{ vars.NAME }} Develop Release 194 | author_icon_url: ${{ vars.RELEASE_IMAGE }} 195 | 196 | cleanup-tags: 197 | runs-on: ubuntu-latest 198 | needs: [ increment-build, verify-changes, docker-build-develop, commit-notification ] 199 | if: ${{ success() }} 200 | steps: 201 | - name: remove tag 202 | run: | 203 | HUB_TOKEN=$(curl -s -H "Content-Type: application/json" -X POST -d "{\"username\": \"${{ secrets.DOCKER_HUB_USERNAME }}\", \"password\": \"${{ secrets.DOCKER_HUB_ACCESS_TOKEN }}\"}" https://hub.docker.com/v2/users/login/ | jq -r .token) 204 | curl -i -X DELETE \ 205 | -H "Accept: application/json" \ 206 | -H "Authorization: JWT $HUB_TOKEN" \ 207 | https://hub.docker.com/v2/repositories/${{ vars.DOCKER_TEAM }}/${{ vars.DOCKER_REPO }}/tags/${{ needs.increment-build.outputs.pr-tag }}/ -------------------------------------------------------------------------------- /.github/workflows/release-master.yml: -------------------------------------------------------------------------------- 1 | name: Master Release 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | release_type: 7 | type: choice 8 | description: Choose which type of release to perform. 9 | options: 10 | - major 11 | - minor 12 | - patch 13 | default: patch 14 | 15 | jobs: 16 | release-master: 17 | runs-on: ubuntu-latest 18 | steps: 19 | 20 | - name: Create App Token 21 | uses: actions/create-github-app-token@v1 22 | id: app-token 23 | with: 24 | app-id: ${{ vars.APP_ID }} 25 | private-key: ${{ secrets.APP_TOKEN }} 26 | 27 | - name: Check Out Repo 28 | uses: actions/checkout@v4 29 | with: 30 | token: ${{ steps.app-token.outputs.token }} 31 | ref: develop 32 | fetch-depth: 0 33 | 34 | - name: Create Release Commit and Synchronize Branches 35 | run: | 36 | value=$(cat VERSION) 37 | version="${value%-build*}" 38 | echo "CURRENT_VERSION: '${version}'" 39 | IFS='.' read -r MAJOR MINOR PATCH <<< "$version" 40 | 41 | if [[ "${{ github.event.inputs.release_type }}" == "major" ]]; then 42 | NEW_VERSION="$((MAJOR+1)).0.0" 43 | elif [[ "${{ github.event.inputs.release_type }}" == "minor" ]]; then 44 | NEW_VERSION="${MAJOR}.$((MINOR+1)).0" 45 | else 46 | NEW_VERSION="${MAJOR}.${MINOR}.$((PATCH+1))" 47 | fi 48 | 49 | echo "NEW_VERSION='${NEW_VERSION}'" 50 | echo "new_ver=$NEW_VERSION" >> $GITHUB_OUTPUT 51 | echo "$NEW_VERSION" > "VERSION" 52 | 53 | git config --local user.email "action@github.com" 54 | git config --local user.name "GitHub Action" 55 | git add VERSION 56 | git commit -m "${{ vars.NAME }} Release ${NEW_VERSION}" 57 | git push origin develop 58 | git push origin refs/heads/develop:refs/heads/master 59 | 60 | - name: Discord Success Notification 61 | uses: Kometa-Team/discord-notifications@master 62 | if: success() 63 | with: 64 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 65 | title: "${{ vars.NAME }} master release ${{ steps.release.outputs.new_ver }}: ${{ vars.TEXT_SUCCESS }}" 66 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 67 | color: ${{ vars.COLOR_SUCCESS }} 68 | username: ${{ vars.BOT_NAME }} 69 | avatar_url: ${{ vars.BOT_IMAGE }} 70 | author: ${{ vars.GIT_NAME }} 71 | author_icon_url: ${{ vars.GIT_IMAGE }} 72 | 73 | - name: Discord Failure Notification 74 | uses: Kometa-Team/discord-notifications@master 75 | if: failure() 76 | with: 77 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 78 | message: ${{ vars.BUILD_FAILURE_ROLE }} 79 | title: "${{ vars.NAME }} master release ${{ steps.release.outputs.new_ver }}: ${{ vars.TEXT_FAILURE }}" 80 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 81 | color: ${{ vars.COLOR_FAILURE }} 82 | username: ${{ vars.BOT_NAME }} 83 | avatar_url: ${{ vars.BOT_IMAGE }} 84 | author: ${{ vars.GIT_NAME }} 85 | author_icon_url: ${{ vars.GIT_IMAGE }} 86 | -------------------------------------------------------------------------------- /.github/workflows/release-notification.yml: -------------------------------------------------------------------------------- 1 | name: Release Notification 2 | 3 | on: 4 | release: 5 | types: [ published ] 6 | 7 | jobs: 8 | 9 | release-notification: 10 | 11 | runs-on: ubuntu-latest 12 | steps: 13 | 14 | - name: Send Discord Release Notification 15 | uses: Kometa-Team/discord-notifications@master 16 | with: 17 | webhook_id_token: ${{ secrets.RELEASE_WEBHOOK }} 18 | release: true 19 | title: Release VERSION 20 | message: "${{ vars.MASTER_ROLE }} - A new version of ${{ vars.NAME }} has been released and is available to all users" 21 | username: ${{ vars.BOT_NAME }} 22 | avatar_url: ${{ vars.BOT_IMAGE }} 23 | author: ${{ vars.NAME }} Release 24 | author_icon_url: ${{ vars.RELEASE_IMAGE }} 25 | -------------------------------------------------------------------------------- /.github/workflows/tag-new-release.yml: -------------------------------------------------------------------------------- 1 | name: Tag New Version 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | tag: 9 | runs-on: ubuntu-latest 10 | steps: 11 | 12 | - uses: actions/checkout@v4 13 | with: 14 | token: ${{ secrets.PAT }} 15 | fetch-depth: 2 16 | 17 | - uses: Kometa-Team/tag-new-version@master 18 | with: 19 | version-command: | 20 | cat VERSION -------------------------------------------------------------------------------- /.github/workflows/validate-pull.yml: -------------------------------------------------------------------------------- 1 | name: Validate Pull Request 2 | 3 | on: 4 | pull_request_target: 5 | types: [opened, synchronize, reopened, labeled] 6 | 7 | jobs: 8 | 9 | validate-pull: 10 | runs-on: ubuntu-latest 11 | outputs: 12 | build: ${{ steps.list-changes.outputs.build }} 13 | steps: 14 | 15 | - name: Display Refs 16 | run: | 17 | echo "Base Repo: ${{ github.event.pull_request.base.repo.full_name }}" 18 | echo "Base Ref: ${{ github.base_ref }}" 19 | echo "Head Repo: ${{ github.event.pull_request.head.repo.full_name }}" 20 | echo "Head Ref: ${{ github.event.pull_request.head.ref }}" 21 | 22 | - name: Check Base Branch 23 | if: github.base_ref == 'master' 24 | run: | 25 | echo "ERROR: Pull Requests cannot be submitted to master. Please submit the Pull Request to the develop branch" 26 | exit 1 27 | 28 | - name: Checkout Repo 29 | uses: actions/checkout@v4 30 | with: 31 | fetch-depth: 0 32 | ref: ${{ github.event.pull_request.head.ref }} 33 | repository: ${{ github.event.pull_request.head.repo.full_name }} 34 | 35 | - name: Get changes 36 | id: get-changes 37 | run: | 38 | git remote add -f upstream https://github.com/Kometa-Team/${{ vars.REPO_NAME }}.git 39 | git remote update 40 | if [[ ${{ github.event.action }} == "labeled" ]]; then 41 | echo "files=$(git diff --name-only upstream/develop HEAD | xargs)" >> $GITHUB_OUTPUT 42 | else 43 | echo "files=$(git diff --name-only HEAD^ | xargs)" >> $GITHUB_OUTPUT 44 | fi 45 | 46 | - name: List changed files 47 | id: list-changes 48 | run: | 49 | for file in ${{ steps.get-changes.outputs.files }}; do 50 | if [[ $file =~ ^(overlay_reset.py|requirements.txt|.dockerignore|Dockerfile).*$ ]] ; then 51 | echo "$file will trigger docker build" 52 | echo "build=true" >> $GITHUB_OUTPUT 53 | else 54 | echo "$file will not trigger docker build" 55 | fi 56 | done 57 | 58 | - name: Run Spellcheck 59 | uses: rojopolis/spellcheck-github-actions@0.42.0 60 | 61 | docker-build-pull: 62 | runs-on: ubuntu-latest 63 | needs: [ validate-pull ] 64 | if: needs.validate-pull.outputs.build == 'true' && contains(github.event.pull_request.labels.*.name, 'docker') 65 | outputs: 66 | commit-msg: ${{ steps.update-version.outputs.commit-msg }} 67 | part_value: ${{ steps.update-version.outputs.part_value }} 68 | tag-name: ${{ steps.update-version.outputs.tag-name }} 69 | extra-text: ${{ steps.update-version.outputs.extra-text }} 70 | steps: 71 | 72 | - name: Create App Token 73 | uses: actions/create-github-app-token@v1 74 | id: app-token 75 | with: 76 | app-id: ${{ vars.APP_ID }} 77 | private-key: ${{ secrets.APP_TOKEN }} 78 | 79 | - name: Check Out Repo 80 | uses: actions/checkout@v4 81 | with: 82 | token: ${{ secrets.PAT }} 83 | ref: ${{ github.event.pull_request.head.ref }} 84 | repository: ${{ github.event.pull_request.head.repo.full_name }} 85 | 86 | - name: Update VERSION File 87 | id: update-version 88 | run: | 89 | branch_name=${{ github.event.pull_request.head.ref }} 90 | repo_name=${{ github.event.pull_request.head.repo.full_name }} 91 | base_name="${repo_name%/*}" 92 | if [[ "${branch_name}" =~ ^(master|develop)$ ]]; then 93 | tag_name="${base_name}" 94 | else 95 | tag_name="${branch_name}" 96 | fi 97 | echo "tag-name=${tag_name}" >> $GITHUB_OUTPUT 98 | 99 | if [[ "${base_name}" == "Kometa-Team" ]]; then 100 | extra="" 101 | else 102 | extra=" from the ${{ github.event.pull_request.head.repo.full_name }} repo" 103 | fi 104 | echo "extra-text=${extra}" >> $GITHUB_OUTPUT 105 | 106 | value=$(cat VERSION) 107 | old_msg=$(git log -1 HEAD --pretty=format:%s) 108 | echo "commit-msg=${old_msg}" >> $GITHUB_OUTPUT 109 | 110 | part=$(cat PART) 111 | if [ -n "$part" ]; then 112 | new_value="$((${part} + 1))" 113 | else 114 | new_value="1" 115 | fi 116 | 117 | echo "part_value=${new_value}" >> $GITHUB_OUTPUT 118 | 119 | echo "$new_value" > "PART" 120 | git config --local user.email "action@github.com" 121 | git config --local user.name "GitHub Action" 122 | git add PART 123 | git commit -m "${tag_name} Part: ${new_value}" 124 | git push 125 | 126 | - name: Login to Docker Hub 127 | uses: docker/login-action@v3 128 | with: 129 | username: ${{ secrets.DOCKER_HUB_USERNAME }} 130 | password: ${{ secrets.DOCKER_HUB_ACCESS_TOKEN }} 131 | 132 | - name: Set up QEMU 133 | uses: docker/setup-qemu-action@master 134 | with: 135 | platforms: all 136 | 137 | - name: Set up Docker Buildx 138 | id: buildx 139 | uses: docker/setup-buildx-action@v3 140 | 141 | - name: Build and Push 142 | id: docker_build 143 | uses: docker/build-push-action@v6 144 | with: 145 | context: ./ 146 | file: ./Dockerfile 147 | build-args: | 148 | "BRANCH_NAME=${{ steps.update-version.outputs.tag-name }}" 149 | platforms: linux/amd64,linux/arm64 150 | push: true 151 | tags: ${{ vars.DOCKER_TEAM }}/${{ vars.DOCKER_REPO }}:${{ steps.update-version.outputs.tag-name }} 152 | cache-from: type=gha 153 | cache-to: type=gha,mode=max 154 | 155 | - name: Discord Success Notification 156 | uses: Kometa-Team/discord-notifications@master 157 | if: success() 158 | with: 159 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 160 | title: "${{ vars.REPO_NAME }} ${{ steps.update-version.outputs.tag-name }}: ${{ vars.TEXT_SUCCESS }}" 161 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 162 | color: ${{ vars.COLOR_SUCCESS }} 163 | username: ${{ vars.BOT_NAME }} 164 | avatar_url: ${{ vars.BOT_IMAGE }} 165 | author: ${{ vars.DOCKER_NAME }} 166 | author_icon_url: ${{ vars.DOCKER_IMAGE }} 167 | 168 | - name: Discord Failure Notification 169 | uses: Kometa-Team/discord-notifications@master 170 | if: failure() 171 | with: 172 | webhook_id_token: ${{ secrets.BUILD_WEBHOOK }} 173 | message: ${{ vars.BUILD_FAILURE_ROLE }} 174 | title: "${{ vars.REPO_NAME }} ${{ steps.update-version.outputs.tag-name }}: ${{ vars.TEXT_FAILURE }}" 175 | url: https://github.com/Kometa-Team/${{ vars.REPO_NAME }}/actions/runs/${{ github.run_id }} 176 | color: ${{ vars.COLOR_FAILURE }} 177 | username: ${{ vars.BOT_NAME }} 178 | avatar_url: ${{ vars.BOT_IMAGE }} 179 | author: ${{ vars.DOCKER_NAME }} 180 | author_icon_url: ${{ vars.DOCKER_IMAGE }} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Byte-compiled / optimized / DLL files 2 | __pycache__/ 3 | *.py[cod] 4 | *$py.class 5 | 6 | # C extensions 7 | *.so 8 | 9 | # Distribution / packaging 10 | .idea 11 | .vscode 12 | .Python 13 | /test* 14 | logs/ 15 | config/* 16 | !config/example.env 17 | build/ 18 | develop-eggs/ 19 | dist/ 20 | downloads/ 21 | eggs/ 22 | .eggs/ 23 | lib/ 24 | lib64/ 25 | parts/ 26 | sdist/ 27 | var/ 28 | wheels/ 29 | pip-wheel-metadata/ 30 | share/python-wheels/ 31 | *.egg-info/ 32 | .installed.cfg 33 | *.egg 34 | MANIFEST 35 | SECRETS 36 | 37 | # PyInstaller 38 | # Usually these files are written by a python script from a template 39 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 40 | *.manifest 41 | *.spec 42 | 43 | # Installer logs 44 | pip-log.txt 45 | pip-delete-this-directory.txt 46 | 47 | # Unit test / coverage reports 48 | htmlcov/ 49 | .tox/ 50 | .nox/ 51 | .coverage 52 | .coverage.* 53 | .cache 54 | nosetests.xml 55 | coverage.xml 56 | *.cover 57 | *.py,cover 58 | .hypothesis/ 59 | .pytest_cache/ 60 | 61 | # Translations 62 | *.mo 63 | *.pot 64 | 65 | # Django stuff: 66 | *.log 67 | local_settings.py 68 | db.sqlite3 69 | db.sqlite3-journal 70 | 71 | # Flask stuff: 72 | instance/ 73 | .webassets-cache 74 | 75 | # Scrapy stuff: 76 | .scrapy 77 | 78 | # Sphinx documentation 79 | docs/_build/ 80 | 81 | # PyBuilder 82 | target/ 83 | 84 | # Jupyter Notebook 85 | .ipynb_checkpoints 86 | 87 | # IPython 88 | profile_default/ 89 | ipython_config.py 90 | 91 | # pyenv 92 | .python-version 93 | 94 | # pipenv 95 | # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. 96 | # However, in case of collaboration, if having platform-specific dependencies or dependencies 97 | # having no cross-platform support, pipenv may install dependencies that don't work, or not 98 | # install all needed dependencies. 99 | #Pipfile.lock 100 | 101 | # PEP 582; used by e.g. github.com/David-OConnor/pyflow 102 | __pypackages__/ 103 | 104 | # Celery stuff 105 | celerybeat-schedule 106 | celerybeat.pid 107 | 108 | # SageMath parsed files 109 | *.sage.py 110 | 111 | # Environments 112 | .env 113 | .venv 114 | .direnv 115 | env/ 116 | venv/ 117 | ENV/ 118 | env.bak/ 119 | venv.bak/ 120 | pmm-venv/ 121 | kometa-venv/ 122 | 123 | # Spyder project settings 124 | .spyderproject 125 | .spyproject 126 | 127 | # Rope project settings 128 | .ropeproject 129 | 130 | # mkdocs documentation 131 | /site 132 | 133 | # mypy 134 | .mypy_cache/ 135 | .dmypy.json 136 | dmypy.json 137 | 138 | # Pyre type checker 139 | .pyre/ 140 | -------------------------------------------------------------------------------- /.spellcheck.yml: -------------------------------------------------------------------------------- 1 | matrix: 2 | - name: Markdown 3 | sources: 4 | - '**/*.md' 5 | - 'CHANGELOG' 6 | aspell: 7 | lang: en 8 | dictionary: 9 | wordlists: 10 | - .github/.wordlist.txt 11 | encoding: utf-8 12 | pipeline: 13 | - pyspelling.filters.markdown: 14 | - pyspelling.filters.html: 15 | comments: false 16 | ignores: 17 | - code 18 | - pre 19 | default_encoding: utf-8 -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.11-slim-buster 2 | ARG BRANCH_NAME=master 3 | ENV BRANCH_NAME ${BRANCH_NAME} 4 | ENV TINI_VERSION v0.19.0 5 | ENV KOMETA_DOCKER True 6 | COPY . / 7 | RUN echo "**** install system packages ****" \ 8 | && apt-get update \ 9 | && apt-get upgrade -y --no-install-recommends \ 10 | && apt-get install -y tzdata --no-install-recommends \ 11 | && apt-get install -y gcc g++ libxml2-dev libxslt-dev libz-dev libjpeg62-turbo-dev zlib1g-dev wget curl ffmpeg libsm6 libxext6 \ 12 | && wget -O /tini https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-"$(dpkg --print-architecture | awk -F- '{ print $NF }')" \ 13 | && chmod +x /tini \ 14 | && pip3 install --no-cache-dir --upgrade --requirement /requirements.txt \ 15 | && apt-get --purge autoremove gcc g++ libxml2-dev libxslt-dev libz-dev -y \ 16 | && apt-get clean \ 17 | && apt-get update \ 18 | && apt-get check \ 19 | && apt-get -f install \ 20 | && apt-get autoclean \ 21 | && rm -rf /requirements.txt /tmp/* /var/tmp/* /var/lib/apt/lists/* 22 | VOLUME /config 23 | ENTRYPOINT ["/tini", "-s", "python3", "overlay_reset.py", "--"] 24 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 meisnate12 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /PART: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Kometa Overlay Reset 2 | 3 | [![GitHub release (latest by date)](https://img.shields.io/github/v/release/Kometa-Team/Overlay-Reset?style=plastic)](https://github.com/Kometa-Team/Overlay-Reset/releases) 4 | [![Docker Image Version (latest semver)](https://img.shields.io/docker/v/kometateam/overlay-reset?label=docker&sort=semver&style=plastic)](https://hub.docker.com/r/kometateam/overlay-reset) 5 | [![Docker Pulls](https://img.shields.io/docker/pulls/kometateam/overlay-reset?style=plastic)](https://hub.docker.com/r/kometateam/overlay-reset) 6 | [![Develop GitHub commits since latest stable release (by SemVer)](https://img.shields.io/github/commits-since/Kometa-Team/Overlay-Reset/latest/develop?label=Commits%20in%20Develop&style=plastic)](https://github.com/Kometa-Team/Overlay-Reset/tree/develop) 7 | 8 | [![Discord](https://img.shields.io/discord/822460010649878528?color=%2300bc8c&label=Discord&style=plastic)](https://discord.gg/NfH6mGFuAB) 9 | [![Reddit](https://img.shields.io/reddit/subreddit-subscribers/Kometa?color=%2300bc8c&label=r%2FKometa&style=plastic)](https://www.reddit.com/r/Kometa/) 10 | [![Wiki](https://img.shields.io/readthedocs/kometa?color=%2300bc8c&style=plastic)](https://kometa.wiki/en/latest/home/scripts/overlay-reset.html) 11 | [![GitHub Sponsors](https://img.shields.io/github/sponsors/meisnate12?color=%238a2be2&style=plastic)](https://github.com/sponsors/meisnate12) 12 | [![Sponsor or Donate](https://img.shields.io/badge/-Sponsor%2FDonate-blueviolet?style=plastic)](https://github.com/sponsors/meisnate12) 13 | 14 | Kometa Overlay Reset is an open source Python 3 project that has been created to Remove all Overlays placed on a Plex Library. 15 | 16 | ## Installing Kometa Overlay Reset 17 | 18 | Generally, Kometa Overlay Reset can be installed in one of two ways: 19 | 20 | 1. Running on a system as a Python script [we will refer to this as a "local" install] 21 | 2. Running as a Docker container 22 | 23 | GENERALLY SPEAKING, running as a Docker container is simpler, as you won't have to be concerned about installing Python, or support libraries, or any possible system conflicts generated by those actions. 24 | 25 | For this reason, it's generally recommended that you install via Docker rather than directly on the host. 26 | 27 | If you have some specific reason to avoid Docker, or you prefer running it as a Python script for some particular reason, then this general recommendation is not aimed at you. It's aimed at someone who doesn't have an existing compelling reason to choose one over the other. 28 | 29 | ### Install Walkthroughs 30 | 31 | There are no detailed walkthroughs specifically for Kometa Overlay Reset but the process is extremely similar to how you would do it with [Kometa](https://kometa.wiki/en/latest/home/installation.html#install-walkthroughs). 32 | 33 | ### Local Install Overview 34 | 35 | Kometa Overlay Reset requires Python 3.11 or later. Later versions may function but are untested. 36 | 37 | These are high-level steps which assume the user has knowledge of python and pip, and the general ability to troubleshoot issues. 38 | 39 | 1. Clone or [download and unzip](https://github.com/Kometa-Team/Overlay-Reset/archive/refs/heads/master.zip) the repo. 40 | 41 | ```shell 42 | git clone https://github.com/Kometa-Team/Overlay-Reset 43 | ``` 44 | 2. Move into the script directory. 45 | 46 | ```shell 47 | cd Overlay-Reset 48 | ``` 49 | 3. Install dependencies (it's recommended to do this in a virtual environment): 50 | 51 | ```shell 52 | pip install -r requirements.txt 53 | ``` 54 | 55 | 4. If the above command fails, run the following command: 56 | 57 | ```shell 58 | pip install -r requirements.txt --ignore-installed 59 | ``` 60 | 61 | At this point Kometa-Overlay-Reset has been installed, and you can verify installation by running: 62 | 63 | ```shell 64 | python overlay_reset.py 65 | ``` 66 | 67 | ### Docker Install Overview 68 | 69 | #### Docker Run: 70 | 71 | ```shell 72 | docker run -v :/config:rw kometateam/overlay-reset 73 | ``` 74 | * The `-v :/config:rw` flag mounts the location you choose as a persistent volume to store your files. 75 | 76 | * Change `` to a folder where your .env and other files are. 77 | 78 | * If your directory has spaces (such as "My Documents"), place quotation marks around your directory pathing as shown here: `-v ":/config:rw"` 79 | 80 | Example Docker Run command: 81 | 82 | These docs are assuming you have a basic understanding of Docker concepts. One place to get familiar with Docker would be the [official tutorial](https://www.docker.com/101-tutorial/). 83 | 84 | ```shell 85 | docker run -v "X:\Media\Kometa Overlay Reset\config:/config:rw" kometateam/overlay-reset 86 | ``` 87 | 88 | #### Docker Compose: 89 | 90 | Example Docker Compose file: 91 | ```yaml 92 | services: 93 | overlay-reset: 94 | image: kometateam/overlay-reset 95 | container_name: overlay-reset 96 | environment: 97 | - TZ=TIMEZONE #optional 98 | volumes: 99 | - /path/to/config:/config 100 | restart: unless-stopped 101 | ``` 102 | 103 | #### Dockerfile 104 | 105 | A `Dockerfile` is included within the GitHub repository for those who require it, although this is only suggested for those with knowledge of dockerfiles. The official Kometa Overlay Reset build is available on the [Dockerhub Website](https://hub.docker.com/r/kometateam/overlay-reset). 106 | 107 | ## Options 108 | 109 | Each option can be applied in three ways: 110 | 111 | 1. Use the Shell Command when launching. 112 | 113 | 2. Setting the Environment Variable. 114 | 115 | 3. Adding the Environment Variables to `config/.env` 116 | 117 | | Option | Description | Required | 118 | |:------------------------|:------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|:--------:| 119 | | Plex URl | Plex URL of the Server you want to connect to.
**Shell Command:** `-u` or `--url "http://192.168.1.12:32400"`
**Environment Variable:** `PLEX_URL=http://192.168.1.12:32400` | ✅ | 120 | | Plex Token | Plex Token of the Server you want to connect to.
**Shell Command:** `-t` or `--token 123456789`
**Environment Variable:** `PLEX_TOKEN=123456789` | ✅ | 121 | | Plex Library | Plex Library Name you want to reset.
**Shell Command:** `-l` or `--library Movies`
**Environment Variable:** `PLEX_LIBRARY=Movies` | ✅ | 122 | | Kometa Asset Folder | Kometa Asset Folder to Scan for restoring posters.
**Shell Command:** `-a` or `--asset "C:\Kometa\config\assets"`
**Environment Variable:** `KOMETA_ASSET=C:\Kometa\config\assets` | ❌ | 123 | | Kometa Original Folder | Kometa Original Folder to Scan for restoring posters.
**Shell Command:** `-o` or `--original "C:\Kometa\config\overlays\Movies Original Posters"`
**Environment Variable:** `KOMETA_ORIGINAL=C:\Kometa\config\overlays\Movies Original Posters` | ❌ | 124 | | TMDb V3 API Key | TMDb V3 API Key for restoring posters from TMDb.
**Shell Command:** `-ta` or `--tmdbapi 123456789123456789`
**Environment Variable:** `TMDBAPI=123456789123456789` | ❌ | 125 | | Start From | Plex Item Title to Start restoring posters from.
**Shell Command:** `-st` or `--start "Mad Max"`
**Environment Variable:** `START=Mad Max` | ❌ | 126 | | Items | Restore specific Plex Items by Title. Can use a bar-separated (|) list.
**Shell Command:** `-it` or --items "Mad Max|Mad Max 2"
**Environment Variable:** ITEMS=Mad Max|Mad Max 2 | ❌ | 127 | | Labels | Additional labels to remove. Can use a bar-separated (|) list.
**Shell Command:** `-lb` or --labels "TCM|Other Label"
**Environment Variable:** LABELS=TCM|Other Label | ❌ | 128 | | Timeout | Timeout can be any number greater then 0. **Default:** `600`
**Shell Command:** `-ti` or `--timeout 1000`
**Environment Variable:** `TIMEOUT=1000` | ❌ | 129 | | Dry Run | Run as a Dry Run without making changes in Plex.
**Shell Command:** `-d` or `--dry`
**Environment Variable:** `DRY_RUN=True` | ❌ | 130 | | Flat Assets | Kometa Asset Folder uses [Flat Assets Image Paths](https://kometa.wiki/en/latest/home/guides/assets.html#asset-naming).
**Shell Command:** `-f` or `--flat`
**Environment Variable:** `KOMETA_FLAT=True` | ❌ | 131 | | Reset Main Posters | Do not restore Main Show/Movie posters during run.
**Shell Command:** `-nm` or `--no-main`
**Environment Variable:** `NO_MAIN=True` | ❌ | 132 | | Reset Season Posters | Restore Season posters during run.
**Shell Command:** `-s` or `--season`
**Environment Variable:** `SEASON=True` | ❌ | 133 | | Reset Episode Posters | Restore Episode posters during run.
**Shell Command:** `-e` or `--episode`
**Environment Variable:** `EPISODE=True` | ❌ | 134 | | Ignore Automatic Resume | Ignores the automatic resume.
**Shell Command:** `-ir` or `--ignore-resume`
**Environment Variable:** `IGNORE_RESUME=True` | ❌ | 135 | | Trace Logs | Run with extra trace logs.
**Shell Command:** `-tr` or `--trace`
**Environment Variable:** `TRACE=True` | ❌ | 136 | | Log Requests | Run with every request logged.
**Shell Command:** `-lr` or `--log-requests`
**Environment Variable:** `LOG_REQUESTS=True` | ❌ | 137 | 138 | ### Example .env File 139 | 140 | ``` 141 | PLEX_URL=http://192.168.1.12:32400 142 | PLEX_TOKEN=123456789 143 | PLEX_LIBRARY=Movies 144 | KOMETA_ASSET=C:\Kometa\config\assets 145 | KOMETA_ORIGINAL=C:\Kometa\config\overlays\Movies Original Posters 146 | TMDBAPI=123456789123456789 147 | START= 148 | ITEMS= 149 | LABELS= 150 | TIMEOUT=600 151 | DRY_RUN=True 152 | KOMETA_FLAT=False 153 | NO_MAIN=False 154 | SEASON=True 155 | EPISODE=True 156 | IGNORE_RESUME=False 157 | TRACE=False 158 | LOG_REQUESTS=False 159 | ``` 160 | -------------------------------------------------------------------------------- /VERSION: -------------------------------------------------------------------------------- 1 | 1.0.4 2 | -------------------------------------------------------------------------------- /config/example.env: -------------------------------------------------------------------------------- 1 | PLEX_URL=http://192.168.1.12:32400 2 | PLEX_TOKEN=123456789 3 | PLEX_LIBRARY=Movies 4 | KOMETA_ASSET=C:\Kometa\config\assets 5 | KOMETA_ORIGINAL=C:\Kometa\config\overlays\Movies Original Posters 6 | TMDBAPI=123456789123456789 7 | START= 8 | ITEMS= 9 | LABELS= 10 | TIMEOUT=600 11 | DRY_RUN=True 12 | KOMETA_FLAT=False 13 | NO_MAIN=False 14 | SEASON=True 15 | EPISODE=True 16 | IGNORE_RESUME=False 17 | TRACE=False 18 | LOG_REQUESTS=False -------------------------------------------------------------------------------- /overlay_reset.py: -------------------------------------------------------------------------------- 1 | import os, sys 2 | from xml.etree.ElementTree import ParseError 3 | from urllib.parse import quote 4 | 5 | if sys.version_info[0] != 3 or sys.version_info[1] < 11: 6 | print("Version Error: Version: %s.%s.%s incompatible please use Python 3.11+" % (sys.version_info[0], sys.version_info[1], sys.version_info[2])) 7 | sys.exit(0) 8 | 9 | try: 10 | import cv2, numpy, plexapi, requests 11 | from kometautils import util, KometaArgs, KometaLogger, Failed 12 | from PIL import Image, ImageFile, UnidentifiedImageError 13 | from plexapi.exceptions import BadRequest, NotFound, Unauthorized 14 | from plexapi.server import PlexServer 15 | from plexapi.video import Movie, Show, Season, Episode 16 | from tmdbapis import TMDbAPIs, TMDbException 17 | except (ModuleNotFoundError, ImportError) as e: 18 | print(e) 19 | print("Requirements Error: Requirements are not installed") 20 | sys.exit(0) 21 | 22 | options = [ 23 | {"arg": "u", "key": "url", "env": "PLEX_URL", "type": "str", "default": None, "help": "Plex URL of the Server you want to connect to."}, 24 | {"arg": "t", "key": "token", "env": "PLEX_TOKEN", "type": "str", "default": None, "help": "Plex Token of the Server you want to connect to."}, 25 | {"arg": "l", "key": "library", "env": "PLEX_LIBRARY", "type": "str", "default": None, "help": "Plex Library Name you want to reset."}, 26 | {"arg": "a", "key": "asset", "env": "KOMETA_ASSET", "type": "str", "default": None, "help": "Kometa Asset Folder to Scan for restoring posters."}, 27 | {"arg": "o", "key": "original", "env": "KOMETA_ORIGINAL", "type": "str", "default": None, "help": "Kometa Original Folder to Scan for restoring posters."}, 28 | {"arg": "ta", "key": "tmdbapi", "env": "TMDBAPI", "type": "str", "default": None, "help": "TMDb V3 API Key for restoring posters from TMDb."}, 29 | {"arg": "st", "key": "start", "env": "START", "type": "str", "default": None, "help": "Plex Item Title to Start restoring posters from."}, 30 | {"arg": "it", "key": "items", "env": "ITEMS", "type": "str", "default": None, "help": "Restore specific Plex Items by Title. Can use a bar-separated (|) list."}, 31 | {"arg": "lb", "key": "labels", "env": "LABELS", "type": "str", "default": None, "help": "Additional labels to remove. Can use a bar-separated (|) list."}, 32 | {"arg": "di", "key": "discord", "env": "DISCORD", "type": "str", "default": None, "help": "Webhook URL to channel for Notifications."}, 33 | {"arg": "ti", "key": "timeout", "env": "TIMEOUT", "type": "int", "default": 600, "help": "Timeout can be any number greater then 0. (Default: 600)"}, 34 | {"arg": "d", "key": "dry", "env": "DRY_RUN", "type": "bool", "default": False, "help": "Run as a Dry Run without making changes in Plex."}, 35 | {"arg": "f", "key": "flat", "env": "KOMETA_FLAT", "type": "bool", "default": False, "help": "Kometa Asset Folder uses Flat Assets Image Paths."}, 36 | {"arg": "nm", "key": "no-main", "env": "NO_MAIN", "type": "bool", "default": False, "help": "Do not restore the Main Movie/Show posters during run."}, 37 | {"arg": "s", "key": "season", "env": "SEASON", "type": "bool", "default": False, "help": "Restore Season posters during run."}, 38 | {"arg": "e", "key": "episode", "env": "EPISODE", "type": "bool", "default": False, "help": "Restore Episode posters during run."}, 39 | {"arg": "ir", "key": "ignore-resume", "env": "IGNORE_RESUME", "type": "bool", "default": None, "help": "Ignores the automatic resume."}, 40 | {"arg": "tr", "key": "trace", "env": "TRACE", "type": "bool", "default": False, "help": "Run with extra trace logs."}, 41 | {"arg": "lr", "key": "log-requests", "env": "LOG_REQUESTS", "type": "bool", "default": False, "help": "Run with every request logged."} 42 | ] 43 | script_name = "Overlay Reset" 44 | base_dir = os.path.dirname(os.path.abspath(__file__)) 45 | config_dir = os.path.join(base_dir, "config") 46 | resume_file = os.path.join(config_dir, "resume.kor") 47 | 48 | args = KometaArgs("Kometa-Team/Overlay-Reset", base_dir, options, use_nightly=False) 49 | logger = KometaLogger(script_name, "overlay_reset", os.path.join(config_dir, "logs"), discord_url=args["discord"], is_trace=args["trace"], log_requests=args["log-requests"]) 50 | logger.secret([args["url"], args["discord"], args["tmdbapi"], args["token"], quote(str(args["url"])), requests.utils.urlparse(args["url"]).netloc]) 51 | requests.Session.send = util.update_send(requests.Session.send, args["timeout"]) 52 | plexapi.BASE_HEADERS["X-Plex-Client-Identifier"] = args.uuid 53 | ImageFile.LOAD_TRUNCATED_IMAGES = True 54 | 55 | logger.header(args, sub=True, discord_update=True) 56 | logger.separator("Validating Options", space=False, border=False) 57 | try: 58 | logger.info("Script Started", log=False, discord=True, start="script") 59 | except Failed as e: 60 | logger.error(f"Discord URL Error: {e}") 61 | report = [] 62 | current_rk = None 63 | run_type = "" 64 | try: 65 | # Connect to Plex 66 | if not args["url"]: 67 | raise Failed("Error: No Plex URL Provided") 68 | if not args["token"]: 69 | raise Failed("Error: No Plex Token Provided") 70 | if not args["library"]: 71 | raise Failed("Error: No Plex Library Name Provided") 72 | try: 73 | server = PlexServer(args["url"], args["token"], timeout=args["timeout"]) 74 | plexapi.server.TIMEOUT = args["timeout"] 75 | os.environ["PLEXAPI_PLEXAPI_TIMEOUT"] = str(args["timeout"]) 76 | logger.info("Plex Connection Successful") 77 | except Unauthorized: 78 | raise Failed("Plex Error: Plex token is invalid") 79 | except (requests.exceptions.ConnectionError, ParseError): 80 | raise Failed("Plex Error: Plex url is invalid") 81 | lib = next((s for s in server.library.sections() if s.title == args["library"]), None) 82 | if not lib: 83 | raise Failed(f"Plex Error: Library: {args['library']} not found. Options: {', '.join([s.title for s in server.library.sections()])}") 84 | if lib.type not in ["movie", "show"]: 85 | raise Failed("Plex Error: Plex Library must be Movie or Show") 86 | 87 | # Connect to TMDb 88 | tmdbapi = None 89 | if args["tmdbapi"]: 90 | try: 91 | tmdbapi = TMDbAPIs(args["tmdbapi"]) 92 | logger.info("TMDb Connection Successful") 93 | except TMDbException as e: 94 | logger.error(e) 95 | 96 | # Check Labels 97 | labels = ["Overlay"] 98 | if args["labels"]: 99 | labels.extend(args["labels"].split("|")) 100 | logger.info(f"Labels to be Removed: {', '.join(labels)}") 101 | 102 | # Check for Overlay Files 103 | overlay_directory = os.path.join(base_dir, "overlays") 104 | config_overlay_directory = os.path.join(config_dir, "overlays") 105 | if not os.path.exists(overlay_directory): 106 | raise Failed(f"Folder Error: overlays Folder not found {os.path.abspath(overlay_directory)}") 107 | if not os.path.exists(config_overlay_directory): 108 | os.makedirs(config_overlay_directory) 109 | overlay_images = util.glob_filter(os.path.join(overlay_directory, "*.png")) + util.glob_filter(os.path.join(config_overlay_directory, "*.png")) 110 | if not overlay_images: 111 | raise Failed(f"Images Error: overlays Folder Images not found {os.path.abspath(os.path.join(overlay_directory, '*.png'))}") 112 | logger.info("overlays Folder Images Loaded Successfully ") 113 | 114 | # Check for Assets Folder 115 | assets_directory = os.path.join(base_dir, "assets") 116 | 117 | if os.path.exists(assets_directory) and os.listdir(assets_directory) and not args["asset"]: 118 | args["asset"] = assets_directory 119 | if args["asset"]: 120 | args["asset"] = os.path.abspath(args["asset"]) 121 | if not os.path.exists(args["asset"]): 122 | raise Failed(f"Folder Error: Asset Folder Path Not Found: {args['asset']}") 123 | logger.info(f"Asset Folder Loaded: {args['asset']}") 124 | else: 125 | logger.warning("No Asset Folder Found") 126 | 127 | # Check for Originals Folder 128 | originals_directory = os.path.join(base_dir, "originals") 129 | if os.path.exists(originals_directory) and os.listdir(originals_directory) and not args["original"]: 130 | args["original"] = originals_directory 131 | if args["original"]: 132 | args["original"] = os.path.abspath(args["original"]) 133 | if not os.path.exists(args["original"]): 134 | raise Failed(f"Folder Error: Original Folder Path Not Found: {os.path.abspath(args['original'])}") 135 | logger.info(f"Originals Folder Loaded: {args['original']}") 136 | else: 137 | logger.warning("No Originals Folder Found") 138 | 139 | def detect_overlay_in_image(item_title, poster_source, shape, img_path=None, url_path=None): 140 | out_path = img_path 141 | if url_path: 142 | img_path = util.download_image(url_path, config_dir) 143 | out_path = url_path 144 | try: 145 | logger.trace(f"{img_path}: {os.path.exists(img_path)}") 146 | with Image.open(img_path) as pil_image: 147 | exif_tags = pil_image.getexif() 148 | if 0x04bc in exif_tags and exif_tags[0x04bc] == "overlay": 149 | logger.debug(f"Overlay Detected: EXIF Overlay Tag Found ignoring {poster_source}: {out_path}") 150 | return True 151 | if (shape == "portrait" and pil_image.size != (1000, 1500)) or (shape == "landscape" and pil_image.size != (1920, 1080)): 152 | logger.debug("No Overlay: Image not standard overlay size") 153 | return False 154 | 155 | logger.trace(f"{img_path}: {os.path.exists(img_path)}") 156 | target = cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) 157 | if target is None: 158 | logger.error(f"Image Load Error: {poster_source}: {out_path}", group=item_title) 159 | return None 160 | if target.shape[0] < 500 or target.shape[1] < 500: 161 | logger.info(f"Image Error: {poster_source}: Dimensions {target.shape[0]}x{target.shape[1]} must be greater then 500x500: {out_path}") 162 | return False 163 | for overlay_image in overlay_images: 164 | overlay = cv2.imread(overlay_image, cv2.IMREAD_GRAYSCALE) 165 | if overlay is None: 166 | logger.error(f"Image Load Error: {overlay_image}", group=item_title) 167 | continue 168 | 169 | if overlay.shape[0] > target.shape[0] or overlay.shape[1] > target.shape[1]: 170 | logger.error(f"Image Error: {overlay_image} is larger than {poster_source}: {out_path}", group=item_title) 171 | continue 172 | 173 | template_result = cv2.matchTemplate(target, overlay, cv2.TM_CCOEFF_NORMED) 174 | loc = numpy.where(template_result >= 0.95) 175 | 176 | if len(loc[0]) == 0: 177 | continue 178 | logger.debug(f"Overlay Detected: {overlay_image} found in {poster_source}: {out_path} with score {template_result.max()}") 179 | return True 180 | return False 181 | except Exception: 182 | logger.stacktrace() 183 | logger.error(f"Image Load Error: {poster_source}: {out_path}", group=item_title) 184 | return None 185 | 186 | def reset_from_plex(item_title, item_with_posters, shape, ignore=0): 187 | for p, plex_poster in enumerate(item_with_posters.posters(), 1): 188 | logger.trace(f"Poster URL: {plex_poster.key}") 189 | reset_url = None 190 | if plex_poster.key.startswith("/"): 191 | temp_url = f"{args['url']}{plex_poster.key}&X-Plex-Token={args['token']}" 192 | user = plex_poster.ratingKey.startswith("upload") 193 | if not user or (user and detect_overlay_in_image(item_title, f"Plex Poster {p}", shape, url_path=temp_url) is False): 194 | reset_url = temp_url 195 | else: 196 | reset_url = plex_poster.key 197 | if reset_url: 198 | if ignore < 1: 199 | return reset_url 200 | else: 201 | ignore -= 1 202 | 203 | def reset_poster(item_title, plex_item, tmdb_poster_url, asset_directory, asset_file_name, parent=None, shape="portrait"): 204 | poster_source = None 205 | poster_path = None 206 | 207 | # Check Assets 208 | if asset_directory: 209 | asset_matches = util.glob_filter(os.path.join(asset_directory, f"{asset_file_name}.*")) 210 | if len(asset_matches) > 0: 211 | poster_source = "Assets Folder" 212 | poster_path = asset_matches[0] 213 | else: 214 | logger.info("No Asset Found") 215 | 216 | # Check Original Folder 217 | if not poster_source and args["original"]: 218 | png = os.path.join(args["original"], f"{plex_item.ratingKey}.png") 219 | jpg = os.path.join(args["original"], f"{plex_item.ratingKey}.jpg") 220 | if os.path.exists(png) and detect_overlay_in_image(item_title, "Original Poster", shape, img_path=png) is False: 221 | poster_source = "Originals Folder" 222 | poster_path = png 223 | elif os.path.exists(jpg) and detect_overlay_in_image(item_title, "Original Poster", shape, img_path=jpg) is False: 224 | poster_source = "Originals Folder" 225 | poster_path = jpg 226 | else: 227 | logger.info("No Original Found") 228 | 229 | # Check Plex 230 | if not poster_source: 231 | poster_path = reset_from_plex(item_title, plex_item, shape) 232 | if poster_path: 233 | poster_source = "Plex" 234 | else: 235 | logger.info("No Clean Plex Image Found") 236 | 237 | # TMDb 238 | if not poster_source: 239 | if tmdb_poster_url: 240 | poster_source = "TMDb" 241 | poster_path = tmdb_poster_url 242 | else: 243 | logger.info("No TMDb Image Found") 244 | 245 | # Check Item's Show 246 | if not poster_source and parent: 247 | poster_path = reset_from_plex(item_title, parent, shape) 248 | if poster_path: 249 | poster_source = "Plex's Show" 250 | else: 251 | logger.info("No Clean Plex Show Image Found") 252 | 253 | def upload(attempt=0): 254 | nonlocal poster_path 255 | is_url = poster_source in ["TMDb", "Plex", "Plex's Show"] 256 | try: 257 | if args["dry"]: 258 | logger.info(f"Poster will be Reset by {'URL' if is_url else 'File'} from {poster_source}") 259 | else: 260 | logger.info(f"Reset From {poster_source}") 261 | logger.info(f"{'URL' if is_url else 'File'} Path: {poster_path}") 262 | if is_url: 263 | plex_item.uploadPoster(url=poster_path) 264 | else: 265 | plex_item.uploadPoster(filepath=poster_path) 266 | except BadRequest as eb: 267 | logger.error(eb, group=item_title) 268 | if poster_source in ["Plex", "Plex's Show"]: 269 | attempt += 1 270 | logger.info(f"Trying next poster #{attempt + 1}") 271 | if poster_source == "Plex": 272 | poster_path = reset_from_plex(item_title, plex_item, shape, ignore=attempt) 273 | if not poster_path: 274 | logger.info("No Clean Plex Image Found") 275 | if poster_source == "Plex's Show": 276 | poster_path = reset_from_plex(item_title, parent, shape, ignore=attempt) 277 | if not poster_path: 278 | logger.info("No Clean Plex Show Image Found") 279 | if poster_path: 280 | upload(attempt=attempt) 281 | else: 282 | item_labels = [la.tag for la in plex_item.labels] 283 | remove_labels = [la for la in labels if la in item_labels] 284 | if remove_labels: 285 | if not args["dry"]: 286 | for label in remove_labels: 287 | plex_item.removeLabel(label) 288 | logger.info(f"Labels Removed: {', '.join(remove_labels)}") 289 | else: 290 | logger.info(f"Labels To Be Removed: {', '.join(remove_labels)}") 291 | else: 292 | logger.info("No Labels to Remove") 293 | 294 | # Upload poster and Remove "Overlay" Label 295 | if poster_source: 296 | upload() 297 | else: 298 | logger.error("Image Error: No Image Found to Restore", group=item_title) 299 | 300 | def get_title(plex_item): 301 | if isinstance(plex_item, Movie): 302 | return f"Movie: {item.title}" 303 | elif isinstance(plex_item, Show): 304 | return f"Show: {item.title}" 305 | elif isinstance(plex_item, Season): 306 | if season.title == f"Season {season.seasonNumber}": 307 | return season.title 308 | return f"Season {season.seasonNumber}: {season.title}" 309 | elif isinstance(plex_item, Episode): 310 | return f"Episode {episode.seasonEpisode.upper()}: {episode.title}" 311 | else: 312 | return f"Item: {item.title}" 313 | 314 | def reload(plex_item): 315 | try: 316 | plex_item.reload(checkFiles=False, includeAllConcerts=False, includeBandwidths=False, includeChapters=False, 317 | includeChildren=False, includeConcerts=False, includeExternalMedia=False, includeExtras=False, 318 | includeFields=False, includeGeolocation=False, includeLoudnessRamps=False, includeMarkers=False, 319 | includeOnDeck=False, includePopularLeaves=False, includeRelated=False, includeRelatedCount=0, 320 | includeReviews=False, includeStations=False) 321 | plex_item._autoReload = False 322 | except (BadRequest, NotFound) as e1: 323 | raise Failed(f"Plex Error: {get_title(plex_item)} Failed to Load: {e1}") 324 | 325 | start_from = None 326 | run_items = [] 327 | resume_rk = None 328 | if args["items"]: 329 | run_items = [rs for r in args["items"].split("|") if (rs := r.strip())] 330 | if len(run_items) > 1: 331 | str_items = "" 332 | current = "" 333 | for r in run_items[:-1]: 334 | current += f"{r}, " 335 | if len(current) > 75: 336 | str_items += f"{current}\n" 337 | current = "" 338 | str_items += f"and {run_items[-1]}" 339 | else: 340 | str_items = run_items[0] 341 | logger.separator(f"Resetting Specific Posters\n{str_items}") 342 | run_type = "of Specific Items " 343 | elif args["start"]: 344 | start_from = args["start"] 345 | logger.separator(f'Resetting Posters\nStarting From "{start_from}"') 346 | run_type = f'Starting From "{start_from}" ' 347 | elif not args["ignore-resume"] and os.path.exists(resume_file): 348 | with open(resume_file) as handle: 349 | for line in handle.readlines(): 350 | line = line.strip() 351 | if len(line) > 0: 352 | resume_rk = str(line).strip() 353 | break 354 | os.remove(resume_file) 355 | if resume_rk: 356 | logger.separator(f'Resetting Posters\nStarting From Rating Key "{resume_rk}"') 357 | run_type = f'Starting From Rating Key "{resume_rk}" ' 358 | if not run_items and not start_from and not resume_rk: 359 | logger.separator("Resetting All Posters") 360 | 361 | items = lib.all() 362 | total_items = len(items) 363 | for i, item in enumerate(items): 364 | if run_items or start_from or resume_rk: 365 | if (run_items and item.title not in run_items) or \ 366 | (start_from and item.title != start_from) or \ 367 | (resume_rk and str(item.ratingKey) != resume_rk): 368 | logger.info(f"Skipping {i + 1}/{total_items} {item.title}") 369 | continue 370 | elif start_from: 371 | start_from = None 372 | elif resume_rk: 373 | resume_rk = None 374 | title = item.title 375 | current_rk = item.ratingKey 376 | logger.separator(f"Resetting {i + 1}/{total_items} {title}", start="reset") 377 | try: 378 | reload(item) 379 | except Failed as e: 380 | logger.error(e, group=title) 381 | continue 382 | 383 | # Find Item's Kometa Asset Directory 384 | item_asset_directory = None 385 | asset_name = None 386 | if args["asset"]: 387 | if not item.locations: 388 | logger.error(f"Asset Error: No video filepath found fo {title}", group=title) 389 | else: 390 | file_name = "poster" 391 | path_test = str(item.locations[0]) 392 | if not os.path.dirname(path_test): 393 | path_test = path_test.replace("\\", "/") 394 | asset_name = util.validate_filename(os.path.basename(os.path.dirname(path_test) if isinstance(item, Movie) else path_test)) 395 | if args["flat"]: 396 | item_asset_directory = args["asset"] 397 | file_name = asset_name 398 | elif os.path.isdir(os.path.join(args["asset"], asset_name)): 399 | item_asset_directory = os.path.join(args["asset"], asset_name) 400 | else: 401 | for n in range(1, 5): 402 | new_path = args["asset"] 403 | for m in range(1, n + 1): 404 | new_path = os.path.join(new_path, "*") 405 | matches = util.glob_filter(os.path.join(new_path, asset_name)) 406 | if len(matches) > 0: 407 | item_asset_directory = os.path.abspath(matches[0]) 408 | break 409 | if not item_asset_directory: 410 | logger.warning(f"Asset Warning: No Asset Directory Found") 411 | 412 | tmdb_item = None 413 | if tmdbapi: 414 | guid = requests.utils.urlparse(item.guid) # noqa 415 | item_type = guid.scheme.split(".")[-1] 416 | check_id = guid.netloc 417 | tmdb_id = None 418 | tvdb_id = None 419 | imdb_id = None 420 | if item_type == "plex": 421 | for guid_tag in item.guids: 422 | url_parsed = requests.utils.urlparse(guid_tag.id) # noqa 423 | if url_parsed.scheme == "tvdb": 424 | tvdb_id = int(url_parsed.netloc) 425 | elif url_parsed.scheme == "imdb": 426 | imdb_id = url_parsed.netloc 427 | elif url_parsed.scheme == "tmdb": 428 | tmdb_id = int(url_parsed.netloc) 429 | if not tvdb_id and not imdb_id and not tmdb_id: 430 | item.refresh() 431 | elif item_type == "imdb": 432 | imdb_id = check_id 433 | elif item_type == "thetvdb": 434 | tvdb_id = int(check_id) 435 | elif item_type == "themoviedb": 436 | tmdb_id = int(check_id) 437 | elif item_type in ["xbmcnfo", "xbmcnfotv"]: 438 | if len(check_id) > 10: 439 | logger.warning(f"XMBC NFO Local ID: {check_id}") 440 | try: 441 | if item_type == "xbmcnfo": 442 | tmdb_id = int(check_id) 443 | else: 444 | tvdb_id = int(check_id) 445 | except ValueError: 446 | imdb_id = check_id 447 | if not tvdb_id and not imdb_id and not tmdb_id: 448 | logger.error("Plex Error: No External GUIDs found", group=title) 449 | if not tmdb_id and imdb_id: 450 | try: 451 | results = tmdbapi.find_by_id(imdb_id=imdb_id) 452 | if results.movie_results and isinstance(item, Movie): 453 | tmdb_id = results.movie_results[0].id 454 | elif results.tv_results and isinstance(item, Show): 455 | tmdb_id = results.tv_results[0].id 456 | except TMDbException as e: 457 | logger.warning(e, group=title) 458 | if not tmdb_id and tvdb_id and isinstance(item, Show): 459 | try: 460 | results = tmdbapi.find_by_id(tvdb_id=tvdb_id) 461 | if results.tv_results: 462 | tmdb_id = results.tv_results[0].id 463 | except TMDbException as e: 464 | logger.warning(e, group=title) 465 | if tmdb_id: 466 | try: 467 | tmdb_item = tmdbapi.movie(tmdb_id) if isinstance(item, Movie) else tmdbapi.tv_show(tmdb_id) 468 | except TMDbException as e: 469 | logger.error(f"TMDb Error: {e}", group=title) 470 | else: 471 | logger.error("Plex Error: TMDb ID Not Found", group=title) 472 | 473 | if not args["no-main"]: 474 | reset_poster(title, item, tmdb_item.poster_url if tmdb_item else None, item_asset_directory, asset_name if args["flat"] else "poster") 475 | 476 | logger.info(f"Runtime: {logger.runtime('reset')}") 477 | 478 | if isinstance(item, Show) and (args["season"] or args["episode"]): 479 | tmdb_seasons = {s.season_number: s for s in tmdb_item.seasons} if tmdb_item else {} 480 | for season in item.seasons(): 481 | title = f"Season {season.seasonNumber}" 482 | title = title if title == season.title else f"{title}: {season.title}" 483 | title = f"{item.title}\n {title}" 484 | if args["season"]: 485 | logger.separator(f"Resetting {title}", start="reset") 486 | try: 487 | reload(season) 488 | except Failed as e: 489 | logger.error(e, group=title) 490 | continue 491 | tmdb_poster = tmdb_seasons[season.seasonNumber].poster_url if season.seasonNumber in tmdb_seasons else None 492 | file_name = f"Season{'0' if not season.seasonNumber or season.seasonNumber < 10 else ''}{season.seasonNumber}" 493 | reset_poster(title, season, tmdb_poster, item_asset_directory, f"{asset_name}_{file_name}" if args["flat"] else file_name, parent=item) 494 | 495 | logger.info(f"Runtime: {logger.runtime('reset')}") 496 | 497 | if args["episode"]: 498 | if not args["season"]: 499 | try: 500 | reload(season) 501 | except Failed as e: 502 | logger.error(e, group=title) 503 | continue 504 | tmdb_episodes = {} 505 | if season.seasonNumber in tmdb_seasons: 506 | for episode in tmdb_seasons[season.seasonNumber].episodes: 507 | episode._partial = False 508 | try: 509 | tmdb_episodes[episode.episode_number] = episode 510 | except TMDbException: 511 | logger.error(f"TMDb Error: An Episode of Season {season.seasonNumber} was Not Found", group=title) 512 | 513 | for episode in season.episodes(): 514 | title = f"{item.title}\nEpisode {episode.seasonEpisode.upper()}: {episode.title}" 515 | logger.separator(f"Resetting {title}", start="reset") 516 | try: 517 | reload(episode) 518 | except Failed as e: 519 | logger.error(e, group=title) 520 | continue 521 | tmdb_poster = tmdb_episodes[episode.episodeNumber].still_url if episode.episodeNumber in tmdb_episodes else None 522 | file_name = episode.seasonEpisode.upper() 523 | reset_poster(title, episode, tmdb_poster, item_asset_directory, f"{asset_name}_{file_name}" if args["flat"] else file_name, shape="landscape") 524 | logger.info(f"Runtime: {logger.runtime('reset')}") 525 | 526 | current_rk = None 527 | except Failed as e: 528 | logger.separator() 529 | logger.critical(e, discord=True) 530 | logger.separator() 531 | except Exception as e: 532 | logger.separator() 533 | logger.stacktrace() 534 | logger.critical(e, discord=True) 535 | logger.separator() 536 | except KeyboardInterrupt: 537 | if current_rk: 538 | with open(resume_file, "w") as handle: 539 | handle.write(str(current_rk)) 540 | logger.separator(f"User Canceled Run {script_name}") 541 | raise 542 | 543 | if current_rk: 544 | with open(resume_file, "w") as handle: 545 | handle.write(str(current_rk)) 546 | 547 | logger.error_report() 548 | logger.switch() 549 | report.append([(f"{script_name} Finished", "")]) 550 | report.append([("Total Runtime", f"{logger.runtime()}")]) 551 | description = f"{args['library']} Library{' Dry' if args['dry'] else ''} Run {run_type}Finished" 552 | logger.report(f"{script_name} Summary", description=description, rows=report, width=18, discord=True) 553 | -------------------------------------------------------------------------------- /overlays/1080P-DV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/1080P-DV.png -------------------------------------------------------------------------------- /overlays/1080P-HDR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/1080P-HDR.png -------------------------------------------------------------------------------- /overlays/1080P.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/1080P.png -------------------------------------------------------------------------------- /overlays/480P-DV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/480P-DV.png -------------------------------------------------------------------------------- /overlays/480P-HDR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/480P-HDR.png -------------------------------------------------------------------------------- /overlays/480P.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/480P.png -------------------------------------------------------------------------------- /overlays/4K-DV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/4K-DV.png -------------------------------------------------------------------------------- /overlays/4K-HDR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/4K-HDR.png -------------------------------------------------------------------------------- /overlays/4K.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/4K.png -------------------------------------------------------------------------------- /overlays/576P-DV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/576P-DV.png -------------------------------------------------------------------------------- /overlays/576P-HDR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/576P-HDR.png -------------------------------------------------------------------------------- /overlays/576P.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/576P.png -------------------------------------------------------------------------------- /overlays/720P-DV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/720P-DV.png -------------------------------------------------------------------------------- /overlays/720P-HDR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/720P-HDR.png -------------------------------------------------------------------------------- /overlays/720P.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/720P.png -------------------------------------------------------------------------------- /overlays/AAC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/AAC.png -------------------------------------------------------------------------------- /overlays/Amazon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Amazon.png -------------------------------------------------------------------------------- /overlays/Anniversary-Edition-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Anniversary-Edition-Box.png -------------------------------------------------------------------------------- /overlays/AppleTV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/AppleTV.png -------------------------------------------------------------------------------- /overlays/CSS-Families-Movies-Ribbon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/CSS-Families-Movies-Ribbon.png -------------------------------------------------------------------------------- /overlays/Collectors-Edition-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Collectors-Edition-Box.png -------------------------------------------------------------------------------- /overlays/Criterion-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Criterion-Box.png -------------------------------------------------------------------------------- /overlays/DTS-ES.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/DTS-ES.png -------------------------------------------------------------------------------- /overlays/DTS-HD-HRA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/DTS-HD-HRA.png -------------------------------------------------------------------------------- /overlays/DTS-HD-MA.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/DTS-HD-MA.png -------------------------------------------------------------------------------- /overlays/DTS-HD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/DTS-HD.png -------------------------------------------------------------------------------- /overlays/DTS-X.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/DTS-X.png -------------------------------------------------------------------------------- /overlays/DTS.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/DTS.png -------------------------------------------------------------------------------- /overlays/DV.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/DV.png -------------------------------------------------------------------------------- /overlays/Direct-Play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Direct-Play.png -------------------------------------------------------------------------------- /overlays/Directors-Cut-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Directors-Cut-Box.png -------------------------------------------------------------------------------- /overlays/Disney.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Disney.png -------------------------------------------------------------------------------- /overlays/Dolby-Atmos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Dolby-Atmos.png -------------------------------------------------------------------------------- /overlays/Dolby-Digital-Plus-Atmos-Filepath.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Dolby-Digital-Plus-Atmos-Filepath.png -------------------------------------------------------------------------------- /overlays/Dolby-Digital-Plus-Atmos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Dolby-Digital-Plus-Atmos.png -------------------------------------------------------------------------------- /overlays/Dolby-Digital-Plus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Dolby-Digital-Plus.png -------------------------------------------------------------------------------- /overlays/Dolby-Digital.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Dolby-Digital.png -------------------------------------------------------------------------------- /overlays/Dolby-TrueHD-Atmos.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Dolby-TrueHD-Atmos.png -------------------------------------------------------------------------------- /overlays/Dolby-TrueHD.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Dolby-TrueHD.png -------------------------------------------------------------------------------- /overlays/Dual-Audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Dual-Audio.png -------------------------------------------------------------------------------- /overlays/Extended-Edition-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Extended-Edition-Box.png -------------------------------------------------------------------------------- /overlays/FLAC.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/FLAC.png -------------------------------------------------------------------------------- /overlays/Final-Cut-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Final-Cut-Box.png -------------------------------------------------------------------------------- /overlays/HBO-Max.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/HBO-Max.png -------------------------------------------------------------------------------- /overlays/HDR.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/HDR.png -------------------------------------------------------------------------------- /overlays/Hulu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Hulu.png -------------------------------------------------------------------------------- /overlays/IMAX-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/IMAX-Box.png -------------------------------------------------------------------------------- /overlays/IMAX-E-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/IMAX-E-Box.png -------------------------------------------------------------------------------- /overlays/IMDB-Top-250.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/IMDB-Top-250.png -------------------------------------------------------------------------------- /overlays/IMDb-black.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/IMDb-black.png -------------------------------------------------------------------------------- /overlays/IMDb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/IMDb.png -------------------------------------------------------------------------------- /overlays/International-Cut-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/International-Cut-Box.png -------------------------------------------------------------------------------- /overlays/MC-Must-See-Movies-Ribbon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/MC-Must-See-Movies-Ribbon.png -------------------------------------------------------------------------------- /overlays/MP3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/MP3.png -------------------------------------------------------------------------------- /overlays/Mediastinger.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Mediastinger.png -------------------------------------------------------------------------------- /overlays/Multi-Audio.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Multi-Audio.png -------------------------------------------------------------------------------- /overlays/Netflix.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Netflix.png -------------------------------------------------------------------------------- /overlays/Opus.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Opus.png -------------------------------------------------------------------------------- /overlays/Oscars-Ribbon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Oscars-Ribbon.png -------------------------------------------------------------------------------- /overlays/PCM.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/PCM.png -------------------------------------------------------------------------------- /overlays/Paramount.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Paramount.png -------------------------------------------------------------------------------- /overlays/Peacock.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Peacock.png -------------------------------------------------------------------------------- /overlays/RT-Cert-Fresh-Ribbon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/RT-Cert-Fresh-Ribbon.png -------------------------------------------------------------------------------- /overlays/RT-Cert-Fresh.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/RT-Cert-Fresh.png -------------------------------------------------------------------------------- /overlays/Remastered-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Remastered-Box.png -------------------------------------------------------------------------------- /overlays/Special-Edition-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Special-Edition-Box.png -------------------------------------------------------------------------------- /overlays/TMDb.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/TMDb.png -------------------------------------------------------------------------------- /overlays/Theatrical-Cut-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Theatrical-Cut-Box.png -------------------------------------------------------------------------------- /overlays/Ultimate-Cut-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Ultimate-Cut-Box.png -------------------------------------------------------------------------------- /overlays/Uncut-Edition-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Uncut-Edition-Box.png -------------------------------------------------------------------------------- /overlays/Unrated-Edition-Box.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/Unrated-Edition-Box.png -------------------------------------------------------------------------------- /overlays/YouTube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/YouTube.png -------------------------------------------------------------------------------- /overlays/css.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/css.png -------------------------------------------------------------------------------- /overlays/flix-metacritic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/flix-metacritic.png -------------------------------------------------------------------------------- /overlays/flix-prime.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/flix-prime.png -------------------------------------------------------------------------------- /overlays/metacritic-mustsee.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/metacritic-mustsee.png -------------------------------------------------------------------------------- /overlays/rt-cert.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/rt-cert.png -------------------------------------------------------------------------------- /overlays/rt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Kometa-Team/Overlay-Reset/6ad11118cf54876ac2fbf57841e858c99c8a64c1/overlays/rt.png -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | numpy==2.1.1 2 | opencv-python==4.10.0.84 3 | pillow==10.4.0 4 | PlexAPI==4.15.16 5 | kometautils==0.3.4 6 | requests==2.32.3 7 | tmdbapis==1.2.21 --------------------------------------------------------------------------------