Compare commits

..

92 Commits

Author SHA1 Message Date
CodeDevMLH
1872a744a7 Update manifest.json for release v1.3.0.0 [skip ci] 2026-02-04 00:07:16 +00:00
CodeDevMLH
83441a3c4f Bump version to 1.3.0.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 1m0s
2026-02-04 01:06:22 +01:00
CodeDevMLH
49ad41c3f6 Enhance custom media ID functionality with manual trailer override 2026-02-04 01:06:12 +01:00
CodeDevMLH
984a41b180 Update manifest.json for release v1.2.3.7 [skip ci] 2026-01-28 22:39:54 +00:00
CodeDevMLH
c8421d12b0 Bump version to 1.2.3.7 and update changelog for release
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 57s
2026-01-28 23:39:03 +01:00
CodeDevMLH
b5d38629d2 Update manifest.json for release v1.2.3.6 [skip ci] 2026-01-28 21:31:54 +00:00
CodeDevMLH
8f4adece49 Bump version to 1.2.3.6 and update changelog for release
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 58s
2026-01-28 22:31:01 +01:00
CodeDevMLH
cfebccc289 Update manifest.json for release v1.2.3.5 [skip ci] 2026-01-28 20:21:21 +00:00
CodeDevMLH
2613fd7acf Update version to 1.2.3.5 in project file and manifest.json
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 1m20s
2026-01-28 21:20:06 +01:00
CodeDevMLH
bb10b9c15e Merge branch 'main' of ssh://git.mahom03-spacecloud.de:44322/CodeDevMLH/jellyfin-plugin-media-bar-enhanced 2026-01-28 21:16:52 +01:00
CodeDevMLH
a9ad8d65e4 Merge branch 'main' of ssh://git.mahom03-spacecloud.de:44322/CodeDevMLH/jellyfin-plugin-media-bar-enhanced [skip-ci] 2026-01-28 02:15:28 +01:00
CodeDevMLH
e7232da38b Update manifest.json for release v1.2.3.4 [skip ci] 2026-01-28 01:09:39 +00:00
CodeDevMLH
53bd1d23c7 Update manifest.json for release v1.2.3.4 with changelog and source URL adjustments
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 57s
2026-01-28 02:07:25 +01:00
CodeDevMLH
5643ebfd28 Update manifest.json for release v1.2.3.3 [skip ci] 2026-01-28 01:05:46 +00:00
CodeDevMLH
bed2fbaa76 Bump version to 1.2.3.4 and update release automation to generate commit log
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 58s
2026-01-28 02:04:45 +01:00
CodeDevMLH
05f64bc3d7 Update manifest.json for release v1.2.3.3 [skip ci] 2026-01-28 00:45:20 +00:00
CodeDevMLH
277433581c Bump version to 1.2.3.3 and update manifest with changelog for button positioning adjustments
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 58s
2026-01-28 01:44:23 +01:00
CodeDevMLH
44f0b1cb38 Update manifest.json for release v1.2.3.2 [skip ci] 2026-01-28 00:30:37 +00:00
CodeDevMLH
d31dcbabdc Bump version to 1.2.3.2 and update manifest with changelog for button adjustments on small screens
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 1m1s
2026-01-28 01:29:42 +01:00
CodeDevMLH
4ed6509505 Update manifest.json for release v1.2.3.1 [skip ci] 2026-01-28 00:17:29 +00:00
CodeDevMLH
6427b8422a Bump version to 1.2.3.1 and update manifest with changelog for button layout adjustments on small screens
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 56s
2026-01-28 01:16:38 +01:00
CodeDevMLH
ebfbe1d563 Update manifest.json for release v1.2.3.0 [skip ci] 2026-01-27 23:54:43 +00:00
CodeDevMLH
67e5d8e4d2 Bump version to 1.2.3.0 and update manifest with changelog for button display fixes on small screens
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 56s
2026-01-28 00:53:50 +01:00
CodeDevMLH
d68ba7e846 Update manifest.json for release v1.2.2.0 [skip ci] 2026-01-24 22:53:55 +00:00
CodeDevMLH
0444cf333d Bump version to 1.2.2.0 and update manifest with changelog for visibility fixes
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 1m0s
2026-01-24 23:52:59 +01:00
CodeDevMLH
10279e97d9 Comment out CHANGELOG body in release automation workflow 2026-01-23 01:18:22 +01:00
CodeDevMLH
f6ccd0ea5f Update manifest.json for release v1.2.1.0 [skip ci] 2026-01-22 23:50:56 +00:00
CodeDevMLH
47827df047 Update mediaBarEnhanced.js and mediaBarEnhanced.css with version 3.0.8 from original repo
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 1m0s
2026-01-23 00:50:01 +01:00
CodeDevMLH
7fd781c9d0 Update manifest.json for release v1.2.0.0 [skip ci] 2026-01-08 23:30:58 +00:00
CodeDevMLH
6faa8f1a4c Update plugin description in manifest.json for clarity and completeness
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 1m4s
2026-01-09 00:30:00 +01:00
CodeDevMLH
3e05ff1dc9 Update manifest.json for release v1.2.0.0 [skip ci] 2026-01-08 23:15:07 +00:00
CodeDevMLH
fa06179cd3 Update manifest.json to enhance plugin description and overview
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 55s
2026-01-09 00:14:16 +01:00
CodeDevMLH
d8327fc5c9 Update manifest.json for release v1.2.0.0 [skip ci] 2026-01-08 22:16:05 +00:00
CodeDevMLH
9ffe03f0df Update version to 1.2.0.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 57s
2026-01-08 23:15:13 +01:00
CodeDevMLH
37e99d7fed Add Preferred Video Quality setting and update playback quality logic 2026-01-08 23:14:59 +01:00
CodeDevMLH
9b0e3762ac Update manifest.json for release v1.1.2.0 [skip ci] 2026-01-08 15:26:55 +00:00
CodeDevMLH
48f93e3480 Update version to 1.1.2.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 53s
2026-01-08 16:26:04 +01:00
CodeDevMLH
2e9c093cdc Add resumeActivePlayback method to resume video playback when slideshow is active 2026-01-08 16:25:04 +01:00
CodeDevMLH
60593dc855 Update manifest.json for release v1.1.1.0 [skip ci] 2026-01-08 14:54:58 +00:00
CodeDevMLH
0edde43720 Update version to 1.1.1.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 1m3s
2026-01-08 15:53:56 +01:00
CodeDevMLH
0f6938a91d Add stopAllPlayback method to pause all video playback when navigating away from home screen 2026-01-08 15:52:46 +01:00
CodeDevMLH
fe661925e0 Update manifest.json for release v1.1.0.0 [skip ci] 2026-01-08 02:15:51 +00:00
CodeDevMLH
5fbe60c27a Fix version formatting in manifest.json for consistency 1.1.0.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 55s
2026-01-08 03:15:01 +01:00
CodeDevMLH
89bde9233d Update version to 1.1.0.0 and enhance changelog with custom media ID improvements
Some checks failed
Auto Release Plugin / build-and-release (push) Failing after 41s
2026-01-08 03:07:31 +01:00
CodeDevMLH
24ac119e01 Enable custom media IDs by default and improve GUID handling in slideshow manager for seperator and description 2026-01-08 03:07:15 +01:00
CodeDevMLH
1ee4aaefb5 Enable custom media IDs by default in plugin configuration 2026-01-08 02:59:42 +01:00
CodeDevMLH
d737bc9422 Update configPage.html to clarify custom media ID functionality and input instructions 2026-01-08 02:59:21 +01:00
CodeDevMLH
2a154aaf92 Update README.md to enhance clarity and add overview section with layout details 2026-01-07 02:20:32 +01:00
CodeDevMLH
561a4254b2 Update release automation to include changelog in release body and clean up .gitignore 2026-01-07 00:56:48 +01:00
CodeDevMLH
b8a0c7f589 Update manifest.json for release v1.0.0.3 [skip ci] 2026-01-06 23:26:30 +00:00
CodeDevMLH
10e02eeb3c fix ui
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 55s
2026-01-07 00:25:38 +01:00
CodeDevMLH
f39200544d Update manifest.json for release v1.0.0.3 [skip ci] 2026-01-06 23:17:33 +00:00
CodeDevMLH
5173f66449 test
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 53s
2026-01-07 00:16:45 +01:00
CodeDevMLH
965942f63b fix link again 2026-01-07 00:16:37 +01:00
CodeDevMLH
c251cf7e70 Update manifest.json for release v1.0.0.3 [skip ci] 2026-01-06 23:12:18 +00:00
CodeDevMLH
8699e0b3e2 test
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 55s
2026-01-07 00:10:57 +01:00
CodeDevMLH
5db2157232 fix links 2026-01-07 00:09:51 +01:00
CodeDevMLH
822f572006 Update manifest.json for release v1.0.0.3 [skip ci] 2026-01-06 22:56:33 +00:00
CodeDevMLH
e6637b34f7 fix name issue
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 54s
2026-01-06 23:55:42 +01:00
CodeDevMLH
1acaff6552 Update manifest.json for release v1.0.0.3 [skip ci] 2026-01-06 22:39:23 +00:00
CodeDevMLH
58188ca094 test
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 54s
2026-01-06 23:38:34 +01:00
CodeDevMLH
37b30aef1a Merge branch 'main' of ssh://git.mahom03-spacecloud.de:44322/CodeDevMLH/jellyfin-plugin-media-bar-enhanced 2026-01-06 23:30:57 +01:00
CodeDevMLH
f0370ac57f fix url and remote repo 2026-01-06 23:30:56 +01:00
CodeDevMLH
0663b7d9e4 Update manifest.json for release v1.0.0.3 [skip ci] 2026-01-06 22:23:52 +00:00
CodeDevMLH
e3213f72cc Enhance error handling in ScriptInjector for injection and removal processes
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 55s
2026-01-06 23:22:59 +01:00
CodeDevMLH
6c131aef58 Update manifest.json for release v1.0.0.3 [skip ci] 2026-01-06 21:33:22 +00:00
CodeDevMLH
0747f63d11 renamed slidshowpure to mediaBarEnhanced
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-01-06 22:32:31 +01:00
CodeDevMLH
12f6f23314 Update manifest.json for release v1.0.0.2 [skip ci] 2026-01-06 21:21:38 +00:00
CodeDevMLH
a27488366b fixes
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 54s
2026-01-06 22:20:45 +01:00
CodeDevMLH
dd4c71c3bf Update manifest.json for release v1.0.0.1 [skip ci] 2026-01-06 21:18:34 +00:00
CodeDevMLH
715cd1a663 test
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 58s
2026-01-06 22:17:38 +01:00
CodeDevMLH
9371ed9a33 Add seasonal manifest update step to release automation 2026-01-06 22:16:57 +01:00
CodeDevMLH
c21b2d3ede Update manifest.json for release v1.0.0.1 [skip ci] 2026-01-06 21:09:36 +00:00
CodeDevMLH
8ac0b9c003 add readme
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-06 22:08:46 +01:00
CodeDevMLH
0a0080c889 Update manifest.json for release v1.0.0.1 [skip ci] 2026-01-06 19:05:25 +00:00
CodeDevMLH
b2dd3e4d21 fix name (v1.0.0.1)
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-06 20:04:34 +01:00
CodeDevMLH
e4dac0d85c Update manifest.json for release v1.0.0.0 [skip ci] 2026-01-06 18:56:30 +00:00
CodeDevMLH
52bc8022fc Fix download URL formatting in release automation workflows and remove unused test.txt file
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-06 19:55:41 +01:00
CodeDevMLH
fb4416f4b3 Update manifest.json for release v1.0.0.0 [skip ci] 2026-01-06 18:40:10 +00:00
CodeDevMLH
a67c4ecbe7 Add new test.txt file
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 49s
2026-01-06 19:39:21 +01:00
CodeDevMLH
972c914dab Remove outdated setup instructions for automatic updates in Plugin B 2026-01-06 19:38:43 +01:00
CodeDevMLH
60825b7e2f Update manifest.json for release v1.0.0.0 [skip ci] 2026-01-06 18:36:23 +00:00
CodeDevMLH
5d23594e08 Remove outdated JPRM documentation and release automation workflow
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-06 19:35:33 +01:00
CodeDevMLH
2cccb139bf Enhance release automation to update central manifest with plugin GUID and target ABI 2026-01-06 19:34:16 +01:00
CodeDevMLH
f37b946c0c Update manifest.json for release v1.0.0.0 [skip ci] 2026-01-06 17:26:55 +00:00
CodeDevMLH
51c3eec58a Merge branch 'main' of ssh://git.mahom03-spacecloud.de:44322/CodeDevMLH/jellyfin-plugin-media-bar-enhanced
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 47s
2026-01-06 18:26:05 +01:00
CodeDevMLH
236def9fed Update manifest.json for release v1.0.0.0 [skip ci] 2026-01-06 17:26:04 +00:00
CodeDevMLH
f864b1105e Update imageUrl in manifest.json to correct path 2026-01-06 18:26:03 +01:00
CodeDevMLH
353db1eab1 new logo
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 49s
2026-01-06 18:25:13 +01:00
CodeDevMLH
7abaca731d Update manifest.json for release v1.0.0.0 [skip ci] 2026-01-06 01:43:51 +00:00
CodeDevMLH
56a8d82f2a init release v1.0.0.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 48s
2026-01-06 02:43:01 +01:00
CodeDevMLH
eec8f23968 add doc 2026-01-06 02:20:20 +01:00
17 changed files with 1167 additions and 376 deletions

