Compare commits

..

107 Commits

Author SHA1 Message Date
CodeDevMLH
32e5e2b690 Update manifest.json for release v1.6.13.0 [skip ci] 2026-02-03 23:12:29 +00:00
CodeDevMLH
c967c1e308 Bump version to 1.6.13.0 and update changelog for new features and fixes
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-02-04 00:11:38 +01:00
CodeDevMLH
ae28d5219b Enhance README.md with additional details and images for configuration UI and user toggle features 2026-02-03 23:47:58 +01:00
CodeDevMLH
e4228f889e Add guidance for safely resetting 'dev' branch to 'main' in Git [skip ci] 2026-02-03 23:22:33 +01:00
CodeDevMLH
6d721c755e Update README.md to enhance documentation and add new seasonal themes 2026-02-03 23:06:47 +01:00
CodeDevMLH
6948953778 Add optional stash commands to Git rebase instructions 2026-02-03 23:04:58 +01:00
CodeDevMLH
8a50cef330 Update Git rebase instructions to include fetching from origin [skip ci] 2026-02-03 22:37:20 +01:00
CodeDevMLH
a0bf5370bd Update manifest.json for release v1.6.12.0 [skip ci] 2026-02-03 21:28:05 +00:00
CodeDevMLH
c5800b431d Bump version to 1.6.12.0 and update disabled options in configuration page
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-02-03 22:27:15 +01:00
CodeDevMLH
9a4056651d Update manifest.json for release v1.6.11.0 [skip ci] 2026-02-03 21:10:34 +00:00
CodeDevMLH
87382db78e Bump version to 1.6.11.0 and update configuration styles in the settings page
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-02-03 22:09:43 +01:00
CodeDevMLH
5d9afa762f Update manifest.json for release v1.6.10.0 [skip ci] 2026-02-03 21:03:41 +00:00
CodeDevMLH
2f88587dab Bump version to 1.6.10.0 and update logo source in settings
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-02-03 22:02:50 +01:00
CodeDevMLH
360a959b69 rename logo [skip ci] 2026-02-03 22:02:01 +01:00
CodeDevMLH
36fba545cf Update manifest.json for release v1.6.9.0 [skip ci] 2026-02-03 21:01:40 +00:00
CodeDevMLH
7faa2cc766 Merge branch 'main' of ssh://git.mahom03-spacecloud.de:44322/CodeDevMLH/Jellyfin-Seasonals-Plugin
Some checks failed
Auto Release Plugin / build-and-release (push) Has been cancelled
2026-02-03 22:00:43 +01:00
CodeDevMLH
aa832e93aa add logo [skip ci] 2026-02-03 22:00:32 +01:00
CodeDevMLH
86bbeb583d Update manifest.json for release v1.6.9.0 [skip ci] 2026-02-03 20:59:03 +00:00
CodeDevMLH
7a642b34b8 add assets [skip CI]
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 53s
2026-02-03 21:58:01 +01:00
CodeDevMLH
926b30b8ce Update manifest.json for release v1.6.9.0 [skip ci] 2026-02-03 20:30:56 +00:00
CodeDevMLH
5b672cef42 Bump version to 1.6.9.0; update logo asset path and manifest for new release
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 53s
2026-02-03 21:30:03 +01:00
CodeDevMLH
ceccbf4ded Update manifest.json for release v1.6.8.0 [skip ci] 2026-02-03 20:24:42 +00:00
CodeDevMLH
9cba2a0755 Bump version to 1.6.8.0; update manifest and add new logo assets
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 1m6s
2026-02-03 21:23:36 +01:00
CodeDevMLH
af036a9aa4 Update manifest.json for release v1.6.7.0 [skip ci] 2026-02-03 19:59:06 +00:00
CodeDevMLH
cfefd2d2d3 Bump version to 1.6.7.0; update manifest and configuration files for improved seasonal settings
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-02-03 20:58:14 +01:00
CodeDevMLH
8e7299508b Update manifest.json for release v1.6.6.0 [skip ci] 2026-02-03 19:51:20 +00:00
CodeDevMLH
fc7aa36f41 Bump version to 1.6.6.0; update manifest and settings popup for improved theme selection
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 53s
2026-02-03 20:50:28 +01:00
CodeDevMLH
fc9896048f Update manifest.json for release v1.6.5.0 [skip ci] 2026-02-03 19:37:37 +00:00
CodeDevMLH
572c4d9ace Bump version to 1.6.5.0 and update manifest; add new select options in settings popup
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-02-03 20:36:45 +01:00
CodeDevMLH
2572e085f6 Update manifest.json for release v1.6.4.0 [skip ci] 2026-02-03 18:46:36 +00:00
CodeDevMLH
8297f989fd Bump version to 1.6.4.0 and update changelog for new features; modify select classes in config page and settings popup
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 58s
2026-02-03 19:45:38 +01:00
CodeDevMLH
636aaa2a4a Update manifest.json for release v1.6.3.0 [skip ci] 2026-02-03 18:33:25 +00:00
CodeDevMLH
5e70621e93 Update version to 1.6.3.0, modify checkbox layout, and adjust popup styles
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-02-03 19:32:34 +01:00
CodeDevMLH
0b4434c51c Update manifest.json for release v1.6.2.0 [skip ci] 2026-02-03 18:18:35 +00:00
CodeDevMLH
dd6583c055 Bump version to 1.6.2.0 and update changelog for new features
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-02-03 19:17:44 +01:00
CodeDevMLH
a0b0514159 Update manifest.json for release v1.6.1.0 [skip ci] 2026-02-03 18:08:59 +00:00
CodeDevMLH
e977c83e8f Bump version to 1.6.1.0 in project file and manifest
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 53s
2026-02-03 19:08:07 +01:00
CodeDevMLH
e281f5c579 test other ui design 2026-02-03 19:08:02 +01:00
CodeDevMLH
e6b646e478 Update .gitignore to include test-site-new.html [skip CI] 2026-02-03 18:50:22 +01:00
CodeDevMLH
8d6bc12fa4 Update manifest.json for release v1.6.0.0 [skip ci] 2026-02-03 17:49:06 +00:00
CodeDevMLH
f036e748da Add client-side toggle option for seasonal settings
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 54s
2026-02-03 18:48:11 +01:00
CodeDevMLH
0177a7caea Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-28 22:40:50 +00:00
CodeDevMLH
c45e9f6156 Auto-Update MediaBar Enhanced to v1.2.3.7
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-01-28 22:40:00 +00:00
CodeDevMLH
8dc9b9f157 Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-28 21:32:51 +00:00
CodeDevMLH
e73c6c14bb Auto-Update MediaBar Enhanced to v1.2.3.6
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-01-28 21:32:01 +00:00
CodeDevMLH
aa1c60f9ce Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-28 20:22:17 +00:00
CodeDevMLH
d1e668bcff Auto-Update MediaBar Enhanced to v1.2.3.5
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-28 20:21:27 +00:00
CodeDevMLH
0454d43f32 Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-28 01:10:34 +00:00
CodeDevMLH
61b3b51139 Auto-Update MediaBar Enhanced to v1.2.3.4
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-01-28 01:09:45 +00:00
CodeDevMLH
60d1a546a2 Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-28 01:06:40 +00:00
CodeDevMLH
669933d270 Auto-Update MediaBar Enhanced to v1.2.3.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-28 01:05:53 +00:00
CodeDevMLH
053f0ccfa7 Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-28 00:46:16 +00:00
CodeDevMLH
60e998fc7f Auto-Update MediaBar Enhanced to v1.2.3.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-28 00:45:27 +00:00
CodeDevMLH
3aa631198a Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-28 00:31:33 +00:00
CodeDevMLH
b1876d655e Auto-Update MediaBar Enhanced to v1.2.3.2
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-01-28 00:30:43 +00:00
CodeDevMLH
9a9f89c1fc Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-28 00:18:24 +00:00
CodeDevMLH
2fb41f6442 Auto-Update MediaBar Enhanced to v1.2.3.1
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-01-28 00:17:35 +00:00
CodeDevMLH
4ab949e6d7 Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-27 23:55:34 +00:00
CodeDevMLH
7d1024c917 Auto-Update MediaBar Enhanced to v1.2.3.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-27 23:54:49 +00:00
CodeDevMLH
c2e3d55110 Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-24 22:54:52 +00:00
CodeDevMLH
c6503a90bb Auto-Update MediaBar Enhanced to v1.2.2.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 53s
2026-01-24 22:54:01 +00:00
CodeDevMLH
b70787d5ec Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-22 23:51:52 +00:00
CodeDevMLH
a9eb8113a6 Auto-Update MediaBar Enhanced to v1.2.1.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-22 23:51:03 +00:00
CodeDevMLH
aaf15d8934 Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-21 23:12:11 +00:00
CodeDevMLH
ec298ebde0 bump version to 1.5.1.0 in project file
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 53s
2026-01-22 00:11:19 +01:00
CodeDevMLH
bb108d0f49 Update manifest.json for release v1.5.1.0 [skip ci] 2026-01-21 22:53:15 +00:00
MLH
f271e1715d Merge pull request 'fix: snowfall effect sometimes not scaling on window resize, which leads to clustering and rain effect of snowflakes' (#1) from dev into main
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 57s
Reviewed-on: #1
2026-01-21 23:52:18 +01:00
CodeDevMLH
bd0e2779e5 fix: snowfall effect sometimes not scaling on window resize, which leads to clustering and rain effect of snowflakes
All checks were successful
🏗️ Build Plugin / build (push) Successful in 53s
🏗️ Build Plugin / build (pull_request) Successful in 58s
2026-01-21 23:51:23 +01:00
CodeDevMLH
53a1682868 Enhance descriptions and overviews in manifest.json for Seasonals and Media Bar Enhanced plugins [skip ci] 2026-01-09 00:32:40 +01:00
CodeDevMLH
a7df2fd832 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-08 23:31:54 +00:00
CodeDevMLH
c56cde860b Auto-Update MediaBar Enhanced to v1.2.0.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-08 23:31:04 +00:00
CodeDevMLH
59211e27c6 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-08 23:15:57 +00:00
CodeDevMLH
a2b1179353 Auto-Update MediaBar Enhanced to v1.2.0.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 47s
2026-01-08 23:15:12 +00:00
CodeDevMLH
c7f34ec92f Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-08 22:16:58 +00:00
CodeDevMLH
4c011cf560 Auto-Update MediaBar Enhanced to v1.2.0.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 48s
2026-01-08 22:16:11 +00:00
CodeDevMLH
e5f78c711d Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-08 15:27:46 +00:00
CodeDevMLH
98a536315b Auto-Update MediaBar Enhanced to v1.1.2.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-08 15:27:00 +00:00
CodeDevMLH
01343848e3 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-08 14:55:53 +00:00
CodeDevMLH
113e7dd0f7 Auto-Update MediaBar Enhanced to v1.1.1.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-08 14:55:04 +00:00
CodeDevMLH
1bc4176771 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-08 02:16:44 +00:00
CodeDevMLH
b091e5592d Auto-Update MediaBar Enhanced to v1.1.0.0
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-08 02:15:57 +00:00
CodeDevMLH
cb2d86340e Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 23:34:26 +00:00
CodeDevMLH
57a92e94de Remove build.yaml configuration file for Seasonals plugin
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 57s
2026-01-07 00:33:36 +01:00
CodeDevMLH
30bc8bef39 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 23:27:26 +00:00
CodeDevMLH
2d237063a3 Auto-Update MediaBar Enhanced to v1.0.0.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 54s
2026-01-06 23:26:36 +00:00
CodeDevMLH
049a5075b5 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 23:18:28 +00:00
CodeDevMLH
cb2e9c4b07 Auto-Update MediaBar Enhanced to v1.0.0.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-06 23:17:39 +00:00
CodeDevMLH
5a39f85082 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 23:13:12 +00:00
CodeDevMLH
b863d201b9 Auto-Update MediaBar Enhanced to v1.0.0.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-06 23:12:24 +00:00
CodeDevMLH
78b50b41c2 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 23:11:24 +00:00
CodeDevMLH
0ba1545fd6 test
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 49s
2026-01-07 00:10:33 +01:00
CodeDevMLH
16c4e0f29b fix link 2026-01-07 00:09:41 +01:00
CodeDevMLH
3581b8cbb2 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 22:57:27 +00:00
CodeDevMLH
7184c93f6f Auto-Update MediaBar Enhanced to v1.0.0.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-06 22:56:39 +00:00
CodeDevMLH
0969f0238f Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 22:45:32 +00:00
CodeDevMLH
12f868d3f9 test ..
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-01-06 23:44:42 +01:00
CodeDevMLH
dc7be56807 Merge branch 'main' of ssh://git.mahom03-spacecloud.de:44322/CodeDevMLH/Jellyfin-Seasonals-Plugin 2026-01-06 23:41:57 +01:00
CodeDevMLH
cb60690e6b fix log name 2026-01-06 23:41:55 +01:00
CodeDevMLH
e0397bb2e8 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 22:40:15 +00:00
CodeDevMLH
822bcafd11 Auto-Update MediaBar Enhanced to v1.0.0.3
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 50s
2026-01-06 22:39:29 +00:00
CodeDevMLH
429d96c816 Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 22:37:52 +00:00
CodeDevMLH
e948055f0f test
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 51s
2026-01-06 23:37:01 +01:00
CodeDevMLH
5129d46163 fix remote repo 2026-01-06 23:36:39 +01:00
CodeDevMLH
660f7142ef Update manifest.json for release v1.5.0.0 [skip ci] 2026-01-06 22:33:07 +00:00
CodeDevMLH
9f657588d8 fix changelog
All checks were successful
Auto Release Plugin / build-and-release (push) Successful in 52s
2026-01-06 23:32:16 +01:00
CodeDevMLH
0457f1a764 Merge branch 'main' of ssh://git.mahom03-spacecloud.de:44322/CodeDevMLH/Jellyfin-Seasonals-Plugin 2026-01-06 23:30:37 +01:00
CodeDevMLH
f196c6c296 fix url 2026-01-06 23:30:36 +01:00
20 changed files with 2092 additions and 276 deletions

View File

@@ -40,6 +40,11 @@ jobs:
echo "Detected Version: $VERSION"
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
echo "CHANGELOG<<EOF" >> $GITHUB_ENV
@@ -71,7 +76,7 @@ jobs:
REPO_OWNER="${{ github.repository_owner }}"
REPO_NAME="${{ github.event.repository.name }}"
VERSION="${{ env.VERSION }}"
DOWNLOAD_URL="https://git.mahom03-spacecloud.de/${{ github.repository }}/releases/download/v$VERSION/Jellyfin.Plugin.Seasonals.zip"
DOWNLOAD_URL="https://git.mahom03-spacecloud.de/$REPO_OWNER/$REPO_NAME/releases/download/v$VERSION/Jellyfin.Plugin.Seasonals.zip"
echo "Updating manifest.json with:"
echo "Hash: ${{ env.ZIP_HASH }}"
@@ -115,11 +120,14 @@ jobs:
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/${{ github.repository }}/releases/download/v$VERSION/Jellyfin.Plugin.Seasonals.zip"
DOWNLOAD_URL="https://git.mahom03-spacecloud.de/$REPO_OWNER/$REPO_NAME/releases/download/v$VERSION/Jellyfin.Plugin.Seasonals.zip"
# 2. Get info from env
PLUGIN_GUID="${{ env.PLUGIN_GUID }}"
@@ -171,7 +179,7 @@ jobs:
# 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 commit -m "Auto-Update Seasonals to v${{ env.VERSION }}"
git push
else
echo "No changes to central manifest."

View File

@@ -39,6 +39,11 @@ jobs:
echo "Detected Version: $VERSION"
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
echo "CHANGELOG<<EOF" >> $GITHUB_ENV
@@ -113,6 +118,9 @@ jobs:
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 }}"
@@ -169,7 +177,7 @@ jobs:
# 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 commit -m "Auto-Update Seasonals to v${{ env.VERSION }}"
git push
else
echo "No changes to central manifest."