View File

@@ -40,6 +40,11 @@ jobs:
echo "Detected Version: $VERSION" echo "Detected Version: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "TARGET_ABI=$TARGET_ABI" >> $GITHUB_ENV
# Also export GUID for later use
PLUGIN_GUID=$(jq -r '.[0].guid' manifest.json)
echo "PLUGIN_GUID=$PLUGIN_GUID" >> $GITHUB_ENV
# Escape newlines in changelog for GITHUB_ENV # Escape newlines in changelog for GITHUB_ENV
echo "CHANGELOG<<EOF" >> $GITHUB_ENV echo "CHANGELOG<<EOF" >> $GITHUB_ENV
@@ -71,7 +76,7 @@ jobs:
REPO_OWNER="${{ github.repository_owner }}" REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}" REPO_NAME="${{ github.event.repository.name }}"
VERSION="${{ env.VERSION }}" VERSION="${{ env.VERSION }}"
DOWNLOAD_URL="https://git.mahom03-spacecloud.de/${{ github.repository }}/releases/download/v$VERSION/Jellyfin.Plugin.MediaBarEnhanced.zip" DOWNLOAD_URL="https://git.mahom03-spacecloud.de/$REPO_OWNER/$REPO_NAME/releases/download/v$VERSION/Jellyfin.Plugin.MediaBarEnhanced.zip"
echo "Updating manifest.json with:" echo "Updating manifest.json with:"
echo "Hash: ${{ env.ZIP_HASH }}" echo "Hash: ${{ env.ZIP_HASH }}"
@@ -101,3 +106,159 @@ jobs:
tag_name: "v${{ env.VERSION }}" tag_name: "v${{ env.VERSION }}"
draft: false draft: false
prerelease: false prerelease: false
# Update Message in Remote Repository
- name: Checkout Central Manifest Repo
uses: actions/checkout@v6
with:
repository: ${{ github.repository_owner }}/jellyfin-plugin-manifest
path: central-manifest
token: ${{ secrets.JELLYFIN_PLUGIN_MANIFEST_UPDATER_PAT }}
- name: Update Central Manifest
shell: bash
run: |
cd central-manifest
REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}"
# 1. Get info from previous steps
VERSION="${{ env.VERSION }}"
HASH="${{ env.ZIP_HASH }}"
TIME="${{ env.BUILD_TIME }}"
DOWNLOAD_URL="https://git.mahom03-spacecloud.de/$REPO_OWNER/$REPO_NAME/releases/download/v$VERSION/Jellyfin.Plugin.MediaBarEnhanced.zip"
# 2. Get info from env
PLUGIN_GUID="${{ env.PLUGIN_GUID }}"
CHANGELOG="${{ env.CHANGELOG }}"
TARGET_ABI="${{ env.TARGET_ABI }}"
echo "Updating Central Manifest for Plugin GUID: $PLUGIN_GUID"
# 3. Update/Prepend entry in central manifest.json
# Logic:
# - If array is empty or new version != old version: PREPEND new entry
# - If new version == old version: OVERWRITE (update) existing entry (re-release)
jq --arg guid "$PLUGIN_GUID" \
--arg hash "$HASH" \
--arg time "$TIME" \
--arg url "$DOWNLOAD_URL" \
--arg ver "$VERSION" \
--arg changelog "$CHANGELOG" \
--arg abi "$TARGET_ABI" \
'map(if .guid == $guid then
if .versions[0].version != $ver then
# New Version -> Prepend
.versions = [{
"version": $ver,
"changelog": $changelog,
"targetAbi": $abi,
"sourceUrl": $url,
"checksum": $hash,
"timestamp": $time
}] + .versions
else
# Same Version -> Update existing (overwrite top)
.versions[0].changelog = $changelog |
.versions[0].targetAbi = $abi |
.versions[0].sourceUrl = $url |
.versions[0].checksum = $hash |
.versions[0].timestamp = $time
end
else . end)' \
manifest.json > manifest.json.tmp && mv manifest.json.tmp manifest.json
- name: Commit and Push Central Manifest
run: |
cd central-manifest
git config user.name "CodeDevMLH"
git config user.email "145071728+CodeDevMLH@users.noreply.github.com"
# Check if there are changes
if [[ -n $(git status -s) ]]; then
git add manifest.json
git commit -m "Auto-Update MediaBar Enhanced to v${{ env.VERSION }}"
git push
else
echo "No changes to central manifest."
fi
# Update Message in Seasonals Repository
- name: Checkout Seasonal Manifest Repo
uses: actions/checkout@v6
with:
repository: ${{ github.repository_owner }}/Jellyfin-Seasonals-Plugin
path: seasonal-manifest
token: ${{ secrets.JELLYFIN_PLUGIN_MANIFEST_UPDATER_PAT }}
- name: Update Seasonal Manifest
shell: bash
run: |
cd seasonal-manifest
REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}"
# 1. Get info from previous steps
VERSION="${{ env.VERSION }}"
HASH="${{ env.ZIP_HASH }}"
TIME="${{ env.BUILD_TIME }}"
DOWNLOAD_URL="https://git.mahom03-spacecloud.de/$REPO_OWNER/$REPO_NAME/releases/download/v$VERSION/Jellyfin.Plugin.MediaBarEnhanced.zip"
# 2. Get info from env
PLUGIN_GUID="${{ env.PLUGIN_GUID }}"
CHANGELOG="${{ env.CHANGELOG }}"
TARGET_ABI="${{ env.TARGET_ABI }}"
echo "Updating Seasonal Manifest for Plugin GUID: $PLUGIN_GUID"
# 3. Update/Prepend entry in seasonal manifest.json
# Logic:
# - If array is empty or new version != old version: PREPEND new entry
# - If new version == old version: OVERWRITE (update) existing entry (re-release)
jq --arg guid "$PLUGIN_GUID" \
--arg hash "$HASH" \
--arg time "$TIME" \
--arg url "$DOWNLOAD_URL" \
--arg ver "$VERSION" \
--arg changelog "$CHANGELOG" \
--arg abi "$TARGET_ABI" \
'map(if .guid == $guid then
if .versions[0].version != $ver then
# New Version -> Prepend
.versions = [{
"version": $ver,
"changelog": $changelog,
"targetAbi": $abi,
"sourceUrl": $url,
"checksum": $hash,
"timestamp": $time
}] + .versions
else
# Same Version -> Update existing (overwrite top)
.versions[0].changelog = $changelog |
.versions[0].targetAbi = $abi |
.versions[0].sourceUrl = $url |
.versions[0].checksum = $hash |
.versions[0].timestamp = $time
end
else . end)' \
manifest.json > manifest.json.tmp && mv manifest.json.tmp manifest.json
- name: Commit and Push Seasonal Manifest
run: |
cd seasonal-manifest
git config user.name "CodeDevMLH"
git config user.email "145071728+CodeDevMLH@users.noreply.github.com"
# Check if there are changes
if [[ -n $(git status -s) ]]; then
git add manifest.json
git commit -m "Auto-Update MediaBar Enhanced to v${{ env.VERSION }}"
git push
else
echo "No changes to seasonal manifest."
fi

View File

@@ -24,6 +24,8 @@ jobs:
uses: actions/checkout@v6 uses: actions/checkout@v6
with: with:
token: ${{ secrets.GITHUB_TOKEN }} token: ${{ secrets.GITHUB_TOKEN }}
fetch-depth: 0
- name: Setup .NET - name: Setup .NET
uses: actions/setup-dotnet@v5 uses: actions/setup-dotnet@v5
@@ -39,6 +41,11 @@ jobs:
echo "Detected Version: $VERSION" echo "Detected Version: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV echo "VERSION=$VERSION" >> $GITHUB_ENV
echo "TARGET_ABI=$TARGET_ABI" >> $GITHUB_ENV
# Also export GUID for later use
PLUGIN_GUID=$(jq -r '.[0].guid' manifest.json)
echo "PLUGIN_GUID=$PLUGIN_GUID" >> $GITHUB_ENV
# Escape newlines in changelog for GITHUB_ENV # Escape newlines in changelog for GITHUB_ENV
echo "CHANGELOG<<EOF" >> $GITHUB_ENV echo "CHANGELOG<<EOF" >> $GITHUB_ENV
@@ -89,6 +96,40 @@ jobs:
commit_message: "Update manifest.json for release v${{ env.VERSION }} [skip ci]" commit_message: "Update manifest.json for release v${{ env.VERSION }} [skip ci]"
file_pattern: manifest.json file_pattern: manifest.json
- name: Generate Commit Log
if: success()
shell: bash
run: |
echo "Generating commit log since last tag..."
# Get the previous tag
PREV_TAG=$(git describe --tags --abbrev=0 2>/dev/null || echo "")
if [ -z "$PREV_TAG" ]; then
echo "No previous tag found. Getting all commits."
start_range=""
else
echo "Previous tag: $PREV_TAG"
start_range="$PREV_TAG.."
fi
echo "### What's Changed" > commit_log.md
echo "" >> commit_log.md
git log --pretty=format:"- %s (%h) by @%an" $start_range >> commit_log.md
# Combine Changelog from manifest (if exists) and commit log
if [ -n "${{ env.CHANGELOG }}" ]; then
echo "${{ env.CHANGELOG }}" > release_body.txt
echo "" >> release_body.txt
echo "" >> release_body.txt
cat commit_log.md >> release_body.txt
else
cat commit_log.md > release_body.txt
fi
# Debug output
cat release_body.txt
- name: Create Release - name: Create Release
uses: softprops/action-gh-release@v2 uses: softprops/action-gh-release@v2
with: with:
@@ -98,4 +139,162 @@ jobs:
files: ${{ env.ZIP_PATH }} files: ${{ env.ZIP_PATH }}
draft: false draft: false
prerelease: false prerelease: false
generate_release_notes: true generate_release_notes: false
body_path: release_body.txt
# Update Message in Remote Repository
- name: Checkout Central Manifest Repo
uses: actions/checkout@v6
with:
repository: ${{ github.repository_owner }}/jellyfin-plugin-manifest
path: central-manifest
token: ${{ secrets.JELLYFIN_PLUGIN_MANIFEST_UPDATER_PAT }}
- name: Update Central Manifest
shell: bash
run: |
cd central-manifest
REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}"
# 1. Get info from previous steps
VERSION="${{ env.VERSION }}"
HASH="${{ env.ZIP_HASH }}"
TIME="${{ env.BUILD_TIME }}"
DOWNLOAD_URL="https://github.com/$REPO_OWNER/$REPO_NAME/releases/download/v$VERSION/Jellyfin.Plugin.MediaBarEnhanced.zip"
# 2. Get info from env
PLUGIN_GUID="${{ env.PLUGIN_GUID }}"
CHANGELOG="${{ env.CHANGELOG }}"
TARGET_ABI="${{ env.TARGET_ABI }}"
echo "Updating Central Manifest for Plugin GUID: $PLUGIN_GUID"
# 3. Update/Prepend entry in central manifest.json
# Logic:
# - If array is empty or new version != old version: PREPEND new entry
# - If new version == old version: OVERWRITE (update) existing entry (re-release)
jq --arg guid "$PLUGIN_GUID" \
--arg hash "$HASH" \
--arg time "$TIME" \
--arg url "$DOWNLOAD_URL" \
--arg ver "$VERSION" \
--arg changelog "$CHANGELOG" \
--arg abi "$TARGET_ABI" \
'map(if .guid == $guid then
if .versions[0].version != $ver then
# New Version -> Prepend
.versions = [{
"version": $ver,
"changelog": $changelog,
"targetAbi": $abi,
"sourceUrl": $url,
"checksum": $hash,
"timestamp": $time
}] + .versions
else
# Same Version -> Update existing (overwrite top)
.versions[0].changelog = $changelog |
.versions[0].targetAbi = $abi |
.versions[0].sourceUrl = $url |
.versions[0].checksum = $hash |
.versions[0].timestamp = $time
end
else . end)' \
manifest.json > manifest.json.tmp && mv manifest.json.tmp manifest.json
- name: Commit and Push Central Manifest
run: |
cd central-manifest
git config user.name "CodeDevMLH"
git config user.email "145071728+CodeDevMLH@users.noreply.github.com"
# Check if there are changes
if [[ -n $(git status -s) ]]; then
git add manifest.json
git commit -m "Auto-Update MediaBar Enhanced to v${{ env.VERSION }}"
git push
else
echo "No changes to central manifest."
fi
# Update Message in Seasonals Repository
- name: Checkout Seasonal Manifest Repo
uses: actions/checkout@v6
with:
repository: ${{ github.repository_owner }}/Jellyfin-Seasonals
path: seasonal-manifest
token: ${{ secrets.JELLYFIN_PLUGIN_MANIFEST_UPDATER_PAT }}
- name: Update Seasonal Manifest
shell: bash
run: |
cd seasonal-manifest
REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}"
# 1. Get info from previous steps
VERSION="${{ env.VERSION }}"
HASH="${{ env.ZIP_HASH }}"
TIME="${{ env.BUILD_TIME }}"
DOWNLOAD_URL="https://github.com/$REPO_OWNER/$REPO_NAME/releases/download/v$VERSION/Jellyfin.Plugin.MediaBarEnhanced.zip"
# 2. Get info from env
PLUGIN_GUID="${{ env.PLUGIN_GUID }}"
CHANGELOG="${{ env.CHANGELOG }}"
TARGET_ABI="${{ env.TARGET_ABI }}"
echo "Updating Seasonal Manifest for Plugin GUID: $PLUGIN_GUID"
# 3. Update/Prepend entry in seasonal manifest.json
# Logic:
# - If array is empty or new version != old version: PREPEND new entry
# - If new version == old version: OVERWRITE (update) existing entry (re-release)
jq --arg guid "$PLUGIN_GUID" \
--arg hash "$HASH" \
--arg time "$TIME" \
--arg url "$DOWNLOAD_URL" \
--arg ver "$VERSION" \
--arg changelog "$CHANGELOG" \
--arg abi "$TARGET_ABI" \
'map(if .guid == $guid then
if .versions[0].version != $ver then
# New Version -> Prepend
.versions = [{
"version": $ver,
"changelog": $changelog,
"targetAbi": $abi,
"sourceUrl": $url,
"checksum": $hash,
"timestamp": $time
}] + .versions
else
# Same Version -> Update existing (overwrite top)
.versions[0].changelog = $changelog |
.versions[0].targetAbi = $abi |
.versions[0].sourceUrl = $url |
.versions[0].checksum = $hash |
.versions[0].timestamp = $time
end
else . end)' \
manifest.json > manifest.json.tmp && mv manifest.json.tmp manifest.json
- name: Commit and Push Seasonal Manifest
run: |
cd seasonal-manifest
git config user.name "CodeDevMLH"
git config user.email "145071728+CodeDevMLH@users.noreply.github.com"
# Check if there are changes
if [[ -n $(git status -s) ]]; then
git add manifest.json
git commit -m "Auto-Update MediaBar Enhanced to v${{ env.VERSION }}"
git push
else
echo "No changes to seasonal manifest."
fi

2
.gitignore vendored
View File

@@ -4,7 +4,5 @@ obj/
.idea/ .idea/
artifacts artifacts
example-plugins/
*.md *.md
!README.md !README.md

View File

@@ -30,7 +30,8 @@ namespace Jellyfin.Plugin.MediaBarEnhanced.Configuration
public bool EnableKeyboardControls { get; set; } = true; public bool EnableKeyboardControls { get; set; } = true;
public bool AlwaysShowArrows { get; set; } = false; public bool AlwaysShowArrows { get; set; } = false;
public string CustomMediaIds { get; set; } = ""; public string CustomMediaIds { get; set; } = "";
public bool EnableCustomMediaIds { get; set; } = false; public bool EnableCustomMediaIds { get; set; } = true;
public string PreferredVideoQuality { get; set; } = "Auto";
public bool EnableSeasonalContent { get; set; } = false; public bool EnableSeasonalContent { get; set; } = false;
public bool IsEnabled { get; set; } = true; public bool IsEnabled { get; set; } = true;
} }

View File

@@ -14,9 +14,9 @@
<div class="sectionTitleContainer"> <div class="sectionTitleContainer">
<h2 class="sectionTitle">Media Bar Enhanced</h2> <h2 class="sectionTitle">Media Bar Enhanced</h2>
<a is="emby-linkbutton" class="raised raised-mini emby-button" style="margin-left: 2em;" <a is="emby-linkbutton" class="raised raised-mini emby-button" style="margin-left: 2em;"
target="_blank" href="https://github.com/CodeDevMLH/Jellyfin-Seasonals"> target="_blank" href="https://github.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced">
<i class="md-icon button-icon button-icon-left secondaryText"></i> <i class="md-icon button-icon button-icon-left secondaryText"></i>
<span>Help</span> <span>${Help}</span>
</a> </a>
</div> </div>
<hr style="max-width: 800px; margin: 1em 0;"> <hr style="max-width: 800px; margin: 1em 0;">
@@ -93,8 +93,9 @@
name="EnableCustomMediaIds" /> name="EnableCustomMediaIds" />
<span>Enable Custom Media IDs</span> <span>Enable Custom Media IDs</span>
</label> </label>
<div class="fieldDescription">If enabled, the slideshow will ONLY show the items listed <div class="fieldDescription">If enabled, the slideshow will try to show the items listed
below.</div> below. If the list is empty, default behavior (random items) is used. Disable this
to temporarily ignore your custom list without deleting it.</div>
</div> </div>
<div class="checkboxContainer checkboxContainer-withDescription"> <div class="checkboxContainer checkboxContainer-withDescription">
<label> <label>
@@ -108,28 +109,35 @@
<div class="inputContainer"> <div class="inputContainer">
<label class="inputLabel inputLabelUnfocused" for="CustomMediaIds">Media/Collection/Playlist <label class="inputLabel inputLabelUnfocused" for="CustomMediaIds">Media/Collection/Playlist
IDs IDs
(Comma or Newline separated)</label> (Newline or Comma separated)</label>
<textarea is="emby-textarea" id="CustomMediaIds" name="CustomMediaIds" <textarea is="emby-textarea" id="CustomMediaIds" name="CustomMediaIds"
style="width: 100%; height: 150px; font-family: monospace;"></textarea> style="width: 100%; height: 150px; font-family: monospace;"></textarea>
<div class="fieldDescription" id="customMediaIdsDesc">Enter the IDs of the items you want to <div class="fieldDescription" id="customMediaIdsDesc">Enter the IDs of the items you want to show in the slideshow.
show in the slideshow. You can separate them by new line or comma.
You can separate them by comma or new line.</div> <br>
<b>Manual Trailer Override:</b> You can specify a YouTube URL for an item by adding it in
brackets: <code>ID [https://youtu.be/...]</code>
<br>
You can also add a description after the ID using any separator like space, pipe
(|) or dash (-) (e.g. <code>ID | Description</code>).
<b>Note:</b> If using a <b>Collection Name</b> (instead of an ID) combined with a description, you <b>MUST</b> use
the pipe (|) separator.</div>
<b>Note:</b> The separator MUST NOT be a hex character (0-9, a-f).</div>
<div class="fieldDescription" id="seasonalMediaIdsDesc" style="display: none;"> <div class="fieldDescription" id="seasonalMediaIdsDesc" style="display: none;">
<b>Seasonal Mode Enabled:</b> Define lines with date ranges (Format: DD.MM-DD.MM | <b>Seasonal Mode Enabled:</b> Define lines with date ranges (Format: DD.MM-DD.MM |
<i>name</i> | <i>IDs</i>).<br> <i>name</i> | <i>IDs</i>).<br>
Example:<br> Example:<br>
<code>20.10-31.10 | Halloween | ID1, ID2</code><br> <code>20.10-31.10 | Halloween | ID1, ID2 [https://youtu.be/...]</code><br>
<code>01.12-26.12 | Christmas | ID3, ID4</code><br> <code>01.12-26.12 | Christmas | ID3, ID4</code><br>
<i>Only lines matching the current date will be used. If no line matches, it will try to <i>Only lines matching the current date will be used. If no line matches, it will try to
fetch the list.txt or use random items.</i> fetch the list.txt or use random items.</i>
</div> </div>
<p>You can find the IDs of your items in the URL of the item page in the web interface.<br> <p>You can find the IDs of your items in the URL of the item page in the web interface.<br>
Example: Example:
<code>https://your-jellyfin-url/web/#/details?id=<b style="color:red;">your-item-id</b>&serverId=your-server-id</code><br> <code>https://your-jellyfin-url/web/#/details?id=<b style="color:red;">your-item-id</b>&serverId=your-server-id</code><br><br>
You can also insert a name of a collection or playlist to fetch the IDs of all items in You can also insert a name of a collection or playlist to fetch the IDs of all items in
it (will take the first hit. Note: there is currently no feedback if the name resolution it (will take the first hit.<br>Note: there is currently no feedback if the name
succeeded, you resolution succeeded, you will have to look if the bar displays the correct items.).
will have to look if the bar displays the correct items.).
</p> </p>
</div> </div>
</div> </div>
@@ -153,6 +161,18 @@
</label> </label>
<div class="fieldDescription">Skip intro/outro segments in YouTube trailers.</div> <div class="fieldDescription">Skip intro/outro segments in YouTube trailers.</div>
</div> </div>
<div class="selectContainer">
<label class="selectLabel" for="PreferredVideoQuality">Preferred YouTube Quality</label>
<select is="emby-select" id="PreferredVideoQuality" name="PreferredVideoQuality"
class="emby-select-withcolor emby-select">
<option value="Auto">Auto (Smart)</option>
<option value="Maximum">Maximum (4K+)</option>
<option value="1080p">1080p</option>
<option value="720p">720p</option>
</select>
<div class="fieldDescription">"Auto" selects Maximum if screen width > 1920px, otherwise
1080p.</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription"> <div class="checkboxContainer checkboxContainer-withDescription">
<label> <label>
<input is="emby-checkbox" type="checkbox" id="StartMuted" name="StartMuted" /> <input is="emby-checkbox" type="checkbox" id="StartMuted" name="StartMuted" />

View File

@@ -12,8 +12,8 @@
<!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> --> <!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> -->
<Title>Jellyfin Media Bar Enhanced Plugin</Title> <Title>Jellyfin Media Bar Enhanced Plugin</Title>
<Authors>CodeDevMLH</Authors> <Authors>CodeDevMLH</Authors>
<Version>1.5.0.0</Version> <Version>1.3.0.0</Version>
<RepositoryUrl>https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin</RepositoryUrl> <RepositoryUrl>https://github.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced</RepositoryUrl>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

View File

@@ -59,7 +59,7 @@ namespace Jellyfin.Plugin.MediaBarEnhanced
} }
/// <inheritdoc /> /// <inheritdoc />
public override string Name => "Media Bar"; public override string Name => "Media Bar Enhanced";
/// <inheritdoc /> /// <inheritdoc />
public override Guid Id => Guid.Parse("d7e11d57-819b-4bdd-a88d-53c5f5560225"); public override Guid Id => Guid.Parse("d7e11d57-819b-4bdd-a88d-53c5f5560225");