1
.gitignore vendored
View File

@@ -5,4 +5,5 @@ obj/
artifacts
test-site.html
test-site-new.html
RELEASE_GUIDE.md

View File

@@ -62,6 +62,7 @@ public class SeasonalsController : ControllerBase
if (path.EndsWith(".png", StringComparison.OrdinalIgnoreCase)) return "image/png";
if (path.EndsWith(".jpg", StringComparison.OrdinalIgnoreCase)) return "image/jpeg";
if (path.EndsWith(".gif", StringComparison.OrdinalIgnoreCase)) return "image/gif";
if (path.EndsWith(".svg", StringComparison.OrdinalIgnoreCase)) return "image/svg+xml";
return "application/octet-stream";
}
}

View File

@@ -15,6 +15,7 @@ public class PluginConfiguration : BasePluginConfiguration
IsEnabled = true;
SelectedSeason = "none";
AutomateSeasonSelection = true;
EnableClientSideToggle = true;
Autumn = new AutumnOptions();
Snowflakes = new SnowflakesOptions();
@@ -43,6 +44,14 @@ public class PluginConfiguration : BasePluginConfiguration
/// </summary>
public bool AutomateSeasonSelection { get; set; }
/// <summary>
/// Gets or sets a value indicating whether to enable client-side toggle for users.
/// </summary>
public bool EnableClientSideToggle { get; set; }
/// <summary>
/// Gets or sets the Seasonals options.
/// </summary>
public AutumnOptions Autumn { get; set; }
public SnowflakesOptions Snowflakes { get; set; }
public SnowfallOptions Snowfall { get; set; }