View File

@@ -18,10 +18,8 @@ namespace Jellyfin.Plugin.MediaBarEnhanced
{ {
private readonly IApplicationPaths _appPaths; private readonly IApplicationPaths _appPaths;
private readonly ILogger<ScriptInjector> _logger; private readonly ILogger<ScriptInjector> _logger;
public const string ScriptTag = "<script src=\"/MediaBarEnhanced/Resources/slideshowpure.js\" defer></script>"; public const string ScriptTag = "<script src=\"/MediaBarEnhanced/Resources/mediaBarEnhanced.js\" defer></script>";
public const string CssTag = "<link rel=\"stylesheet\" href=\"/MediaBarEnhanced/Resources/slideshowpure.css\" />"; public const string CssTag = "<link rel=\"stylesheet\" href=\"/MediaBarEnhanced/Resources/mediaBarEnhanced.css\" />";
// private const string ScriptTag = "<script src=\"/MediaBarEnhanced/Resources/media-bar.js\" defer></script>";
// private const string CssTag = "<link rel=\"stylesheet\" href=\"/MediaBarEnhanced/Resources/media-bar.css\">";
public const string ScriptMarker = "</body>"; public const string ScriptMarker = "</body>";
public const string CssMarker = "</head>"; public const string CssMarker = "</head>";
@@ -39,7 +37,6 @@ namespace Jellyfin.Plugin.MediaBarEnhanced
/// <summary> /// <summary>
/// Injects the script tag into index.html if it's not already present. /// Injects the script tag into index.html if it's not already present.
/// </summary> /// </summary>
/// <returns>True if injection was successful or already present, false otherwise.</returns>
public void Inject() public void Inject()
{ {
try try
@@ -103,6 +100,11 @@ namespace Jellyfin.Plugin.MediaBarEnhanced
_logger.LogInformation("MediaBarEnhanced script and CSS already present in index.html. Or could not be injected."); _logger.LogInformation("MediaBarEnhanced script and CSS already present in index.html. Or could not be injected.");
} }
} }
catch (UnauthorizedAccessException)
{
_logger.LogWarning("Unauthorized access when attempting to inject script into index.html. Automatic injection failed. Attempting fallback now...");
RegisterFileTransformation();
}
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Error injecting MediaBarEnhanced resources. Attempting fallback."); _logger.LogError(ex, "Error injecting MediaBarEnhanced resources. Attempting fallback.");
@@ -150,8 +152,15 @@ namespace Jellyfin.Plugin.MediaBarEnhanced
{ {
File.WriteAllText(indexPath, content); File.WriteAllText(indexPath, content);
_logger.LogInformation("MediaBarEnhanced script removed from index.html."); _logger.LogInformation("MediaBarEnhanced script removed from index.html.");
} else
{
_logger.LogInformation("MediaBarEnhanced script not found in index.html. No removal necessary.");
} }
} }
catch (UnauthorizedAccessException uaEx)
{
_logger.LogError(uaEx, "Unauthorized access when trying to remove MediaBarEnhanced script. Check file permissions.");
}
catch (Exception ex) catch (Exception ex)
{ {
_logger.LogError(ex, "Error removing MediaBarEnhanced script."); _logger.LogError(ex, "Error removing MediaBarEnhanced script.");
@@ -172,7 +181,6 @@ namespace Jellyfin.Plugin.MediaBarEnhanced
{ {
JObject payload = new JObject(); JObject payload = new JObject();
// Random GUID for ID
payload.Add("id", "0dfac9d7-d898-4944-900b-1c1837707279"); payload.Add("id", "0dfac9d7-d898-4944-900b-1c1837707279");
payload.Add("fileNamePattern", "index.html"); payload.Add("fileNamePattern", "index.html");
payload.Add("callbackAssembly", GetType().Assembly.FullName); payload.Add("callbackAssembly", GetType().Assembly.FullName);
@@ -223,7 +231,6 @@ namespace Jellyfin.Plugin.MediaBarEnhanced
if (pluginInterfaceType != null) if (pluginInterfaceType != null)
{ {
// The ID must match the one used in RegisterFileTransformation
Guid id = Guid.Parse("0dfac9d7-d898-4944-900b-1c1837707279"); Guid id = Guid.Parse("0dfac9d7-d898-4944-900b-1c1837707279");
pluginInterfaceType.GetMethod("RemoveTransformation")?.Invoke(null, new object?[] { id }); pluginInterfaceType.GetMethod("RemoveTransformation")?.Invoke(null, new object?[] { id });
_logger.LogInformation("File transformation unregistered successfully."); _logger.LogInformation("File transformation unregistered successfully.");
@@ -232,7 +239,6 @@ namespace Jellyfin.Plugin.MediaBarEnhanced
} }
catch (Exception ex) catch (Exception ex)
{ {
// Log but don't throw, as we want to continue with normal removal
_logger.LogWarning(ex, "Error attempting to unregister file transformation. It might not have been registered."); _logger.LogWarning(ex, "Error attempting to unregister file transformation. It might not have been registered.");
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Jellyfin Slideshow by M0RPH3US v3.0.6 * Jellyfin Slideshow by M0RPH3US v3.0.9
* Modified by CodeDevMLH v1.1.0.0 * Modified by CodeDevMLH v1.1.0.0
* *
* New features: * New features:
@@ -41,11 +41,11 @@
@keyframes kenBurnsZoomIn { @keyframes kenBurnsZoomIn {
from { from {
transform: scale(1); transform: scale3d(1, 1, 0);
} }
to { to {
transform: scale(1.1); transform: scale3d(1.1, 1.1, 0.1);
} }
} }
@@ -128,6 +128,10 @@
transition: width 0.2s ease-in-out; transition: width 0.2s ease-in-out;
} }
.layout-mobile .splashLogo {
height: 12%;
}
.backdrop.low-quality { .backdrop.low-quality {
filter: blur(0.5px); filter: blur(0.5px);
transform: scale(1.01); transform: scale(1.01);
@@ -166,6 +170,12 @@
height: 90%; height: 90%;
overflow: hidden; overflow: hidden;
margin: 0 auto; margin: 0 auto;
pointer-events: auto;
}
#slides-container[style*="display: none"],
#slides-container[style*="visibility: hidden"] {
pointer-events: none !important;
} }
.arrow { .arrow {
@@ -780,6 +790,41 @@
left: 50%; left: 50%;
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
} }
@media (max-width: 400px) {
.button-container {
gap: 10px;
}
.play-button,
.trailer-button {
padding: 8px 14px;
}
.misc-info {
flex-wrap: wrap;
justify-content: center;
gap: 0px 10px;
}
.runTime {
width: 100%;
justify-content: center;
margin-top: 0.5vh;
}
.misc-info .separator-icon:last-of-type {
display: none;
}
.genre {
top: calc(50% + 16vh);
}
.button-container {
top: calc(50% + 27vh);
}
}
} }
/*Landscape Mode Phones*/ /*Landscape Mode Phones*/

View File

@@ -1,5 +1,5 @@
/* /*
* Jellyfin Slideshow by M0RPH3US v3.0.6 * Jellyfin Slideshow by M0RPH3US v3.0.9
* Modified by CodeDevMLH v1.1.0.0 * Modified by CodeDevMLH v1.1.0.0
* *
* New features: * New features:
@@ -42,9 +42,10 @@ const CONFIG = {
fullWidthVideo: true, fullWidthVideo: true,
enableMobileVideo: false, enableMobileVideo: false,
showTrailerButton: true, showTrailerButton: true,
preferredVideoQuality: "Auto",
enableKeyboardControls: true, enableKeyboardControls: true,
alwaysShowArrows: false, alwaysShowArrows: false,
enableCustomMediaIds: false, enableCustomMediaIds: true,
enableSeasonalContent: false, enableSeasonalContent: false,
customMediaIds: "", customMediaIds: "",
enableLoadingScreen: true, enableLoadingScreen: true,
@@ -77,6 +78,7 @@ const STATE = {
videoPlayers: {}, videoPlayers: {},
sponsorBlockInterval: null, sponsorBlockInterval: null,
isMuted: CONFIG.startMuted, isMuted: CONFIG.startMuted,
customTrailerUrls: {},
}, },
}; };
@@ -252,31 +254,53 @@ const initLoadingScreen = () => {
const checkInterval = setInterval(() => { const checkInterval = setInterval(() => {
const loginFormLoaded = document.querySelector(".manualLoginForm"); const loginFormLoaded = document.querySelector(".manualLoginForm");
const homePageLoaded = const activeTab = document.querySelector(".pageTabContent.is-active");
document.querySelector(".homeSectionsContainer") &&
document.querySelector("#slides-container");
if (loginFormLoaded || homePageLoaded) { if (loginFormLoaded) {
finishLoading();
return;
}
if (activeTab) {
const tabIndex = activeTab.getAttribute("data-index");
if (tabIndex === "0") {
const homeSections = document.querySelector(".homeSectionsContainer");
const slidesContainer = document.querySelector("#slides-container");
if (homeSections && slidesContainer) {
finishLoading();
}
} else {
if (
activeTab.children.length > 0 ||
activeTab.innerText.trim().length > 0
) {
finishLoading();
}
}
}
}, CONFIG.loadingCheckInterval);
const finishLoading = () => {
clearInterval(progressInterval); clearInterval(progressInterval);
clearInterval(checkInterval); clearInterval(checkInterval);
progressBar.style.transition = "width 300ms ease-in-out"; progressBar.style.transition = "width 300ms ease-in-out";
progressBar.style.width = "100%"; progressBar.style.width = "100%";
unfilledBar.style.width = "0%"; unfilledBar.style.width = "0%";
progressBar.addEventListener('transitionend', () => { progressBar.addEventListener("transitionend", () => {
requestAnimationFrame(() => { requestAnimationFrame(() => {
const loader = document.querySelector(".bar-loading"); const loader = document.querySelector(".bar-loading");
if (loader) { if (loader) {
loader.style.opacity = '0'; loader.style.opacity = "0";
setTimeout(() => { setTimeout(() => {
loader.remove(); loader.remove();
}, 300); }, 300);
} }
}); });
}) });
} };
}, CONFIG.loadingCheckInterval);
}; };
/** /**
@@ -321,6 +345,7 @@ const resetSlideshowState = () => {
STATE.slideshow.itemIds = []; STATE.slideshow.itemIds = [];
STATE.slideshow.loadedItems = {}; STATE.slideshow.loadedItems = {};
STATE.slideshow.createdSlides = {}; STATE.slideshow.createdSlides = {};
STATE.slideshow.customTrailerUrls = {};
STATE.slideshow.totalItems = 0; STATE.slideshow.totalItems = 0;
STATE.slideshow.isLoading = false; STATE.slideshow.isLoading = false;
}; };
@@ -820,29 +845,64 @@ const LocalizationUtils = {
throw new Error(`Failed to fetch translations: ${response.statusText}`); throw new Error(`Failed to fetch translations: ${response.statusText}`);
} }
/**
* @example
* Standard version
* ```js
* "use strict";
* (self.webpackChunk = self.webpackChunk || []).push([[62634], {
* 30985: function(e) {
* e.exports = JSON.parse('{"Absolute":"..."}')
* }
* }]);
* ```
*
* Minified version
* ```js
* "use strict";(self.webpackChunk=self.webpackChunk||[]).push([[24072],{60715:function(e){e.exports=JSON.parse('{"Absolute":"..."}')}}]);
* ```
*/
const chunkText = await response.text(); const chunkText = await response.text();
let jsonMatch = chunkText.match(/JSON\.parse\(['"](.*?)['"]\)/); const replaceEscaped = (text) =>
if (jsonMatch) { text.replace(/\\"/g, '"').replace(/\\n/g, '\n').replace(/\\\\/g, '\\').replace(/\\'/g, "'");
let jsonString = jsonMatch[1]
.replace(/\\"/g, '"') // 1. Try to remove start and end wrappers first
.replace(/\\n/g, '\n')
.replace(/\\\\/g, '\\')
.replace(/\\'/g, "'");
try { try {
// Matches from start of file to the beginning of JSON.parse('
const START = /^(.*)JSON\.parse\(['"]/gms;
// Matches from the end of the JSON string to the end of the file
const END = /['"]?\)?\s*}?(\r\n|\r|\n)?}?]?\)?;(\r\n|\r|\n)?$/gms;
const jsonString = replaceEscaped(chunkText.replace(START, '').replace(END, ''));
this.translations[locale] = JSON.parse(jsonString); this.translations[locale] = JSON.parse(jsonString);
return; return;
} catch (e) { } catch (e) {
console.error('Failed to parse JSON from standard extraction.');
// Try alternative extraction below
}
// 2. Try to extract only the JSON string directly
let jsonMatch = chunkText.match(/JSON\.parse\(['"](.*?)['"]\)/);
if (jsonMatch) {
try {
const jsonString = replaceEscaped(jsonMatch[1]);
this.translations[locale] = JSON.parse(jsonString);
return;
} catch (e) {
console.error('Failed to parse JSON from direct extraction.');
// Try direct extraction // Try direct extraction
} }
} }
// 3. Fallback: extract everything between the first { and the last }
const jsonStart = chunkText.indexOf('{'); const jsonStart = chunkText.indexOf('{');
const jsonEnd = chunkText.lastIndexOf('}') + 1; const jsonEnd = chunkText.lastIndexOf('}') + 1;
if (jsonStart !== -1 && jsonEnd > jsonStart) { if (jsonStart !== -1 && jsonEnd > jsonStart) {
const jsonString = chunkText.substring(jsonStart, jsonEnd); const jsonString = chunkText.substring(jsonStart, jsonEnd);
try { try {
this.translations[locale] = JSON.parse(jsonString); this.translations[locale] = JSON.parse(jsonString);
return;
} catch (e) { } catch (e) {
console.error("Failed to parse JSON from chunk:", e); console.error("Failed to parse JSON from chunk:", e);
} }
@@ -1252,18 +1312,23 @@ const VisibilityObserver = {
const isVisible = const isVisible =
(window.location.hash === "#/home.html" || (window.location.hash === "#/home.html" ||
window.location.hash === "#/home") && window.location.hash === "#/home") &&
activeTab &&
activeTab.getAttribute("data-index") === "0"; activeTab.getAttribute("data-index") === "0";
container.style.display = isVisible ? "block" : "none"; container.style.display = isVisible ? "block" : "none";
container.style.visibility = isVisible ? "visible" : "hidden";
container.style.pointerEvents = isVisible ? "auto" : "none";
if (isVisible) { if (isVisible) {
if (STATE.slideshow.slideInterval && !STATE.slideshow.isPaused) { if (STATE.slideshow.slideInterval && !STATE.slideshow.isPaused) {
STATE.slideshow.slideInterval.start(); STATE.slideshow.slideInterval.start();
SlideshowManager.resumeActivePlayback();
} }
} else { } else {
if (STATE.slideshow.slideInterval) { if (STATE.slideshow.slideInterval) {
STATE.slideshow.slideInterval.stop(); STATE.slideshow.slideInterval.stop();
} }
SlideshowManager.stopAllPlayback();
} }
}, },
@@ -1271,11 +1336,11 @@ const VisibilityObserver = {
* Initializes visibility observer * Initializes visibility observer
*/ */
init() { init() {
const observer = new MutationObserver(this.updateVisibility); const observer = new MutationObserver(() => this.updateVisibility());
observer.observe(document.body, { childList: true, subtree: true }); observer.observe(document.body, { childList: true, subtree: true });
document.body.addEventListener("click", this.updateVisibility); document.body.addEventListener("click", () => this.updateVisibility());
window.addEventListener("hashchange", this.updateVisibility); window.addEventListener("hashchange", () => this.updateVisibility());
this.updateVisibility(); this.updateVisibility();
}, },
@@ -1366,7 +1431,11 @@ const SlideCreator = {
let trailerUrl = null; let trailerUrl = null;
// 1. Check for Remote Trailers (YouTube) // 1. Check for Remote Trailers (YouTube)
if (item.RemoteTrailers && item.RemoteTrailers.length > 0) { // Priority: Custom Config URL > Metadata RemoteTrailer
if (STATE.slideshow.customTrailerUrls && STATE.slideshow.customTrailerUrls[itemId]) {
trailerUrl = STATE.slideshow.customTrailerUrls[itemId];
console.log(`Using custom trailer URL for ${itemId}: ${trailerUrl}`);
} else if (item.RemoteTrailers && item.RemoteTrailers.length > 0) {
trailerUrl = item.RemoteTrailers[0].Url; trailerUrl = item.RemoteTrailers[0].Url;
} }
@@ -1415,6 +1484,21 @@ const SlideCreator = {
loop: 0 loop: 0
}; };
// Determine video quality
let quality = 'hd1080';
if (CONFIG.preferredVideoQuality === 'Maximum') {
quality = 'highres';
} else if (CONFIG.preferredVideoQuality === '720p') {
quality = 'hd720';
} else if (CONFIG.preferredVideoQuality === '1080p') {
quality = 'hd1080';
} else { // Auto or fallback
// If screen is wider than 1920, prefer highres, otherwise 1080p
quality = window.screen.width > 1920 ? 'highres' : 'hd1080';
}
playerVars.suggestedQuality = quality;
// Apply SponsorBlock start/end times // Apply SponsorBlock start/end times
if (segments.intro) { if (segments.intro) {
playerVars.start = Math.ceil(segments.intro[1]); playerVars.start = Math.ceil(segments.intro[1]);
@@ -1444,6 +1528,10 @@ const SlideCreator = {
event.target.setVolume(40); event.target.setVolume(40);
} }
if (typeof event.target.setPlaybackQuality === 'function') {
event.target.setPlaybackQuality(quality);
}
// Only play if this is the active slide // Only play if this is the active slide
const slide = document.querySelector(`.slide[data-item-id="${itemId}"]`); const slide = document.querySelector(`.slide[data-item-id="${itemId}"]`);
if (slide && slide.classList.contains('active')) { if (slide && slide.classList.contains('active')) {
@@ -1492,6 +1580,7 @@ const SlideCreator = {
className: "backdrop video-backdrop", className: "backdrop video-backdrop",
src: trailerUrl, src: trailerUrl,
autoplay: false, autoplay: false,
preload: "auto",
loop: false, loop: false,
style: "object-fit: cover; width: 100%; height: 100%; pointer-events: none;" style: "object-fit: cover; width: 100%; height: 100%; pointer-events: none;"
}; };
@@ -2317,6 +2406,65 @@ const SlideshowManager = {
} }
}, },
/**
* Stops all video playback (YouTube and HTML5)
* Used when navigating away from the home screen
*/
stopAllPlayback() {
// 1. Pause all YouTube players
if (STATE.slideshow.videoPlayers) {
Object.values(STATE.slideshow.videoPlayers).forEach(player => {
try {
if (player && typeof player.pauseVideo === 'function') {
player.pauseVideo();
}
} catch (e) {
console.warn("Error pausing YouTube player:", e);
}
});
}
// 2. Pause all HTML5 videos
const container = document.getElementById("slides-container");
if (container) {
container.querySelectorAll('video').forEach(video => {
try {
video.pause();
} catch (e) {
console.warn("Error pausing HTML5 video:", e);
}
});
}
},
/**
* Resumes playback for the active slide if not globally paused
*/
resumeActivePlayback() {
if (STATE.slideshow.isPaused) return;
const currentItemId = STATE.slideshow.itemIds[STATE.slideshow.currentSlideIndex];
if (!currentItemId) return;
const currentSlide = document.querySelector(`.slide[data-item-id="${currentItemId}"]`);
if (!currentSlide) return;
// 1. Try YouTube Player
const ytPlayer = STATE.slideshow.videoPlayers[currentItemId];
if (ytPlayer && typeof ytPlayer.playVideo === 'function') {
ytPlayer.playVideo();
}
// 2. Try HTML5 Video
const html5Video = currentSlide.querySelector('video');
if (html5Video) {
if (STATE.slideshow.isMuted) {
html5Video.muted = true;
}
html5Video.play().catch(e => console.warn("Error resuming HTML5 video:", e));
}
},
/** /**
* Initializes touch events for swiping * Initializes touch events for swiping
*/ */
@@ -2434,9 +2582,24 @@ const SlideshowManager = {
parseCustomIds() { parseCustomIds() {
if (!CONFIG.enableSeasonalContent) { if (!CONFIG.enableSeasonalContent) {
return CONFIG.customMediaIds return CONFIG.customMediaIds
.split(/[\n,]/) // Split by comma or newline .split(/[\n,]/).map((line) => {
.map((id) => id.trim()) // Remove whitespace const urlMatch = line.match(/\[(.*?)\]/);
.filter((id) => id); // Remove empty strings let id = line;
if (urlMatch) {
const url = urlMatch[1];
id = line.replace(/\[.*?\]/, '').trim();
const guidMatch = id.match(/([0-9a-f]{32})/i);
if (guidMatch) {
id = guidMatch[1];
} else {
id = id.split('|')[0].trim();
}
STATE.slideshow.customTrailerUrls[id] = url;
}
return id.trim();
})
.map((id) => id.trim())
.filter((id) => id);
} else { } else {
return this.parseSeasonalIds(); return this.parseSeasonalIds();
} }
@@ -2493,7 +2656,22 @@ const SlideshowManager = {
if (isInRange) { if (isInRange) {
console.log(`Seasonal match found: ${line}`); console.log(`Seasonal match found: ${line}`);
const ids = idsPart.split(/[,]/).map(id => id.trim()).filter(id => id); const ids = idsPart.split(/[,]/).map(line => {
const urlMatch = line.match(/\[(.*?)\]/);
let id = line;
if (urlMatch) {
const url = urlMatch[1];
id = line.replace(/\[.*?\]/, '').trim();
const guidMatch = id.match(/([0-9a-f]{32})/i);
if (guidMatch) {
id = guidMatch[1];
} else {
id = id.split('|')[0].trim();
}
STATE.slideshow.customTrailerUrls[id] = url;
}
return id.trim();
}).filter(id => id);
rawIds.push(...ids); rawIds.push(...ids);
} }
} }
@@ -2514,8 +2692,13 @@ const SlideshowManager = {
try { try {
let id = rawId; let id = rawId;
// If not a valid GUID, treat as a name and search // If not a valid GUID, check if it starts with one (comments) or treat as a name
if (!guidRegex.test(rawId)) { if (!guidRegex.test(rawId)) {
const guidMatch = rawId.match(/^([0-9a-f]{32})(?:[^0-9a-f]|$)/i);
if (guidMatch) {
id = guidMatch[1];
} else {
console.log(`Input '${rawId}' is not a GUID, searching for Collection/Playlist by name...`); console.log(`Input '${rawId}' is not a GUID, searching for Collection/Playlist by name...`);
const resolvedId = await ApiUtils.findCollectionOrPlaylistByName(rawId); const resolvedId = await ApiUtils.findCollectionOrPlaylistByName(rawId);
@@ -2527,6 +2710,7 @@ const SlideshowManager = {
continue; // Skip if resolution failed continue; // Skip if resolution failed
} }
} }
}
const item = await ApiUtils.fetchItemDetails(id); const item = await ApiUtils.fetchItemDetails(id);
if (item && (item.Type === 'BoxSet' || item.Type === 'Playlist')) { if (item && (item.Type === 'BoxSet' || item.Type === 'Playlist')) {
@@ -2839,7 +3023,7 @@ const slidesInit = async () => {
} }
}; };
window.slideshowPure = { window.mediaBarEnhanced = {
CONFIG, CONFIG,
STATE, STATE,
SlideUtils, SlideUtils,

239
README.md
View File

@@ -1 +1,238 @@
# jellyfin-plugin-media-bar-enhanced # Jellyfin Media Bar Enhanced Plugin
Media Bar Enhanced is a plugin for Jellyfin that introduces a customizable and interactive media bar to your dashboard view on Jellyfin web.
This plugin is a fork and enhancement of the original [Media Bar by MakD](https://github.com/MakD/Jellyfin-Media-Bar), but can be installed as plugin for easier installation and management/configuration.
![logo](https://raw.githubusercontent.com/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/main/logo.png)
---
## Table of Contents
- [Jellyfin Media Bar Enhanced Plugin](#jellyfin-media-bar-enhanced-plugin)
- [Table of Contents](#table-of-contents)
- [Overview](#overview)
- [Features](#features)
- [New Features \& Enhancements](#new-features--enhancements)
- [Core Features](#core-features)
- [Installation](#installation)
- [Client Compatibility](#client-compatibility)
- [Configuration](#configuration)
- [General Settings](#general-settings)
- [Custom Content](#custom-content)
- [Advanced Settings](#advanced-settings)
- [Build The Plugin By Yourself](#build-the-plugin-by-yourself)
- [Troubleshooting](#troubleshooting)
- [Effects Not Showing](#effects-not-showing)
- [Docker Permission Issues](#docker-permission-issues)
- [Contributing](#contributing)
---
## Overview
![demo](https://github.com/user-attachments/assets/3a01b886-1a96-4dd1-abf6-e9c3b054bfde)
Expand to get more impressions:
<details>
<summary>Desktop Layout</summary>
<img width="1920" height="1080" alt="trailer button" src="https://github.com/user-attachments/assets/5dce8eb1-8f2f-4583-a6d5-16f27ced8608" />
Normal mode like the original with additional trailer button
<br><br><br>
<img width="1920" height="993" alt="modal_desktop" src="https://github.com/user-attachments/assets/9087f43d-cd9d-4581-a7e0-404b75bc8e02" />
Trailer modal
<br><br><br>
<img width="1920" height="994" alt="config" src="https://github.com/user-attachments/assets/5492c384-a5c4-47ee-9428-3d9de2748e63" />
Excerpt from the config: E.g. here you can simply add your items that should be displayed
<br><br>
</details>
<details>
<summary>Mobile Layout</summary>
![demo_mobile](https://github.com/user-attachments/assets/d11a7ed0-ceb7-43c3-9b22-09510251e0aa)
<br>If trailer on mobile is eenabled...
<br><br><br>
<img width="1080" height="2199" alt="mobile" src="https://github.com/user-attachments/assets/f0a0cc0d-f019-45f5-96c8-a5de14bf92ba" />
Normal mode like the original with additional trailer button
<br><br><br>
<img width="1080" height="2199" alt="trailer_modal_mobile" src="https://github.com/user-attachments/assets/944f9b82-9c9b-411f-883b-877b65ed933f" />
Trailer modal in portrait mode
<br><br>
</details>
## Features
This plugin builds upon the original Media Bar with new capabilities and improvements:
### New Features & Enhancements
* **Video Backdrop Support**: Play trailer as background video directly in the slideshow
* **SponsorBlock Integration**: Automatically skip intro/outro segments in YouTube trailers
* **Enhanced Controls**:
* Keyboard shortcuts (Arrow keys to navigate, Space to pause, M to mute)
* Option to always show navigation arrows
* Standalone "Trailer" button (opens in a modal) if video backdrops are disabled
* **Smarter Playback**:
* Option to wait for the trailer to end before advancing the slide.
* Mute/Unmute controls
* **Customization**:
* **Custom Media IDs**: Manually specify which items (Movies, Series, Collections/Boxsets) to display. Easily configurable via the plugin settings
* **Seasonal Content Mode**: Define date-based lists for holidays and seasons (e.g., Halloween, Christmas)
* Pagination dots turn into a counter (e.g., 1/20) if the limit is exceeded
* Option to disable the loading screen
### Core Features
* **Immersive Slideshow**: Rotates through your media library
* **Metadata Display**: Shows title, rating, year, and plot summary
* **Direct Play**: Click "Play" to start watching immediately
* **Details View**: Click "Info" to jump to the item's detail page
* **Add To Favorites**: Click the heart to add the item to your favorites
## Installation
This plugin is based on Jellyfin Version `10.11.x`
1. Open your **Jellyfin Dashboard**.
2. Navigate to **Plugins** > **Repositories**.
3. Click the **+** button to add a new repository.
4. Enter a name for the repo and paste the following URL:
```
https://raw.githubusercontent.com/CodeDevMLH/jellyfin-plugin-manifest/refs/heads/main/manifest.json
```
5. Click **Save**.
6. Go to the **Catalog** tab.
7. Find **Media Bar Enhanced** (Under **General**) and install it.
8. **Restart your Jellyfin server.**
9. **Refresh your browser** (Ctrl+F5) to load the new interface elements.
## Client Compatibility
Because this plugin relies on injecting JavaScript and CSS into the web interface, it works best on clients that use the web wrapper.
| Client Platform | Status | Notes |
| :--- | :---: | :--- |
| **Web Browsers** (Chrome, Firefox, Edge, etc.) | ✅ | Fully supported. |
| **Jellyfin Media Player** (Windows/Linux/macOS) | ✅ | Fully supported. |
| **Android App** | ✅ | Works (Web wrapper). |
| **iOS App** | ✅ | Works (Web wrapper). |
| **Android TV / Fire TV** | ❌ | **Not supported** (Native UI). |
| **Roku** | ❌ | **Not supported** (Native UI). |
| **Swiftfin** | ❌ | **Not supported** (Native UI). |
## Configuration
Configure the plugin via **Dashboard** > **Plugins** > **Media Bar Enhanced**.
> [!NOTE]
> You must refresh your browser window (F5 or Ctrl+R) after saving changes for them to take effect.
### General Settings
* **Enable Media Bar Enhanced Plugin**: Master switch to toggle the plugin.
* **Enable Video Backdrops**: Dynamically plays trailers in the background.
* **Wait For Trailer To End**: Prevents slide transition until the video finishes.
* **Enable Mobile Video**: specific setting to allow video playback on mobile devices (disabled by default to save data/battery).
* **Show Trailer Button**: Adds a button to open the trailer in a popup modal if video backdrops are disabled (e.g. on mobile if trailers are disabled there)
### Custom Content
Define exactly what shows up in your bar.
* **Enable Custom Media IDs**: Restrict the slideshow to a specific list of IDs.
* **Manual Trailer Override**: Add `[YouTube_URL]` after an ID to force a specific trailer.
* Example ID: `a1b2c3d4e5... [https://www.youtube.com/watch?v=VIDEO_ID]`
* Example Collection Name: `Halloween Collection [https://...] | My Description` (Note: Use `|` to separate description from name if using a name instead of an ID)
* **Enable Seasonal Content Mode**: Advanced date-based scheduling.
* Format: `DD.MM-DD.MM | Name | ID1, ID2, ID3`
* Example: `20.10-31.10 | Halloween | <ID_OF_HALLOWEEN_COLLECTION>`
* If the current date matches a range, those IDs are used. Otherwise, it defaults to standard behavior or the Custom Media IDs list.
**How to get IDs:**
Check the URL of an item in the web interface:
`.../web/#/details?id=YOUR_ITEM_ID_HERE&...`
### Advanced Settings
* **Slide Animations**: Enable/disable the "Zoom In" effect.
* **Use SponsorBlock**: Skips non-content segments in YouTube trailers (if the data exists).
* **Start Muted**: Videos start without sound (user can unmute).
* **Full Width Video**: Stretches video to cover the entire width (good for desktop, crop on mobile).
* **Enable Loading Screen**: Enable/disable the loading indicator while the bar initializes.
* **Always Show Arrows**: Keeps navigation arrows visible instead of hiding them on mouse leave.
* **Enable Keyboard Controls**:
* `Left`/`Right`: Change slide
* `Space`: Pause/Play slideshow
* `M`: Mute/Unmute video
* **Content Limits**: Fine-tune performance by limiting the number of items (Movies, TV Shows) fetched.
## Build The Plugin By Yourself
If you want to build the plugin yourself:
1. Clone the repository.
2. Ensure you have the .NET SDK installed (NET 8 or 9 depending on your Jellyfin version).
3. Run the build command:
```powershell
dotnet build Jellyfin.Plugin.MediaBarEnhanced/Jellyfin.Plugin.MediaBarEnhanced.csproj --configuration Release --output bin/Publish
```
4. The compiled DLL and resources will be in bin/Publish.
## Troubleshooting
### Effects Not Showing
1. **Verify plugin installation**:
- Check that the plugin appears in the jellyfin admin panel
- Ensure that the plugin is enabled and active
2. **Clear browser cache**:
- Force refresh browser (Ctrl+F5)
- Clear jellyfin web client cache (--> mostly you have to clear the whole browser cache)
### Docker Permission Issues
If you encounter the message `Access was denied when attempting to inject script into index.html. Automatic direct injection failed. Automatic direct insertion failed. The system will now attempt to use the File Transformation plugin.` in the log or similar permission errors in Docker:
**Option 1: Use File Transformation Plugin (Recommended)**
Media Bar Enhanced now automatically detects and uses the [File Transformation](https://github.com/IAmParadox27/jellyfin-plugin-file-transformation) plugin (v2.5.0.0+) if it's installed. This eliminates permission issues by transforming content at runtime without modifying files on disk.
**Installation Steps:**
1. Install the File Transformation plugin from the Jellyfin plugin catalog
2. Restart Jellyfin
3. Media Bar Enhanced will automatically detect and use it (no configuration needed)
4. Check logs to confirm: Look for "Successfully registered transformation with File Transformation plugin"
**Benefits:**
- No file permission issues in Docker environments
- Works with read-only web directories
- Survives Jellyfin updates without re-injection
- No manual file modifications required
**Option 2: Fix File Permissions**
```bash
# Find the actual index.html location
docker exec -it jellyfin find / -name index.html
# Fix ownership (replace 'jellyfin' with your container name and adjust user:group if needed)
docker exec -it --user root jellyfin chown jellyfin:jellyfin /jellyfin/jellyfin-web/index.html
# Restart container
docker restart jellyfin
```
**Option 3: Manual Volume Mapping**
```bash
# Extract index.html from container
docker cp jellyfin:/jellyfin/jellyfin-web/index.html /path/to/jellyfin/config/index.html
# Add to docker-compose.yml volumes section:
volumes:
- /path/to/jellyfin/config/index.html:/jellyfin/jellyfin-web/index.html
```
## Contributing
Feel free to contribute to this project by creating pull requests or reporting issues.

78
RELEASE_GUIDE.md Normal file
View File

@@ -0,0 +1,78 @@
# Release & Update Guide
Diese Anleitung beschreibt die Schritte, die notwendig sind, um eine neue Version des **MediaBar** Plugins zu veröffentlichen.
## 1. Version erhöhen
Bevor du baust, musst du die Versionsnummer in den folgenden Dateien aktualisieren (z.B. von `1.0.0.0` auf `1.0.1.0`):
1. **`Jellyfin.Plugin.MediaBar/Jellyfin.Plugin.MediaBar.csproj`**
Suche nach `<Version>...</Version>` und ändere die Nummer.
2. **`manifest.json`**
Füge einen neuen Eintrag oben in die `versions`-Liste ein (oder bearbeite den vorhandenen, wenn es noch kein Release gab).
* `version`: Deine neue Nummer.
* `changelog`: Was hat sich geändert?
* `timestamp`: Das aktuelle Datum (wird später aktualisiert).
* `checksum`: (wird nach dem Build aktualisiert).
### Versionierungsschema: Major.Minor.Build.Revision
(Beispiel: 1.0.0.0)
1. **Major** (1.x.x.x)
* **Bedeutung:** Hauptversion.
* **Erhöhen bei:** Inkompatiblen Änderungen (Breaking Changes) oder komplettem Rewrite.
* **Folge:** Setzt alle nachfolgenden Zahlen auf 0.
2. **Minor** (x.1.x.x)
* **Bedeutung:** Nebenversion.
* **Erhöhen bei:** Neuen Features / Funktionen, die abwärtskompatibel sind.
* **Folge:** Setzt Build und Revision auf 0.
3. **Build** (x.x.1.x)
* **Bedeutung:** Patch / Fehlerbehebung.
* **Erhöhen bei:** Bugfixes, Sicherheitsupdates (keine neuen Features).
* **Folge:** Setzt Revision auf 0.
4. **Revision** (x.x.x.1)
* **Bedeutung:** Feingranularer Zähler.
* **Erhöhen bei:** Notfall-Fixes (Hotfixes), automatisierter Erstellung (CI/CD) oder internen Anpassungen.
## 2. Plugin bauen und packen
Führe den folgenden Befehl im Terminal (PowerShell) im Hauptverzeichnis aus. Wir nutzen hier `dotnet build` statt `publish`, um unnötige Dateien zu vermeiden.
```powershell
dotnet build Jellyfin.Plugin.MediaBar/Jellyfin.Plugin.MediaBar.csproj --configuration Release --output bin/Publish; Compress-Archive -Path bin/Publish/* -DestinationPath bin/Publish/Jellyfin.Plugin.MediaBar.zip -Force; $hash = (Get-FileHash -Algorithm MD5 bin/Publish/Jellyfin.Plugin.MediaBar.zip).Hash.ToLower(); $time = (Get-Date).ToUniversalTime().ToString("yyyy-MM-ddTHH:mm:ssZ"); Write-Output "`n----------------------------------------"; Write-Output "NEUE CHECKSUMME (MD5): $hash"; Write-Output "ZEITSTEMPEL: $time"; Write-Output "----------------------------------------`n"
```
## 3. Manifest aktualisieren
Nachdem der Befehl durchgelaufen ist, siehst du am Ende eine Ausgabe wie:
```text
----------------------------------------
NEUE CHECKSUMME (MD5): ef8654666ffeae9695e660944f644ad3
ZEITSTEMPEL: 2025-12-15T12:34:56Z
----------------------------------------
```
1. Kopiere die **Checksumme**.
2. Öffne `manifest.json`.
3. Füge die Checksumme bei deinem Versionseintrag unter `"checksum"` ein.
4. Kopiere den **Zeitstempel** und füge ihn unter `"timestamp"` ein.
5. Stelle sicher, dass die `sourceUrl` korrekt auf dein Repository zeigt.
## 4. Veröffentlichen
1. Lade die Datei `bin/Publish/Jellyfin.Plugin.MediaBar.zip` irgendwo hoch (z.B. GitHub Releases).
2. Stelle sicher, dass die `sourceUrl` im `manifest.json` auf diesen Download zeigt (oder auf das Repo, je nachdem wie Jellyfin das handhabt - meistens ist `sourceUrl` der Link zum ZIP).
* *Hinweis:* Wenn du das Plugin über ein Repo hostest, muss die URL im Manifest direkt auf die ZIP-Datei zeigen.
## Zusammenfassung der Dateien
| Datei | Zweck | Änderung nötig? |
| :--- | :--- | :--- |
| `Jellyfin.Plugin.MediaBar.csproj` | Definiert die DLL-Version | **Ja** |
| `build.yaml` | Build-Konfiguration | **Ja** |
| `manifest.json` | Plugin-Liste für Jellyfin | **Ja** (Version, Hash, Zeit) |

107
git_cheat_sheet.md Normal file
View File

@@ -0,0 +1,107 @@
# 🚀 Git Cheat Sheet: Branches, Merge, Rebase & VS Code
## 🌳 Branches (Zweige)
* **`main`** → Stabiler Stand, Production-ready (Deployment).
* **`dev`** → Aktive Entwicklung, Sammelbecken für Features.
---
## 🛠 Zusammenführen von Änderungen
### Git Merge
Führt zwei Zweige zusammen. Git sucht den letzten gemeinsamen Basispunkt und erstellt einen neuen **Merge-Commit**.
```bash
git checkout dev
git merge main
```
| Details | |
|-----------|--------|
| Wann? | In Team-Branches, bei bereits gepushten Branches, wenn Stabilität wichtiger als eine saubere History ist. |
| Vorteile | Sicher, einfach nachvollziehbar, schreibt die History nicht um. |
| Nachteile | Die History kann bei vielen Merges unübersichtlich ("Spaghetti-Graph") werden. |
### Git Rebase
Setzt deine Commits neu auf die Spitze eines anderen Branches. Die Commit-IDs werden dabei neu geschrieben.
```bash
git checkout dev
git fetch origin
git rebase origin/main
```
| Details | |
|-----------|--------|
| Wann? | In lokalen Feature-Branches (bevor sie geteilt werden), um die History sauber zu halten. |
| Vorteile | Erzeugt eine perfekt lineare, leicht lesbare History. |
| Nachteile | ⚠️ Gefährlich auf geteilten/öffentlichen Branches. Konflikte müssen ggf. für jeden einzelnen Commit gelöst werden. |
---
## 📦 Temporäres Speichern & Spezialbefehle
### Stash (Das "Regal")
Speichert uncommitted Changes temporär, um das Arbeitsverzeichnis sauber zu machen, ohne zu committen.
```bash
git stash # Änderungen "parken".
git stash pop # Änderungen zurückholen und Stash leeren.
```
**Wann?** Wenn du schnell den Branch wechseln musst, aber deine Arbeit noch nicht fertig ist.
### Cherry-pick
Kopiert einen ganz gezielten Commit von einem Branch in deinen aktuellen.
```bash
git cherry-pick <commit-hash>
```
**Wann?** Wenn ein Bugfix auf dem falschen Branch gelandet ist oder du nur eine einzige Funktion aus einem Feature-Branch brauchst.
---
## 🔄 Checkout & Switch
```bash
git checkout dev # oder git switch dev Wechselt zum Branch.
git checkout -f dev # Force Checkout: Wechselt den Branch und verwirft alle ungespeicherten lokalen Änderungen unwiderruflich! ⚠️
```
---
## 💻 VS Code Git-Optionen (UI)
VS Code bietet beim Branch-Wechsel oft drei intelligente Optionen an:
* **Migrate Changes ⭐**
* Nimmt deine aktuellen Änderungen einfach mit in den neuen Branch.
* (Intern: stash → switch → stash pop).
* **Stash & Checkout**
* Parkt deine Änderungen sicher im Stash und wechselt den Branch. Die Änderungen bleiben im Stash, bis du sie manuell wieder herausholst.
* **Force Checkout ⚠️**
* Wechselt den Branch und löscht deine aktuellen, ungespeicherten Änderungen. Nur nutzen, wenn die Arbeit weggeworfen werden kann.
---
## 🔄 Typischer Sync-Workflow
Um den Entwicklungs-Branch aktuell zu halten, nachdem dev in main gemerged wurde:
1. Auf dev entwickeln.
2. Merge dev → main für das Release.
3. Zurück auf dev wechseln:
```bash
git checkout dev
git merge main # (oder rebase), um den neuesten Stand vom Main wieder in Dev zu haben.
```
---
## 🧠 Merksätze
* **Merge** = Historien verbinden (Sicher & Dokumentiert).
* **Rebase** = Historie neu schreiben (Linear & Sauber).
* **Stash** = "Ich parke das mal kurz hier."
* **Migrate Changes** = Sicherer Branch-Wechsel mit "Gepäck".

BIN
logo.png

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 MiB

After

Width:  |  Height:  |  Size: 312 KiB

BIN
logos/MediaBar_logo_mod.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 312 KiB

View File

@@ -2,171 +2,83 @@
{ {
"guid": "d7e11d57-819b-4bdd-a88d-53c5f5560225", "guid": "d7e11d57-819b-4bdd-a88d-53c5f5560225",
"name": "Media Bar Enhanced", "name": "Media Bar Enhanced",
"description": "Adds a enhanced media bar (featured content) to the Jellyfin web interface.", "description": "A feature-rich fork of the original Media Bar script by MakD that brings your home screen to life.\n\n-> 100% Configurable via Web UI: Manage all features, lists, and settings effortlessly through the plugin configuration page.\n\nKey Highlights:\n- Cinematic Video Backdrops: Supports local & YouTube trailers (incl. SponsorBlock)\n- Custom Content: Curate your slideshow with specific Collections, Playlists, or seasonal events\n\nAdditional Features:\n- Full-width immersive mode\n- Smart resolution handling (up to 4K)\n- Full keyboard navigation & playback control\n- Wait-for-trailer options\n- Customizable pagination & animations\n\nIf you do not have write permissions to the web folder, please also install the file-transformation plugin.",
"overview": "Media Bar for Jellyfin", "overview": "Transforms your Jellyfin home screen with an immersive, fully configurable media slideshow featuring video backdrops.",
"owner": "CodeDevMLH", "owner": "CodeDevMLH",
"category": "General", "category": "General",
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/raw/branch/main/logo.png", "imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/raw/branch/main/logo.png",
"versions": [ "versions": [
{
"version": "1.5.0.0",
"changelog": "Renamed to Media Bar Enhanced",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.5.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "ccf3a1e8caaa86f298d4f20cd815edf1",
"timestamp": "2026-01-06T01:18:41Z"
},
{
"version": "1.4.0.0",
"changelog": "Add more config description, add search collection/playlist by name",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.4.0.0/Jellyfin.Plugin.MediaBar.zip",
"checksum": "b8a3667fa8290242c74411b2bd1c06da",
"timestamp": "2026-01-04T23:50:01Z"
},
{ {
"version": "1.3.0.0", "version": "1.3.0.0",
"changelog": "Add file transformation fallback", "changelog": "- feat: Enhance custom media ID functionality with manual trailer override support",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.3.0.0/Jellyfin.Plugin.MediaBar.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.3.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "4379eab39684501af97876abe1b4ab91", "checksum": "83c26ba8f7ad6e1a7fe73c7190f532f3",
"timestamp": "2026-01-04T23:47:38Z" "timestamp": "2026-02-04T00:07:15Z"
},
{
"version": "1.2.3.7",
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.\n- Update mediaBarEnhanced.js and mediaBarEnhanced.css with version 3.0.9 from original repo",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.7/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "fa1bf48cff159cc7dbf0aab48511a37c",
"timestamp": "2026-01-28T22:39:54Z"
},
{
"version": "1.2.2.0",
"changelog": "- Fixes issues with persistent slides-container visibility",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.2.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "3362f93815845c4e85b66b31bcd0f52c",
"timestamp": "2026-01-24T22:53:55Z"
},
{
"version": "1.2.1.0",
"changelog": "- Update mediaBarEnhanced.js and mediaBarEnhanced.css with version 3.0.8 from original repo",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.1.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "70defc1fb29a17ff4c9362bf7bdc53b5",
"timestamp": "2026-01-22T23:50:56Z"
}, },
{ {
"version": "1.2.0.0", "version": "1.2.0.0",
"changelog": "Add seasonals content mode", "changelog": "- Add video quality preference setting (Auto / 1080p / Highres)\n- Set preferred video quality on YouTube player based on setting",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.2.0.0/Jellyfin.Plugin.MediaBar.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "8ad0b9d38aa4bd4bd16e1f9f0e6c4d8c", "checksum": "0b6379f68990026240d97fe8f77fbef1",
"timestamp": "2026-01-04T15:13:36Z" "timestamp": "2026-01-08T23:30:58Z"
}, },
{ {
"version": "1.1.0.6", "version": "1.1.2.0",
"changelog": "UI improvements", "changelog": "- Add method to resume video playback when slideshow is active",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.1.0.6/Jellyfin.Plugin.MediaBar.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.1.2.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "91d342865ebdf9b4efd53561125c5604", "checksum": "a0e8ff5e59b22a1bdedc916cd5e1c16a",
"timestamp": "2026-01-04T14:19:50Z" "timestamp": "2026-01-08T15:26:55Z"
}, },
{ {
"version": "1.1.0.5", "version": "1.1.1.0",
"changelog": "Added collection (boxsets) IDs to slideshow option", "changelog": "- Add method to pause all video playback when navigating away from home screen",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.1.0.5/Jellyfin.Plugin.MediaBar.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.1.1.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "41b4ddf3b6f9fc79eac64acb24989e67", "checksum": "09da95fc561b11191d23a5cfa30ea731",
"timestamp": "2026-01-04T14:09:29Z" "timestamp": "2026-01-08T14:54:57Z"
},
{
"version": "1.1.0.4",
"changelog": "Added loading screen disable option T3",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.1.0.4/Jellyfin.Plugin.MediaBar.zip",
"checksum": "f0d2bf6c1ce7bd7166776cd7a4e59d6f",
"timestamp": "2026-01-04T12:41:07Z"
},
{
"version": "1.1.0.3",
"changelog": "Added loading screen disable option",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.1.0.3/Jellyfin.Plugin.MediaBar.zip",
"checksum": "f93373b9bb1f3614e4d4237b04619c32",
"timestamp": "2026-01-04T01:57:20Z"
},
{
"version": "1.1.0.2",
"changelog": "Added loading screen disable option",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.1.0.2/Jellyfin.Plugin.MediaBar.zip",
"checksum": "06907adcd3f6e022c622d5c91119d1e1",
"timestamp": "2026-01-03T23:03:51Z"
},
{
"version": "1.1.0.1",
"changelog": "Added custom media ids",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.1.0.1/Jellyfin.Plugin.MediaBar.zip",
"checksum": "81e90c7a8778856641bbc47ac60ebb32",
"timestamp": "2026-01-03T23:00:39Z"
}, },
{ {
"version": "1.1.0.0", "version": "1.1.0.0",
"changelog": "Added custom media ids", "changelog": "- 'custom media IDs' setting is now enabled by default (no input --> random selection)\n- improve GUID handling in slideshow manager to handle seperator and description",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.1.0.0/Jellyfin.Plugin.MediaBar.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.1.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "03ee3f2eed26ebbc959ef49730018a98", "checksum": "32305d72b8d704acf8eef0c22277fee9",
"timestamp": "2026-01-03T22:44:54Z" "timestamp": "2026-01-08T02:15:50Z"
},
{
"version": "1.0.0.8",
"changelog": "small ui changes",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.8/Jellyfin.Plugin.MediaBar.zip",
"checksum": "f1e8acb78422f6dc729b4086deb9929e",
"timestamp": "2026-01-03T18:43:37Z"
},
{
"version": "1.0.0.7",
"changelog": "always show arrows & keyboard controls",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.7/Jellyfin.Plugin.MediaBar.zip",
"checksum": "e88519a9a7405eb5083e7c950eb4a08b",
"timestamp": "2026-01-03T18:22:25Z"
},
{
"version": "1.0.0.6",
"changelog": "",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.6/Jellyfin.Plugin.MediaBar.zip",
"checksum": "18137a92aa8966584e123ba76bbe71c2",
"timestamp": "2026-01-03T18:11:43Z"
},
{
"version": "1.0.0.5",
"changelog": "",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.5/Jellyfin.Plugin.MediaBar.zip",
"checksum": "156f980aad077b272887a6ab3cfcdfe9",
"timestamp": "2026-01-03T02:42:00Z"
},
{
"version": "1.0.0.4",
"changelog": "",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.4/Jellyfin.Plugin.MediaBar.zip",
"checksum": "e05f0024fe66a9b271c216c3555ce9ff",
"timestamp": "2026-01-03T02:15:29Z"
},
{
"version": "1.0.0.3",
"changelog": "",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.3/Jellyfin.Plugin.MediaBar.zip",
"checksum": "c652dba434689a1116e10010235fa48c",
"timestamp": "2026-01-03T01:42:53Z"
},
{
"version": "1.0.0.2",
"changelog": "",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.2/Jellyfin.Plugin.MediaBar.zip",
"checksum": "aded8f61ac5aed3449190cf7c41aa693",
"timestamp": "2026-01-03T01:13:21Z"
},
{
"version": "1.0.0.1",
"changelog": "",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.1/Jellyfin.Plugin.MediaBar.zip",
"checksum": "8401a51d26ae1906a3eae9f8ff72e9a3",
"timestamp": "2026-01-02T22:45:28Z"
}, },
{ {
"version": "1.0.0.0", "version": "1.0.0.0",
"changelog": "", "changelog": "Initial release",
"targetAbi": "10.11.0.0", "targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Media-Bar-Plugin/releases/download/v1.0.0.0/Jellyfin.Plugin.MediaBar.zip", "sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.0.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "3cbd8527a0cb191dbc4a5126b49b60f9", "checksum": "2ba7cc7f238f6aa7097628797935b903",
"timestamp": "2026-01-02T22:08:37Z" "timestamp": "2026-01-06T18:56:30Z"
} }
] ]
} }

View File

@@ -1,157 +0,0 @@
name: Auto Release Plugin
on:
push:
branches:
- main
paths-ignore:
- '.github/**'
- 'README.md'
- 'jellyfin.ruleset'
- '.gitignore'
- '.editorconfig'
- 'LICENSE'
- 'logo.png'
jobs:
build-and-release:
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
- name: Setup .NET
uses: actions/setup-dotnet@v5
with:
dotnet-version: '9.x'
- name: Read Version from Manifest
id: read_version
run: |
VERSION=$(jq -r '.[0].versions[0].version' manifest.json)
CHANGELOG=$(jq -r '.[0].versions[0].changelog' manifest.json)
TARGET_ABI=$(jq -r '.[0].versions[0].targetAbi' manifest.json)
echo "Detected Version: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
# Escape newlines in changelog for GITHUB_ENV
echo "CHANGELOG<<EOF" >> $GITHUB_ENV
echo "$CHANGELOG" >> $GITHUB_ENV
echo "EOF" >> $GITHUB_ENV
- name: Build and Zip
shell: bash
run: |
# Inject version from manifest into the build
dotnet build Jellyfin.Plugin.MediaBarEnhanced/Jellyfin.Plugin.MediaBarEnhanced.csproj --configuration Release --output bin/Publish /p:Version=${{ env.VERSION }} /p:AssemblyVersion=${{ env.VERSION }}
cd bin/Publish
zip -r Jellyfin.Plugin.MediaBarEnhanced.zip *
cd ../..
# Calculate hash
HASH=$(md5sum bin/Publish/Jellyfin.Plugin.MediaBarEnhanced.zip | awk '{ print $1 }')
TIME=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
# Export variables for next steps
echo "ZIP_HASH=$HASH" >> $GITHUB_ENV
echo "BUILD_TIME=$TIME" >> $GITHUB_ENV
echo "ZIP_PATH=bin/Publish/Jellyfin.Plugin.MediaBarEnhanced.zip" >> $GITHUB_ENV
- name: Update Local manifest.json (Optional)
shell: bash
run: |
REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}"
VERSION="${{ env.VERSION }}"
DOWNLOAD_URL="https://github.com/$REPO_OWNER/$REPO_NAME/releases/download/v$VERSION/Jellyfin.Plugin.MediaBarEnhanced.zip"
echo "Updating local manifest.json with:"
echo "Hash: ${{ env.ZIP_HASH }}"
echo "Time: ${{ env.BUILD_TIME }}"
echo "Url: $DOWNLOAD_URL"
jq --arg hash "${{ env.ZIP_HASH }}" \
--arg time "${{ env.BUILD_TIME }}" \
--arg url "$DOWNLOAD_URL" \
'.[0].versions[0].checksum = $hash | .[0].versions[0].timestamp = $time | .[0].versions[0].sourceUrl = $url' \
manifest.json > manifest.json.tmp && mv manifest.json.tmp manifest.json
- name: Commit Local manifest.json
uses: stefanzweifel/git-auto-commit-action@v7
with:
commit_message: "Update manifest.json for release v${{ env.VERSION }} [skip ci]"
file_pattern: manifest.json
- name: Create Release
uses: softprops/action-gh-release@v2
with:
tag_name: "v${{ env.VERSION }}"
name: "v${{ env.VERSION }}"
# body: ${{ env.CHANGELOG }}
files: ${{ env.ZIP_PATH }}
draft: false
prerelease: false
generate_release_notes: true
# Update Message in Remote Repository
- name: Checkout Central Manifest Repo
uses: actions/checkout@v4
with:
repository: ${{ github.repository_owner }}/jellyfin-plugin-manifest
path: central-manifest
token: ${{ secrets.CENTRAL_REPO_PAT }}
- name: Update Central Manifest
shell: bash
run: |
cd central-manifest
# 1. Get info from previous steps
VERSION="${{ env.VERSION }}"
HASH="${{ env.ZIP_HASH }}"
TIME="${{ env.BUILD_TIME }}"
# URL points to the RELEASE we just created in the CURRENT repo
DOWNLOAD_URL="https://github.com/${{ github.repository }}/releases/download/v$VERSION/Jellyfin.Plugin.MediaBarEnhanced.zip"
# 2. Extract GUID from the *built* artifact or the source manifest (in parent dir)
# We use the source manifest from the checkout in '..'
PLUGIN_GUID=$(jq -r '.[0].guid' ../manifest.json)
echo "Updating Central Manifest for Plugin GUID: $PLUGIN_GUID"
# 3. Update the specific plugin entry in the central manifest.json
# This logic finds the object with matching guid, and updates its first version entry.
jq --arg guid "$PLUGIN_GUID" \
--arg hash "$HASH" \
--arg time "$TIME" \
--arg url "$DOWNLOAD_URL" \
--arg ver "$VERSION" \
'map(if .guid == $guid then
.versions[0].version = $ver |
.versions[0].checksum = $hash |
.versions[0].timestamp = $time |
.versions[0].sourceUrl = $url
else . end)' \
manifest.json > manifest.json.tmp && mv manifest.json.tmp manifest.json
- name: Commit and Push Central Manifest
run: |
cd central-manifest
git config user.name "GitHub Action"
git config user.email "action@github.com"
# Check if there are changes
if [[ -n $(git status -s) ]]; then
git add manifest.json
git commit -m "Update MediaBar Enhanced to v${{ env.VERSION }}"
git push
else
echo "No changes to central manifest."
fi