View File

@@ -6,19 +6,19 @@
</head>
<body>
<div id="SeasonalsConfigPage" data-role="page" class="page type-interior pluginConfigurationPage" data-require="emby-input,emby-button,emby-select,emby-checkbox">
<style>
select option:disabled {
color: #a3a3a3 !important;
}
</style>
<style>
select option:disabled {
color: #a3a3a3 !important;
}
</style>
<div data-role="content">
<div class="content-primary">
<div class="sectionTitleContainer">
<h2 class="sectionTitle">Seasonals</h2>
<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-Seasonals">
<i class="md-icon button-icon button-icon-left secondaryText"></i>
<span>Help</span>
<span>${Help}</span>
</a>
</div>
<hr style="max-width: 800px; margin: 1em 0;">
@@ -40,7 +40,7 @@
</div>
<div class="selectContainer">
<label class="selectLabel" for="SelectedSeason">Selected Season</label>
<select is="emby-select" id="SelectedSeason" name="SelectedSeason" class="emby-select-withcolor emby-select">
<select id="SelectedSeason" name="SelectedSeason" class="emby-select" style="width: 100%; padding: 0.5em; background-color: #333; border: 1px solid #444; color: #fff; border-radius: 4px;">
<option value="none">None</option>
<option value="snowflakes">Snowflakes</option>
<option value="snowfall">Snowfall</option>
@@ -52,17 +52,26 @@
<option value="santa">Santa</option>
<option value="autumn">Autumn</option>
<option value="easter">Easter</option>
<option value="summer" disabled>Summer (not implemented yet, no idea for a theme. Please commit ideas in a issue)</option>
<option value="spring" disabled>Spring (not implemented yet, no idea for a theme. Please commit ideas in a issue)</option>
<option value="oktoberfest" disabled>Oktoberfest (not implemented yet, no idea for a theme. Please commit ideas in a issue)</option>
<option value="carnival" disabled>Carnival (not implemented yet, no idea for a theme. Please commit ideas in a issue)</option>
<option value="championships" disabled>European/World Championships (not implemented yet, no idea for a theme. Please commit ideas in a issue)</option>
<option value="patrick" disabled>St. Patrick's Day (not implemented yet, no idea for a theme. Please commit ideas in a issue)</option>
<option value="thanksgiving" disabled>Thanksgiving (not implemented yet, no idea for a theme. Please commit ideas in a issue)</option>
<option value="pride" disabled>Pride (not implemented yet, no idea for a theme. Please commit ideas in a issue)</option>
<option value="summer" disabled>Summer (not implemented yet. Please commit ideas in a issue or PR)</option>
<option value="spring" disabled>Spring (not implemented yet. Please commit ideas in a issue or PR)</option>
<option value="oktoberfest" disabled>Oktoberfest (not implemented yet. Please commit ideas in a issue or PR)</option>
<option value="carnival" disabled>Carnival (not implemented yet. Please commit ideas in a issue or PR)</option>
<option value="championships" disabled>European/World Championships (not implemented yet. Please commit ideas in a issue or PR)</option>
<option value="patrick" disabled>St. Patrick's Day (not implemented yet. Please commit ideas in a issue or PR)</option>
<option value="thanksgiving" disabled>Thanksgiving (not implemented yet. Please commit ideas in a issue or PR)</option>
<option value="pride" disabled>Pride (not implemented yet. Please commit ideas in a issue or PR)</option>
</select>
<div class="fieldDescription">The season to display if automation is disabled.</div>
</div>
<div class="checkboxContainer checkboxContainer-withDescription">
<label class="emby-checkbox-label">
<input id="EnableClientSideToggle" name="EnableClientSideToggle" type="checkbox"
is="emby-checkbox" />
<span>Allow Client-Side Toggle</span>
</label>
<div class="fieldDescription">If enabled, users will see a seasonals icon in the header to toggle
seasonals for their browser.</div>
</div>
<br>
<details>
@@ -530,6 +539,7 @@
document.querySelector('#IsEnabled').checked = config.IsEnabled;
document.querySelector('#SelectedSeason').value = config.SelectedSeason;
document.querySelector('#AutomateSeasonSelection').checked = config.AutomateSeasonSelection;
document.querySelector('#EnableClientSideToggle').checked = config.EnableClientSideToggle !== undefined ? config.EnableClientSideToggle : true;
// Advanced Config
// Autumn
@@ -621,98 +631,100 @@
document.querySelector('#SeasonalsConfigForm')
.addEventListener('submit', function(e) {
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(SeasonalsConfig.pluginUniqueId).then(function (config) {
config.IsEnabled = document.querySelector('#IsEnabled').checked;
config.SelectedSeason = document.querySelector('#SelectedSeason').value;
config.AutomateSeasonSelection = document.querySelector('#AutomateSeasonSelection').checked;
Dashboard.showLoadingMsg();
ApiClient.getPluginConfiguration(SeasonalsConfig.pluginUniqueId).then(function (config) {
config.IsEnabled = document.querySelector('#IsEnabled').checked;
config.SelectedSeason = document.querySelector('#SelectedSeason').value;
config.AutomateSeasonSelection = document.querySelector('#AutomateSeasonSelection').checked;
config.EnableClientSideToggle = document.querySelector('#EnableClientSideToggle').checked;
// Advanced Config
// Autumn
config.Autumn.EnableAutumn = document.querySelector('#EnableAutumn').checked;
config.Autumn.LeafCount = parseInt(document.querySelector('#AutumnLeafCount').value);
config.Autumn.EnableRandomLeaves = document.querySelector('#EnableRandomLeaves').checked;
config.Autumn.EnableRandomLeavesMobile = document.querySelector('#EnableRandomLeavesMobile').checked;
config.Autumn.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationAutumn').checked;
config.Autumn.EnableRotation = document.querySelector('#EnableRotation').checked;
// Snowflakes
config.Snowflakes.SnowflakeCount = parseInt(document.querySelector('#SnowflakesCount').value);
config.Snowflakes.EnableSnowflakes = document.querySelector('#EnableSnowflakes').checked;
config.Snowflakes.EnableRandomSnowflakes = document.querySelector('#EnableRandomSnowflakes').checked;
config.Snowflakes.EnableRandomSnowflakesMobile = document.querySelector('#EnableRandomSnowflakesMobile').checked;
config.Snowflakes.EnableColoredSnowflakes = document.querySelector('#EnableColoredSnowflakes').checked;
config.Snowflakes.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationSnowflakes').checked;
// Advanced Config
// Autumn
config.Autumn.EnableAutumn = document.querySelector('#EnableAutumn').checked;
config.Autumn.LeafCount = parseInt(document.querySelector('#AutumnLeafCount').value);
config.Autumn.EnableRandomLeaves = document.querySelector('#EnableRandomLeaves').checked;
config.Autumn.EnableRandomLeavesMobile = document.querySelector('#EnableRandomLeavesMobile').checked;
config.Autumn.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationAutumn').checked;
config.Autumn.EnableRotation = document.querySelector('#EnableRotation').checked;
// Snowfall
config.Snowfall.EnableSnowfall = document.querySelector('#EnableSnowfall').checked;
config.Snowfall.SnowflakesCount = parseInt(document.querySelector('#SnowfallCount').value);
config.Snowfall.SnowflakesCountMobile = parseInt(document.querySelector('#SnowfallCountMobile').value);
config.Snowfall.Speed = parseFloat(document.querySelector('#SnowfallSpeed').value);
// Snowflakes
config.Snowflakes.SnowflakeCount = parseInt(document.querySelector('#SnowflakesCount').value);
config.Snowflakes.EnableSnowflakes = document.querySelector('#EnableSnowflakes').checked;
config.Snowflakes.EnableRandomSnowflakes = document.querySelector('#EnableRandomSnowflakes').checked;
config.Snowflakes.EnableRandomSnowflakesMobile = document.querySelector('#EnableRandomSnowflakesMobile').checked;
config.Snowflakes.EnableColoredSnowflakes = document.querySelector('#EnableColoredSnowflakes').checked;
config.Snowflakes.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationSnowflakes').checked;
// Snowstorm
config.Snowstorm.EnableSnowstorm = document.querySelector('#EnableSnowstorm').checked;
config.Snowstorm.SnowflakesCount = parseInt(document.querySelector('#SnowstormCount').value);
config.Snowstorm.SnowflakesCountMobile = parseInt(document.querySelector('#SnowstormCountMobile').value);
config.Snowstorm.Speed = parseFloat(document.querySelector('#SnowstormSpeed').value);
config.Snowstorm.HorizontalWind = parseFloat(document.querySelector('#SnowstormHorizontalWind').value);
config.Snowstorm.VerticalVariation = parseFloat(document.querySelector('#SnowstormVerticalVariation').value);
// Snowfall
config.Snowfall.EnableSnowfall = document.querySelector('#EnableSnowfall').checked;
config.Snowfall.SnowflakesCount = parseInt(document.querySelector('#SnowfallCount').value);
config.Snowfall.SnowflakesCountMobile = parseInt(document.querySelector('#SnowfallCountMobile').value);
config.Snowfall.Speed = parseFloat(document.querySelector('#SnowfallSpeed').value);
// Fireworks
config.Fireworks.EnableFireworks = document.querySelector('#EnableFireworks').checked;
config.Fireworks.ParticleCount = parseInt(document.querySelector('#FireworksParticles').value);
config.Fireworks.LaunchInterval = parseInt(document.querySelector('#FireworksInterval').value);
config.Fireworks.ScrollFireworks = document.querySelector('#ScrollFireworks').checked;
config.Fireworks.MinFireworks = parseInt(document.querySelector('#MinFireworks').value);
config.Fireworks.MaxFireworks = parseInt(document.querySelector('#MaxFireworks').value);
// Snowstorm
config.Snowstorm.EnableSnowstorm = document.querySelector('#EnableSnowstorm').checked;
config.Snowstorm.SnowflakesCount = parseInt(document.querySelector('#SnowstormCount').value);
config.Snowstorm.SnowflakesCountMobile = parseInt(document.querySelector('#SnowstormCountMobile').value);
config.Snowstorm.Speed = parseFloat(document.querySelector('#SnowstormSpeed').value);
config.Snowstorm.HorizontalWind = parseFloat(document.querySelector('#SnowstormHorizontalWind').value);
config.Snowstorm.VerticalVariation = parseFloat(document.querySelector('#SnowstormVerticalVariation').value);
// Halloween
config.Halloween.EnableHalloween = document.querySelector('#EnableHalloween').checked;
config.Halloween.SymbolCount = parseInt(document.querySelector('#HalloweenCount').value);
config.Halloween.EnableRandomSymbols = document.querySelector('#EnableRandomHalloween').checked;
config.Halloween.EnableRandomSymbolsMobile = document.querySelector('#EnableRandomHalloweenMobile').checked;
config.Halloween.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationHalloween').checked;
// Fireworks
config.Fireworks.EnableFireworks = document.querySelector('#EnableFireworks').checked;
config.Fireworks.ParticleCount = parseInt(document.querySelector('#FireworksParticles').value);
config.Fireworks.LaunchInterval = parseInt(document.querySelector('#FireworksInterval').value);
config.Fireworks.ScrollFireworks = document.querySelector('#ScrollFireworks').checked;
config.Fireworks.MinFireworks = parseInt(document.querySelector('#MinFireworks').value);
config.Fireworks.MaxFireworks = parseInt(document.querySelector('#MaxFireworks').value);
// Hearts
config.Hearts.EnableHearts = document.querySelector('#EnableHearts').checked;
config.Hearts.SymbolCount = parseInt(document.querySelector('#HeartsCount').value);
config.Hearts.EnableRandomSymbols = document.querySelector('#EnableRandomHearts').checked;
config.Hearts.EnableRandomSymbolsMobile = document.querySelector('#EnableRandomHeartsMobile').checked;
config.Hearts.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationHearts').checked;
// Halloween
config.Halloween.EnableHalloween = document.querySelector('#EnableHalloween').checked;
config.Halloween.SymbolCount = parseInt(document.querySelector('#HalloweenCount').value);
config.Halloween.EnableRandomSymbols = document.querySelector('#EnableRandomHalloween').checked;
config.Halloween.EnableRandomSymbolsMobile = document.querySelector('#EnableRandomHalloweenMobile').checked;
config.Halloween.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationHalloween').checked;
// Christmas
config.Christmas.EnableChristmas = document.querySelector('#EnableChristmas').checked;
config.Christmas.SymbolCount = parseInt(document.querySelector('#ChristmasCount').value);
config.Christmas.EnableRandomChristmas = document.querySelector('#EnableRandomChristmas').checked;
config.Christmas.EnableRandomChristmasMobile = document.querySelector('#EnableRandomChristmasMobile').checked;
config.Christmas.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationChristmas').checked;
// Hearts
config.Hearts.EnableHearts = document.querySelector('#EnableHearts').checked;
config.Hearts.SymbolCount = parseInt(document.querySelector('#HeartsCount').value);
config.Hearts.EnableRandomSymbols = document.querySelector('#EnableRandomHearts').checked;
config.Hearts.EnableRandomSymbolsMobile = document.querySelector('#EnableRandomHeartsMobile').checked;
config.Hearts.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationHearts').checked;
// Santa
config.Santa.EnableSanta = document.querySelector('#EnableSanta').checked;
config.Santa.SnowflakesCount = parseInt(document.querySelector('#SantaSnowflakes').value);
config.Santa.SnowflakesCountMobile = parseInt(document.querySelector('#SantaSnowflakesMobile').value);
config.Santa.SantaSpeed = parseFloat(document.querySelector('#SantaSpeed').value);
config.Santa.SantaSpeedMobile = parseFloat(document.querySelector('#SantaSpeedMobile').value);
config.Santa.SnowFallSpeed = parseFloat(document.querySelector('#SantaSnowFallSpeed').value);
config.Santa.MaxSantaRestTime = parseFloat(document.querySelector('#MaxSantaRestTime').value);
config.Santa.MinSantaRestTime = parseFloat(document.querySelector('#MinSantaRestTime').value);
config.Santa.MaxPresentFallSpeed = parseFloat(document.querySelector('#MaxPresentFallSpeed').value);
config.Santa.MinPresentFallSpeed = parseFloat(document.querySelector('#MinPresentFallSpeed').value);
// Christmas
config.Christmas.EnableChristmas = document.querySelector('#EnableChristmas').checked;
config.Christmas.SymbolCount = parseInt(document.querySelector('#ChristmasCount').value);
config.Christmas.EnableRandomChristmas = document.querySelector('#EnableRandomChristmas').checked;
config.Christmas.EnableRandomChristmasMobile = document.querySelector('#EnableRandomChristmasMobile').checked;
config.Christmas.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationChristmas').checked;
// Easter
config.Easter.EnableEaster = document.querySelector('#EnableEaster').checked;
config.Easter.EggCount = parseInt(document.querySelector('#EasterEggCount').value);
config.Easter.EnableRandomEaster = document.querySelector('#EnableRandomEaster').checked;
config.Easter.EnableRandomEasterMobile = document.querySelector('#EnableRandomEasterMobile').checked;
config.Easter.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationEaster').checked;
config.Easter.EnableBunny = document.querySelector('#EasterBunny').checked;
config.Easter.BunnyDuration = parseInt(document.querySelector('#BunnyDuration').value);
config.Easter.HopHeight = parseInt(document.querySelector('#HopHeight').value);
config.Easter.MinBunnyRestTime = parseInt(document.querySelector('#MinBunnyRestTime').value);
config.Easter.MaxBunnyRestTime = parseInt(document.querySelector('#MaxBunnyRestTime').value);
// Santa
config.Santa.EnableSanta = document.querySelector('#EnableSanta').checked;
config.Santa.SnowflakesCount = parseInt(document.querySelector('#SantaSnowflakes').value);
config.Santa.SnowflakesCountMobile = parseInt(document.querySelector('#SantaSnowflakesMobile').value);
config.Santa.SantaSpeed = parseFloat(document.querySelector('#SantaSpeed').value);
config.Santa.SantaSpeedMobile = parseFloat(document.querySelector('#SantaSpeedMobile').value);
config.Santa.SnowFallSpeed = parseFloat(document.querySelector('#SantaSnowFallSpeed').value);
config.Santa.MaxSantaRestTime = parseFloat(document.querySelector('#MaxSantaRestTime').value);
config.Santa.MinSantaRestTime = parseFloat(document.querySelector('#MinSantaRestTime').value);
config.Santa.MaxPresentFallSpeed = parseFloat(document.querySelector('#MaxPresentFallSpeed').value);
config.Santa.MinPresentFallSpeed = parseFloat(document.querySelector('#MinPresentFallSpeed').value);
ApiClient.updatePluginConfiguration(SeasonalsConfig.pluginUniqueId, config).then(function (result) {
Dashboard.processPluginConfigurationUpdateResult(result);
// Easter
config.Easter.EnableEaster = document.querySelector('#EnableEaster').checked;
config.Easter.EggCount = parseInt(document.querySelector('#EasterEggCount').value);
config.Easter.EnableRandomEaster = document.querySelector('#EnableRandomEaster').checked;
config.Easter.EnableRandomEasterMobile = document.querySelector('#EnableRandomEasterMobile').checked;
config.Easter.EnableDifferentDuration = document.querySelector('#EnableDifferentDurationEaster').checked;
config.Easter.EnableBunny = document.querySelector('#EasterBunny').checked;
config.Easter.BunnyDuration = parseInt(document.querySelector('#BunnyDuration').value);
config.Easter.HopHeight = parseInt(document.querySelector('#HopHeight').value);
config.Easter.MinBunnyRestTime = parseInt(document.querySelector('#MinBunnyRestTime').value);
config.Easter.MaxBunnyRestTime = parseInt(document.querySelector('#MaxBunnyRestTime').value);
ApiClient.updatePluginConfiguration(SeasonalsConfig.pluginUniqueId, config).then(function (result) {
Dashboard.processPluginConfigurationUpdateResult(result);
});
});

View File

@@ -12,7 +12,7 @@
<!-- <TreatWarningsAsErrors>false</TreatWarningsAsErrors> -->
<Title>Jellyfin Seasonals Plugin</Title>
<Authors>CodeDevMLH</Authors>
<Version>1.5.0.0</Version>
<Version>1.6.13.0</Version>
<RepositoryUrl>https://github.com/CodeDevMLH/Jellyfin-Seasonals</RepositoryUrl>
</PropertyGroup>

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 250 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

View File

@@ -60,6 +60,7 @@ observer.observe(document.body, {
attributes: true // observe changes to attributes (e.g. class changes)
});
let resizeObserver; // Observer for resize events
function initializeCanvas() {
if (document.getElementById('snowfallCanvas')) {
@@ -78,8 +79,12 @@ function initializeCanvas() {
container.appendChild(canvas);
ctx = canvas.getContext('2d');
// Initial resize
resizeCanvas(container);
window.addEventListener('resize', () => resizeCanvas(container));
// Initialize ResizeObserver
resizeObserver = new ResizeObserver(() => resizeCanvas(container));
resizeObserver.observe(container);
}
function removeCanvas() {
@@ -96,15 +101,37 @@ function removeCanvas() {
animationFrameIdSanta = null;
console.log('Santa animation frame canceled');
}
// Disconnect ResizeObserver
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
console.log('Canvas removed');
}
}
function resizeCanvas(container) {
if (!canvas) return;
const oldWidth = canvas.width;
const oldHeight = canvas.height;
const rect = container.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
// Scale snowflakes positions if dimensions changed (to avoid clustering)
if (oldWidth > 0 && oldHeight > 0 && snowflakes.length > 0) {
const scaleX = canvas.width / oldWidth;
const scaleY = canvas.height / oldHeight;
snowflakes.forEach(flake => {
flake.x *= scaleX;
flake.y *= scaleY;
});
}
}
function createSnowflakes(container) {

View File

@@ -99,12 +99,21 @@ function determineCurrentTheme() {
return 'none'; // Fallback (nothing)
}
// helper to resolve paths for local testing vs production
function resolvePath(path) {
if (window.location.protocol === 'file:' || window.location.hostname === 'localhost' || window.location.hostname === '127.0.0.1') {
return path.replace('/Seasonals/Resources/', './');
}
return path;
}
// load theme csss
function loadThemeCSS(cssPath) {
if (!cssPath) return;
const link = document.createElement('link');
link.rel = 'stylesheet';
// link.href = resolvePath(cssPath);
link.href = cssPath;
link.onerror = () => {
@@ -121,6 +130,7 @@ function loadThemeJS(jsPath) {
const script = document.createElement('script');
script.src = jsPath;
// script.src = resolvePath(jsPath);
script.defer = true;
script.onerror = () => {
@@ -145,14 +155,24 @@ function updateThemeContainer(containerClass) {
console.log(`Seasonals-Container class updated to "${containerClass}".`);
}
function removeSelf() {
const script = document.currentScript;
if (script) script.parentNode.removeChild(script);
console.log('External script removed:', script);
}
// function removeSelf() {
// const script = document.currentScript;
// if (script) script.parentNode.removeChild(script);
// console.log('External script removed:', script);
// }
// initialize theme
async function initializeTheme() {
// Check local user preference
const isEnabled = getSavedSetting('seasonals-enabled', 'true') === 'true';
if (!isEnabled) {
console.log('Seasonals disabled by user preference.');
return;
}
const forcedTheme = getSavedSetting('seasonals-theme', 'auto');
let automateThemeSelection = true;
let defaultTheme = 'none';
@@ -172,7 +192,11 @@ async function initializeTheme() {
}
let currentTheme;
if (automateThemeSelection === false) {
if (forcedTheme !== 'auto') {
currentTheme = forcedTheme;
console.log(`User forced theme: ${currentTheme}`);
} else if (automateThemeSelection === false) {
currentTheme = defaultTheme;
} else {
currentTheme = determineCurrentTheme();
@@ -182,7 +206,6 @@ async function initializeTheme() {
if (!currentTheme || currentTheme === 'none') {
console.log('No theme selected.');
removeSelf();
return;
}
@@ -198,9 +221,154 @@ async function initializeTheme() {
if (theme.js) loadThemeJS(theme.js);
console.log(`Theme "${currentTheme}" loaded.`);
removeSelf();
}
initializeTheme();
// User UI Seasonal Settings
function getSavedSetting(key, defaultValue) {
const value = localStorage.getItem(key);
return value !== null ? value : defaultValue;
}
function setSavedSetting(key, value) {
localStorage.setItem(key, value);
}
function createSettingsIcon() {
const button = document.createElement('button');
button.type = 'button';
button.className = 'paper-icon-button-light headerButton seasonal-settings-button';
button.title = 'Seasonal Settings';
// button.innerHTML = '<span class="material-icons">ac_unit</span>';
button.innerHTML = '<img src="/Seasonals/Resources/assets/logo_SW.svg" style="width: 24px; height: 24px; vertical-align: middle;">';
button.style.verticalAlign = 'middle';
button.addEventListener('click', (e) => {
e.stopPropagation();
toggleSettingsPopup(button);
});
return button;
}
function createSettingsPopup(anchorElement) {
const existing = document.querySelector('.seasonal-settings-popup');
if (existing) existing.remove();
const popup = document.createElement('div');
popup.className = 'seasonal-settings-popup dialog';
Object.assign(popup.style, {
position: 'fixed',
zIndex: '10000',
backgroundColor: '#202020',
padding: '1em',
borderRadius: '0.3em',
boxShadow: '0 0 20px rgba(0,0,0,0.5)',
minWidth: '200px',
color: '#fff',
maxWidth: '250px'
});
const rect = anchorElement.getBoundingClientRect();
let rightPos = window.innerWidth - rect.right;
if (window.innerWidth < 450 || (window.innerWidth - rightPos) < 260) {
popup.style.right = '1rem';
popup.style.left = 'auto';
} else {
popup.style.right = `${rightPos}px`;
popup.style.left = 'auto';
}
popup.style.top = `${rect.bottom + 10}px`;
popup.innerHTML = `
<div class="checkboxContainer checkboxContainer-withDescription" style="margin-bottom: 0.5em;">
<label class="emby-checkbox-label">
<input id="seasonal-enable-toggle" type="checkbox" is="emby-checkbox" class="emby-checkbox" />
<span class="checkboxLabel">Enable Seasonals</span>
</label>
</div>
<div class="selectContainer" style="margin-bottom: 0.5em;">
<label class="selectLabel" for="seasonal-theme-select" style="margin-bottom: 0.5em; display: block; color: inherit;">Force Theme</label>
<select id="seasonal-theme-select" class="emby-select" style="width: 100%; padding: 0.5em; background-color: #333; border: 1px solid #444; color: #fff; border-radius: 4px;">
<option value="auto">Server-Side</option>
</select>
</div>
`;
// Populate Select Options
const themeSelect = popup.querySelector('#seasonal-theme-select');
Object.keys(themeConfigs).forEach(key => {
if (key === 'none') return;
const option = document.createElement('option');
option.value = key;
// Capitalize first letter
option.textContent = key.charAt(0).toUpperCase() + key.slice(1);
themeSelect.appendChild(option);
});
// Set Initial Values
const enabledCheckbox = popup.querySelector('#seasonal-enable-toggle');
enabledCheckbox.checked = getSavedSetting('seasonals-enabled', 'true') === 'true';
themeSelect.value = getSavedSetting('seasonals-theme', 'auto');
enabledCheckbox.addEventListener('change', (e) => {
setSavedSetting('seasonals-enabled', e.target.checked);
location.reload();
});
themeSelect.addEventListener('change', (e) => {
setSavedSetting('seasonals-theme', e.target.value);
location.reload();
});
const closeHandler = (e) => {
if (!popup.contains(e.target) && e.target !== anchorElement && !anchorElement.contains(e.target)) {
popup.remove();
document.removeEventListener('click', closeHandler);
}
};
setTimeout(() => document.addEventListener('click', closeHandler), 0);
document.body.appendChild(popup);
}
function toggleSettingsPopup(anchorElement) {
const existing = document.querySelector('.seasonal-settings-popup');
if (existing) {
existing.remove();
} else {
createSettingsPopup(anchorElement);
}
}
function injectSettingsIcon() {
const observer = new MutationObserver((mutations, obs) => {
// Check if admin has enabled this feature
if (window.SeasonalsPluginConfig && window.SeasonalsPluginConfig.EnableClientSideToggle === false) {
return;
}
const headerRight = document.querySelector('.headerRight');
if (headerRight && !document.querySelector('.seasonal-settings-button')) {
const icon = createSettingsIcon();
headerRight.prepend(icon);
// obs.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true
});
}
injectSettingsIcon();

View File

@@ -55,6 +55,7 @@ observer.observe(document.body, {
attributes: true // observe changes to attributes (e.g. class changes)
});
let resizeObserver; // Observer for resize events
function initializeCanvas() {
if (document.getElementById('snowfallCanvas')) {
@@ -73,8 +74,12 @@ function initializeCanvas() {
container.appendChild(canvas);
ctx = canvas.getContext('2d');
// Initial resize
resizeCanvas(container);
window.addEventListener('resize', () => resizeCanvas(container));
// Initialize ResizeObserver
resizeObserver = new ResizeObserver(() => resizeCanvas(container));
resizeObserver.observe(container);
}
function removeCanvas() {
@@ -86,15 +91,37 @@ function removeCanvas() {
animationFrameId = null;
console.log('Animation frame canceled');
}
// Disconnect ResizeObserver
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
console.log('Canvas removed');
}
}
function resizeCanvas(container) {
if (!canvas) return;
const oldWidth = canvas.width;
const oldHeight = canvas.height;
const rect = container.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
// Scale snowflakes positions if dimensions changed (to avoid clustering)
if (oldWidth > 0 && oldHeight > 0 && snowflakes.length > 0) {
const scaleX = canvas.width / oldWidth;
const scaleY = canvas.height / oldHeight;
snowflakes.forEach(flake => {
flake.x *= scaleX;
flake.y *= scaleY;
});
}
}
function createSnowflakes(container) {

View File

@@ -57,6 +57,7 @@ observer.observe(document.body, {
attributes: true // observe changes to attributes (e.g. class changes)
});
let resizeObserver; // Observer for resize events
function initializeCanvas() {
if (document.getElementById('snowfallCanvas')) {
@@ -75,8 +76,12 @@ function initializeCanvas() {
container.appendChild(canvas);
ctx = canvas.getContext('2d');
// Initial resize
resizeCanvas(container);
window.addEventListener('resize', () => resizeCanvas(container));
// Initialize ResizeObserver
resizeObserver = new ResizeObserver(() => resizeCanvas(container));
resizeObserver.observe(container);
}
function removeCanvas() {
@@ -88,15 +93,37 @@ function removeCanvas() {
animationFrameId = null;
console.log('Animation frame canceled');
}
// Disconnect ResizeObserver
if (resizeObserver) {
resizeObserver.disconnect();
resizeObserver = null;
}
console.log('Canvas removed');
}
}
function resizeCanvas(container) {
if (!canvas) return;
const oldWidth = canvas.width;
const oldHeight = canvas.height;
const rect = container.getBoundingClientRect();
canvas.width = rect.width;
canvas.height = rect.height;
// Scale snowflakes positions if dimensions changed (to avoid clustering)
if (oldWidth > 0 && oldHeight > 0 && snowflakes.length > 0) {
const scaleX = canvas.width / oldWidth;
const scaleY = canvas.height / oldHeight;
snowflakes.forEach(flake => {
flake.x *= scaleX;
flake.y *= scaleY;
});
}
}
function createSnowflakes(container) {

View File

@@ -0,0 +1,79 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Seasonals Test Display</title>
<link rel="stylesheet" href="snowfall.css">
<style>
body {
background-color: black;
color: white;
margin: 0;
font-family: sans-serif;
}
/* Mock Jellyfin Header */
.skinHeader {
background-color: #101010;
height: 60px;
display: flex;
align-items: center;
padding: 0 1em;
border-bottom: 1px solid #333;
}
.headerRight {
margin-left: auto;
display: flex;
align-items: center;
}
.paper-icon-button-light {
background: none;
border: none;
color: white;
cursor: pointer;
padding: 10px;
}
.material-icons {
font-family: 'Material Icons';
/* Placeholder if not loaded */
font-weight: normal;
font-style: normal;
font-size: 24px;
display: inline-block;
line-height: 1;
text-transform: none;
letter-spacing: normal;
word-wrap: normal;
white-space: nowrap;
direction: ltr;
}
</style>
<!-- Load Material Icons for the snowflake -->
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
</head>
<body>
<!-- Mock Header Structure -->
<div class="skinHeader">
<div class="skinHeader-content">
<span>Jellyfin Mock Header</span>
</div>
<div class="headerRight">
<button class="paper-icon-button-light">
<span class="material-icons">person</span>
</button>
</div>
</div>
<div class="seasonals-container"></div>
<!-- Load the main script -->
<script src="seasonals.js"></script>
</body>
</html>

188
README.md
View File

@@ -13,20 +13,17 @@ This plugin is based on my manual mod (see the [legacy branch](https://github.co
- [Table of Contents](#table-of-contents)
- [Features](#features)
- [Overview](#overview)
- [Ideas for additional seasonals](#ideas-for-additional-seasonals)
- [Installation](#installation)
- [Client Compatibility](#client-compatibility)
- [Configuration](#configuration)
- [Automatic Theme Selection](#automatic-theme-selection)
- [Theme Settings](#theme-settings)
- [Build The Plugin By Yourself](#build-the-plugin-by-yourself)
- [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)
- [Legacy Manual Installation](#legacy-manual-installation)
- [Installation](#installation-1)
- [Usage](#usage)
- [Additional Directory: Separate Single Seasonals](#additional-directory-separate-single-seasonals)
---
@@ -34,39 +31,83 @@ This plugin is based on my manual mod (see the [legacy branch](https://github.co
- **Automatic Theme Selection**: Dynamically updates the theme based on the date (e.g., snowflakes in December, fireworks for new year's eve).
- **Easy Integration**: No manual file editing required. The plugin injects everything automatically.
- **Configuration UI**: Configure settings directly in the Jellyfin Dashboard (very basic for now, needs some work in the future).
- **Configuration UI**: Configure settings directly in the Jellyfin Dashboard.
<details>
<summary>Have a look:</summary>
<img width="852" height="782" alt="Admin-Settings" src="https://github.com/user-attachments/assets/03d04ea8-7dd9-418e-88f8-9ae2937c06bb" />
</details>
- **User Toggle**: Optionally allow users to enable/disable seasonal effects from their client.
<details>
<summary>Have a look:</summary>
<img width="467" height="263" alt="Client-Settings" src="https://github.com/user-attachments/assets/a8dfc90a-16c8-409c-9133-4139f6527b0b" />
</details>
## Overview
Click on the following themes to expand them and see the theme in action:
<details>
<summary>Easter</summary>
**Easter**
![easter](https://github.com/user-attachments/assets/63665099-5c3c-4209-be6e-dda3686b2a49)
</details>
<details>
<summary>Autumn</summary>
**Autumn**
![autumn](https://github.com/user-attachments/assets/df27d61c-d2d6-4776-82d7-89bf789a7462)
</details>
<details>
<summary>Santa</summary>
**Santa**
![Santa-10](https://github.com/user-attachments/assets/a69b0aa3-537d-4463-b6bc-166f0a316c37)
</details>
<details>
<summary>Christmas</summary>
**Christmas**
![christmas](https://github.com/user-attachments/assets/e70a425d-866f-4617-bbfe-3c03e3654717)
</details>
<details>
<summary>Fireworks</summary>
**Fireworks**
![fireworks](https://github.com/user-attachments/assets/6c8b629e-b338-4dde-910b-c832aa29d77d)
</details>
<details>
<summary>Halloween</summary>
**Halloween**
![halloween](https://github.com/user-attachments/assets/221a1390-847e-45a4-b8eb-dc5b45d5df5c)
</details>
<details>
<summary>Hearts</summary>
**Hearts**
![hearts](https://github.com/user-attachments/assets/e084cb0c-246e-4234-b6dd-d561923c6c91)
</details>
<details>
<summary>Snowfall</summary>
**Snowfall**
![snowfall](https://github.com/user-attachments/assets/24bfdd84-f354-4129-933c-bb29b4180517)
</details>
<details>
<summary>Snowflakes</summary>
**Snowflakes**
![snowflakes](https://github.com/user-attachments/assets/78f2e925-8cf6-4a0b-8a25-f05594de4efd)
</details>
<details>
<summary>Snowstorm</summary>
**Snowstorm**
![snowstorm](https://github.com/user-attachments/assets/6fd726d2-34d1-4f80-8ed6-2f482155059f)
</details>
## Ideas for additional seasonals
If you have any (specific) ideas for additional seasonals, feel free to open an issue or create a pull request.
## Installation
@@ -135,7 +176,7 @@ If automatic selection is enabled, the following themes are applied based on the
## Theme Settings
Each theme contains additional settings to customize its behavior. Expand the advanced configuration section to configure each theme, adjust parameters like particle count, animation speed etc.
## Build The Plugin By Yourself
## Build the plugin by yourself
If you want to build the plugin yourself:
@@ -203,116 +244,3 @@ volumes:
Feel free to contribute to this project by creating pull requests or reporting issues.
---
## Legacy Manual Installation
<details>
<summary>Click to expand instructions for the old manual installation method (without plugin)</summary>
### Installation
> [!TIP]
> Take a look at [CodeDevMLH/Jellyfin-Mods-Automated-Script](https://github.com/CodeDevMLH/Jellyfin-Mods-Automated-Script)
1. **Add Seasonal Container to `index.html`**
Edit the `index.html` file of your Jellyfin web instance. Add the following code inside the `<body>` tag:
```html
<div class="seasonals-container"></div>
<script src="seasonals/seasonals.js"></script>
```
2. **Deploy Files**
Place the seasonals folder (including seasonals.js, CSS, and additional JavaScript files for each theme [this one](https://github.com/CodeDevMLH/Jellyfin-Seasonals/tree/legacy/seasonals)) inside the Jellyfin web server directory (labeld with "web").
3. **Configure Themes**
Customize the theme-configs.js file to modify or add new themes. The default configuration is shown below:
```javascript
const automateThemeSelection = true; // Set to false to disable automatic theme selection based on current date
const defaultTheme = 'none'; // Default theme if automatic selection is off
const themeConfigs = {
snowflakes: {
css: 'seasonals/snowflakes.css',
js: 'seasonals/snowflakes.js',
containerClass: 'snowflakes'
},
snowfall: {
css: 'seasonals/snowfall.css',
js: 'seasonals/snowfall.js',
containerClass: 'snowfall-container'
},
// more configs...
none: {
containerClass: 'none'
},
};
```
4. **Reload the web interface**
After making these changes, restart your Jellyfin server and/or refresh the web interface (ctrl+F5, sometimes you need to clear the browsers temp files/cache (every time with firefox ;-()) to see the changes.
### Theme Settings
Each theme's JavaScript file contains additional settings to customize its behavior. Here are examples for the `autumn` and `snowflakes` themes:
**Autumn Theme Settings**
```javascript
const leaves = true; // Enable/disable leaves
const randomLeaves = true; // Enable random leaves
const randomLeavesMobile = false; // Enable random leaves on mobile devices
const enableDiffrentDuration = true; // Enable different animation duration for random leaves
const leafCount = 25; // Number of random extra leaves
```
**Snowflakes Theme Settings**
```javascript
const snowflakes = true; // Enable/disable snowflakes
const randomSnowflakes = true; // Enable random snowflakes
const randomSnowflakesMobile = false; // Enable random snowflakes on mobile devices
const enableColoredSnowflakes = true; // Enable colored snowflakes on mobile devices
const enableDiffrentDuration = true; // Enable different animation duration for random snowflakes
const snowflakeCount = 25; // Number of random extra snowflakes
```
### Usage
**Automatic Theme Selection**
By default, the theme is automatically selected based on the date. For example:
Snowfall: January
Hearts: February (Valentine's Day)
Halloween: October
Modify the determineCurrentTheme() function in seasonals.js to adjust date-based logic.
**Manual Theme Selection**
To use a fixed theme, set automateThemeSelection to false in the theme-configs.js file and specify a defaultTheme.
**Custom Themes**
1. Add your CSS and JavaScript files to the seasonals folder.
2. Extend the themeConfigs object with your theme details:
```javascript
myTheme: {
css: 'seasonals/my-theme.css',
js: 'seasonals/my-theme.js',
containerClass: 'my-theme-container',
}
```
### Additional Directory: Separate Single Seasonals
For users who prefer not to use the automatic seasonal theme selection, individual seasonals are available in the `separate single seasonals` folder. Each seasonal theme can be independently loaded and used without relying on the main automatic selection system.
but this requires to the modify of the `index.html` with adding the html in `add_to_index_html`.
To use a single seasonal theme, include its specific CSS and JS files in your `index.html` inside the `<body> </body>` tags provided by `add_to_index_html.html` in the sub-theme-folders as shown below:
```html
<div class="seasonalsname-container"></div>
<script src="separate single seasonals/snowflakes.js"></script>
<link rel="stylesheet" href="separate single seasonals/snowflakes.css">
</details>

View File

@@ -1,15 +0,0 @@
---
name: "Seasonals"
guid: "ef1e863f-cbb0-4e47-9f23-f0cbb1826ad4"
version: "1.3.4.0"
targetAbi: "10.11.0.0"
framework: "net9.0"
overview: "Seasonal effects for Jellyfin"
description: >
Adds seasonal effects like snow, leaves, etc. to the Jellyfin web interface.
category: "General"
owner: "CodeDevMLH"
artifacts:
- "Jellyfin.Plugin.Seasonals.dll"
changelog: >
Added Advanced Configuration UI for customizing individual seasonal effects.

View File

@@ -26,8 +26,11 @@ git merge main
Setzt deine Commits neu auf die Spitze eines anderen Branches. Die Commit-IDs werden dabei neu geschrieben.
```bash
git stash # (optional) Änderungen parken.
git checkout dev
git rebase main
git fetch origin
git rebase origin/main
git stash pop # (optional) Änderungen zurückholen.
```
| Details | |
@@ -38,6 +41,60 @@ git rebase main
---
## **Git: dev zurücksetzen & „main ist Chef“**
Problem
Beim Arbeiten mit Git passiert oft Folgendes:
- `dev` hat Commits, die nicht in `main` sind
- diese Commits brauche ich nicht mehr
- beim `git rebase origin/main` will Git trotzdem mergen oder Konflikte lösen
⚠️ Wichtiges Missverständnis:
Das sind keine lokalen Änderungen, sondern Commits, die auf `dev` existieren.
`git reset --hard origin/dev` entfernt nur lokale, nicht gepushte Commits,
aber nicht Commits, die bereits auf `origin/dev` liegen.
Praktische Befehle & sichere Vorgehensweise
- Prüfen — welche Commits würden entfernt werden:
```bash
git fetch origin
git log --oneline origin/main..origin/dev
```
- Optional: Backup des aktuellen `origin/dev`, falls etwas schiefgeht:
```bash
git fetch origin
git branch backup/dev origin/dev
```
- Sicheres Zurücksetzen von `dev` auf `main` (lokal + remote):
```bash
git checkout dev
git fetch origin
git reset --hard origin/main
git push --force-with-lease origin dev
```
- Alternative (ohne lokalen Checkout): Push von `main` direkt nach `dev`:
```bash
git fetch origin
git push --force-with-lease origin origin/main:refs/heads/dev
```
- Warnung: Diese Aktionen schreiben die RemoteHistory um. Koordiniere dich mit
dem Team bevor du ein ForcePush ausführst. Verwende `--force-with-lease`
anstelle von `--force` für etwas mehr Sicherheit.
## 📦 Temporäres Speichern & Spezialbefehle
### Stash (Das "Regal")

View File

@@ -2,19 +2,35 @@
{
"guid": "ef1e863f-cbb0-4e47-9f23-f0cbb1826ad4",
"name": "Seasonals",
"description": "Adds seasonal effects like snow, leaves, etc. to the Jellyfin web interface.",
"overview": "Seasonal effects for Jellyfin",
"description": "Adds atmospheric, animated seasonal effects like snow, falling leaves, hearts, fireworks and more. The plugin provides a settings page for configuration. If you do not have write permissions to the web folder, please also install the file-transformation plugin.",
"overview": "Atmospheric, configurable seasonal effects for the Jellyfin web interface",
"owner": "CodeDevMLH",
"category": "General",
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/raw/branch/main/logo.png",
"versions": [
{
"version": "1.6.13.0",
"changelog": "- feat: Add client-side toggle option for seasonal settings",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/releases/download/v1.6.13.0/Jellyfin.Plugin.Seasonals.zip",
"checksum": "171e02dc929fe93497e784e603475e50",
"timestamp": "2026-02-03T23:12:28Z"
},
{
"version": "1.5.1.0",
"changelog": "- fix: snowfall effect sometimes not scaling on window resize, which leads to clustering and rain effect of snowflakes",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/releases/download/v1.5.1.0/Jellyfin.Plugin.Seasonals.zip",
"checksum": "a66b5c24c1f4bfff14bba5e93576bb80",
"timestamp": "2026-01-28T22:40:49Z"
},
{
"version": "1.5.0.0",
"changelog": "- Refactor SeasonalsPlugin: Simplify script injection logic",
"changelog": "- Refactor script injection logic",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/Jellyfin-Seasonals-Plugin/releases/download/v1.5.0.0/Jellyfin.Plugin.Seasonals.zip",
"checksum": "fa174c764164b0524fb2e8f11ffbcace",
"timestamp": "2026-01-06T22:21:49Z"
"checksum": "ba8d3c358df3e0546b99113b43f54fea",
"timestamp": "2026-01-08T23:31:52Z"
},
{
"version": "1.4.1.0",
@@ -85,12 +101,132 @@
{
"guid": "d7e11d57-819b-4bdd-a88d-53c5f5560225",
"name": "Media Bar Enhanced",
"description": "A jellyfin plugin to display a media bar (featured content) for jellyfin web.",
"overview": "Media Bar for Jellyfin",
"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": "Transforms your Jellyfin home screen with an immersive, fully configurable media slideshow featuring video backdrops.",
"owner": "CodeDevMLH",
"category": "General",
"imageUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/raw/branch/main/logo.png",
"versions": [
{
"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.3.6",
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.6/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "da73bb490548c122906419d2762a2d00",
"timestamp": "2026-01-28T21:31:54Z"
},
{
"version": "1.2.3.5",
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.5/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "b5efea79ec465522dad31e4ee5f1710c",
"timestamp": "2026-01-28T20:21:20Z"
},
{
"version": "1.2.3.4",
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.4/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "4683f75e2df2590db663303bdd329ccd",
"timestamp": "2026-01-28T01:09:38Z"
},
{
"version": "1.2.3.3",
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.3/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "3c18a84b2f59c86c130e91da83f980a2",
"timestamp": "2026-01-28T01:05:45Z"
},
{
"version": "1.2.3.2",
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.2/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "4109a3ea10eb3145217b24ee8f8b37b5",
"timestamp": "2026-01-28T00:30:36Z"
},
{
"version": "1.2.3.1",
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.1/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "e73029ac767e24d36742a27678758b6f",
"timestamp": "2026-01-28T00:17:28Z"
},
{
"version": "1.2.3.0",
"changelog": "- Fixes the issue where buttons were cut off on smaller screens such as on S24/S25.",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.3.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "ae6f34bee76f9d7873964a71ca191bf3",
"timestamp": "2026-01-27T23:54:42Z"
},
{
"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",
"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",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.2.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "0b6379f68990026240d97fe8f77fbef1",
"timestamp": "2026-01-08T23:30:58Z"
},
{
"version": "1.1.2.0",
"changelog": "- Add method to resume video playback when slideshow is active",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.1.2.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "a0e8ff5e59b22a1bdedc916cd5e1c16a",
"timestamp": "2026-01-08T15:26:55Z"
},
{
"version": "1.1.1.0",
"changelog": "- Add method to pause all video playback when navigating away from home screen",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.1.1.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "09da95fc561b11191d23a5cfa30ea731",
"timestamp": "2026-01-08T14:54:57Z"
},
{
"version": "1.1.0.0",
"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",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.1.0.0/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "32305d72b8d704acf8eef0c22277fee9",
"timestamp": "2026-01-08T02:15:50Z"
},
{
"version": "1.0.0.3",
"changelog": "fixes",
"targetAbi": "10.11.0.0",
"sourceUrl": "https://git.mahom03-spacecloud.de/CodeDevMLH/jellyfin-plugin-media-bar-enhanced/releases/download/v1.0.0.3/Jellyfin.Plugin.MediaBarEnhanced.zip",
"checksum": "e6180c42836069029072e96ac4860c42",
"timestamp": "2026-01-06T23:26:29Z"
},
{
"version": "1.0.0.2",
"changelog": "fixes",