This commit is contained in:
@@ -0,0 +1,37 @@
|
||||
using MediaBrowser.Model.Plugins;
|
||||
|
||||
namespace Jellyfin.Plugin.MediaBarEnhanced.Configuration
|
||||
{
|
||||
/// <summary>
|
||||
/// Plugin configuration.
|
||||
/// </summary>
|
||||
public class PluginConfiguration : BasePluginConfiguration
|
||||
{
|
||||
public int ShuffleInterval { get; set; } = 7000;
|
||||
public int RetryInterval { get; set; } = 500;
|
||||
public int MinSwipeDistance { get; set; } = 50;
|
||||
public int LoadingCheckInterval { get; set; } = 100;
|
||||
public int MaxPlotLength { get; set; } = 360;
|
||||
public int MaxMovies { get; set; } = 15;
|
||||
public int MaxTvShows { get; set; } = 15;
|
||||
public int MaxItems { get; set; } = 500;
|
||||
public int PreloadCount { get; set; } = 3;
|
||||
public int FadeTransitionDuration { get; set; } = 500;
|
||||
public int MaxPaginationDots { get; set; } = 15;
|
||||
public bool SlideAnimationEnabled { get; set; } = true;
|
||||
public bool EnableVideoBackdrop { get; set; } = true;
|
||||
public bool UseSponsorBlock { get; set; } = true;
|
||||
public bool WaitForTrailerToEnd { get; set; } = true;
|
||||
public bool StartMuted { get; set; } = true;
|
||||
public bool FullWidthVideo { get; set; } = true;
|
||||
public bool EnableMobileVideo { get; set; } = false;
|
||||
public bool ShowTrailerButton { get; set; } = true;
|
||||
public bool EnableLoadingScreen { get; set; } = true;
|
||||
public bool EnableKeyboardControls { get; set; } = true;
|
||||
public bool AlwaysShowArrows { get; set; } = false;
|
||||
public string CustomMediaIds { get; set; } = "";
|
||||
public bool EnableCustomMediaIds { get; set; } = false;
|
||||
public bool EnableSeasonalContent { get; set; } = false;
|
||||
public bool IsEnabled { get; set; } = true;
|
||||
}
|
||||
}
|
||||
431
Jellyfin.Plugin.MediaBarEnhanced/Configuration/configPage.html
Normal file
431
Jellyfin.Plugin.MediaBarEnhanced/Configuration/configPage.html
Normal file
@@ -0,0 +1,431 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Media Bar Enhanced Configuration</title>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="MediaBarEnhancedConfigurationPage" data-role="page" class="page type-interior pluginConfigurationPage"
|
||||
data-require="emby-input,emby-button,emby-select,emby-checkbox,emby-textarea">
|
||||
<div data-role="content">
|
||||
<div class="content-primary">
|
||||
<div class="sectionTitleContainer">
|
||||
<h2 class="sectionTitle">Media Bar Enhanced</h2>
|
||||
<a is="emby-linkbutton" class="raised raised-mini emby-button" style="margin-left: 2em;"
|
||||
target="_blank" href="https://github.com/CodeDevMLH/Jellyfin-Seasonals">
|
||||
<i class="md-icon button-icon button-icon-left secondaryText"></i>
|
||||
<span>Help</span>
|
||||
</a>
|
||||
</div>
|
||||
<hr style="max-width: 800px; margin: 1em 0;">
|
||||
|
||||
<div style="margin-bottom: 1.5em;">
|
||||
<button class="jellyfin-tab-button active" onclick="showTab('basic', this)"
|
||||
style="background: none; border: none; color: #fff; cursor: pointer; transition: color 0.3s, border-bottom 0.3s; padding: 0.5em 1em; border-bottom: 2px solid #00a4dc;">
|
||||
<h3>General Settings</h3>
|
||||
</button>
|
||||
<button class="jellyfin-tab-button" onclick="showTab('custom', this)"
|
||||
style="background: none; border: none; color: #ccc; cursor: pointer; transition: color 0.3s, border-bottom 0.3s; padding: 0.5em 1em; border-bottom: 2px solid transparent;">
|
||||
<h3>Custom Content</h3>
|
||||
</button>
|
||||
<button class="jellyfin-tab-button" onclick="showTab('advanced', this)"
|
||||
style="background: none; border: none; color: #ccc; cursor: pointer; transition: color 0.3s, border-bottom 0.3s; padding: 0.5em 1em; border-bottom: 2px solid transparent;">
|
||||
<h3>Advanced Settings</h3>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<form id="mediaBarEnhancedConfigForm">
|
||||
|
||||
<!-- BASIC TAB -->
|
||||
<div id="basic" class="tab-content">
|
||||
<h2 class="sectionTitle">Main Plugin Settings</h2>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="IsEnabled" name="IsEnabled" />
|
||||
<span>Enable Media Bar Enhanced Plugin</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Enable or disable the entire plugin functionality.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="EnableVideoBackdrop"
|
||||
name="EnableVideoBackdrop" />
|
||||
<span>Enable Video Backdrops</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Show video trailers as background if available.<br>Adds a
|
||||
mute/unmute and pause/play button to control the video in the right top corner.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="WaitForTrailerToEnd"
|
||||
name="WaitForTrailerToEnd" />
|
||||
<span>Wait For Trailer To End</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Delay slide transition until trailer finishes.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="EnableMobileVideo"
|
||||
name="EnableMobileVideo" />
|
||||
<span>Enable Mobile Video</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Allow video playback on mobile devices.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="ShowTrailerButton"
|
||||
name="ShowTrailerButton" />
|
||||
<span>Show Trailer Button</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Display a button to open trailer in modal. Only visible if
|
||||
trailer is not set as backdrop.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CUSTOM CONTENT TAB -->
|
||||
<div id="custom" class="tab-content" style="display:none;">
|
||||
<h2 class="sectionTitle">Custom Media IDs</h2>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="EnableCustomMediaIds"
|
||||
name="EnableCustomMediaIds" />
|
||||
<span>Enable Custom Media IDs</span>
|
||||
</label>
|
||||
<div class="fieldDescription">If enabled, the slideshow will ONLY show the items listed
|
||||
below.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="EnableSeasonalContent"
|
||||
name="EnableSeasonalContent" />
|
||||
<span>Enable Seasonal Content Mode</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Enable this to define time-based lists in the field below.
|
||||
</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="CustomMediaIds">Media/Collection/Playlist
|
||||
IDs
|
||||
(Comma or Newline separated)</label>
|
||||
<textarea is="emby-textarea" id="CustomMediaIds" name="CustomMediaIds"
|
||||
style="width: 100%; height: 150px; font-family: monospace;"></textarea>
|
||||
<div class="fieldDescription" id="customMediaIdsDesc">Enter the IDs of the items you want to
|
||||
show in the slideshow.
|
||||
You can separate them by comma or new line.</div>
|
||||
<div class="fieldDescription" id="seasonalMediaIdsDesc" style="display: none;">
|
||||
<b>Seasonal Mode Enabled:</b> Define lines with date ranges (Format: DD.MM-DD.MM |
|
||||
<i>name</i> | <i>IDs</i>).<br>
|
||||
Example:<br>
|
||||
<code>20.10-31.10 | Halloween | ID1, ID2</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
|
||||
fetch the list.txt or use random items.</i>
|
||||
</div>
|
||||
<p>You can find the IDs of your items in the URL of the item page in the web interface.<br>
|
||||
Example:
|
||||
<code>https://your-jellyfin-url/web/#/details?id=<b style="color:red;">your-item-id</b>&serverId=your-server-id</code><br>
|
||||
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
|
||||
succeeded, you
|
||||
will have to look if the bar displays the correct items.).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- ADVANCED TAB -->
|
||||
<div id="advanced" class="tab-content" style="display:none;">
|
||||
<h2 class="sectionTitle">Features</h2>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="SlideAnimationEnabled"
|
||||
name="SlideAnimationEnabled" />
|
||||
<span>Enable Slide Animations</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Enable the zooming-in effect when a new slide is
|
||||
shown. Attention: This may cause performance issues on weaker client hardware.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="UseSponsorBlock" name="UseSponsorBlock" />
|
||||
<span>Use SponsorBlock</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Skip intro/outro segments in YouTube trailers.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="StartMuted" name="StartMuted" />
|
||||
<span>Start Muted</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Start trailer video playback muted. (Known issue: In the
|
||||
Android/IOS app, backdrop trailers are always muted.)</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="FullWidthVideo" name="FullWidthVideo" />
|
||||
<span>Full Width Video</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Stretch video to full width. Very nice on desktops, on mobile
|
||||
devices only the middle of the video is visible.<br>Disable to get the full aspect ratio
|
||||
on
|
||||
mobile devices. (looks bad on desktops)</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="EnableLoadingScreen"
|
||||
name="EnableLoadingScreen" />
|
||||
<span>Enable Loading Screen</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Show a loading screen while the slideshow initializes. (You
|
||||
may have to reload the page twice)</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="AlwaysShowArrows"
|
||||
name="AlwaysShowArrows" />
|
||||
<span>Always Show Arrows</span>
|
||||
</label>
|
||||
<div class="fieldDescription">If enabled, navigation arrows will always be visible instead
|
||||
of only on hover.</div>
|
||||
</div>
|
||||
<div class="checkboxContainer checkboxContainer-withDescription">
|
||||
<label>
|
||||
<input is="emby-checkbox" type="checkbox" id="EnableKeyboardControls"
|
||||
name="EnableKeyboardControls" />
|
||||
<span>Enable Keyboard Controls</span>
|
||||
</label>
|
||||
<div class="fieldDescription">Enable keyboard shortcuts (Arrows left/right (change slide),
|
||||
Space (pause), M (mute/unmute)) for
|
||||
the slideshow.</div>
|
||||
</div>
|
||||
|
||||
<h2 class="sectionTitle">Time Settings</h2>
|
||||
<p>Leave a setting blank to use the default value.</p>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="ShuffleInterval">Shuffle Interval
|
||||
(ms)</label>
|
||||
<input is="emby-input" type="number" id="ShuffleInterval" name="ShuffleInterval" />
|
||||
<div class="fieldDescription">Time in milliseconds between changing slides.</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="RetryInterval">Retry Interval
|
||||
(ms)</label>
|
||||
<input is="emby-input" type="number" id="RetryInterval" name="RetryInterval" />
|
||||
<div class="fieldDescription">Time in milliseconds to wait before retrying failed
|
||||
operations.</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="LoadingCheckInterval">Loading Check
|
||||
Interval (ms)</label>
|
||||
<input is="emby-input" type="number" id="LoadingCheckInterval"
|
||||
name="LoadingCheckInterval" />
|
||||
<div class="fieldDescription">Frequency of checking wether the login screen or home screen
|
||||
has loaded (in milliseconds).</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="FadeTransitionDuration">Fade
|
||||
Transition Duration (ms)</label>
|
||||
<input is="emby-input" type="number" id="FadeTransitionDuration"
|
||||
name="FadeTransitionDuration" />
|
||||
<div class="fieldDescription">Duration in milliseconds of the transition between slides.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="MinSwipeDistance">Min Swipe Distance
|
||||
(px)</label>
|
||||
<input is="emby-input" type="number" id="MinSwipeDistance" name="MinSwipeDistance" />
|
||||
<div class="fieldDescription">Minimum distance in pixels for a swipe to be registered (for
|
||||
mobile).</div>
|
||||
</div>
|
||||
|
||||
<h2 class="sectionTitle">Content Limits</h2>
|
||||
<p>Leave a setting blank to use the default value.</p>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="MaxItems">Total Max Items</label>
|
||||
<input is="emby-input" type="number" id="MaxItems" name="MaxItems" />
|
||||
<div class="fieldDescription">Maximum total items to fetch (for all content types combined).
|
||||
</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="MaxMovies">Max Movies</label>
|
||||
<input is="emby-input" type="number" id="MaxMovies" name="MaxMovies" />
|
||||
<div class="fieldDescription">Maximum movies to include in slideshow (for random selection).
|
||||
</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="MaxTvShows">Max TV Shows</label>
|
||||
<input is="emby-input" type="number" id="MaxTvShows" name="MaxTvShows" />
|
||||
<div class="fieldDescription">Maximum TV shows to include in slideshow (for random
|
||||
selection).</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="PreloadCount">Preload Count</label>
|
||||
<input is="emby-input" type="number" id="PreloadCount" name="PreloadCount" />
|
||||
<div class="fieldDescription">Number of images to preload.</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="MaxPaginationDots">Max Pagination
|
||||
Dots</label>
|
||||
<input is="emby-input" type="number" id="MaxPaginationDots" name="MaxPaginationDots" />
|
||||
<div class="fieldDescription">Maximum number of dots to show in navigation. If the number
|
||||
will be exceeded, the dots will "turn" into a counter style (e.g. 1/100). Set to 0 to
|
||||
enable counter style directly.</div>
|
||||
</div>
|
||||
<div class="inputContainer">
|
||||
<label class="inputLabel inputLabelUnfocused" for="MaxPlotLength">Max Plot
|
||||
Length</label>
|
||||
<input is="emby-input" type="number" id="MaxPlotLength" name="MaxPlotLength" />
|
||||
<div class="fieldDescription">Maximum characters for the plot summary.</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
style="background-color: rgba(255, 255, 255, 0.05); border-left: 4px solid #00a4dc; border-radius: 4px; padding: 1em 1.5em; margin: 1.5em 0; display: flex; align-items: center; gap: 1em;">
|
||||
<i class="material-icons" style="color: #00a4dc; font-size: 24px;">info</i>
|
||||
<div>
|
||||
All changes require a page refresh (ctrl + r or F5) after saving for changes to take effect.
|
||||
<br />
|
||||
If old settings persist, please force clear browser cache.
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<button is="emby-button" type="submit" class="raised button-submit block emby-button">
|
||||
<span>${Save}</span>
|
||||
</button>
|
||||
<button is="emby-button" type="button" class="raised button-cancel block btnCancel"
|
||||
onclick="history.back();">
|
||||
<span>${ButtonCancel}</span>
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function showTab(tabId, btn) {
|
||||
document.querySelectorAll('.tab-content').forEach(el => el.style.display = 'none');
|
||||
document.getElementById(tabId).style.display = 'block';
|
||||
|
||||
document.querySelectorAll('.jellyfin-tab-button').forEach(b => {
|
||||
b.classList.remove('active');
|
||||
b.style.color = '#ccc';
|
||||
b.style.borderBottom = '2px solid transparent';
|
||||
});
|
||||
|
||||
if (btn) {
|
||||
btn.classList.add('active');
|
||||
btn.style.color = '#fff';
|
||||
btn.style.borderBottom = '2px solid #00a4dc';
|
||||
}
|
||||
}
|
||||
|
||||
var MediaBarEnhancedConfigurationPage = {
|
||||
pluginId: 'd7e11d57-819b-4bdd-a88d-53c5f5560225',
|
||||
loadConfiguration: function (page) {
|
||||
Dashboard.showLoadingMsg();
|
||||
ApiClient.getPluginConfiguration(MediaBarEnhancedConfigurationPage.pluginId).then(function (config) {
|
||||
|
||||
var keys = [
|
||||
'IsEnabled', 'ShuffleInterval', 'RetryInterval', 'MinSwipeDistance',
|
||||
'LoadingCheckInterval', 'MaxPlotLength', 'MaxMovies', 'MaxTvShows',
|
||||
'MaxItems', 'PreloadCount', 'FadeTransitionDuration', 'MaxPaginationDots',
|
||||
'SlideAnimationEnabled', 'EnableVideoBackdrop', 'UseSponsorBlock',
|
||||
'WaitForTrailerToEnd', 'StartMuted', 'FullWidthVideo', 'EnableMobileVideo',
|
||||
'ShowTrailerButton', 'AlwaysShowArrows', 'EnableKeyboardControls',
|
||||
'EnableCustomMediaIds', 'CustomMediaIds', 'EnableLoadingScreen',
|
||||
'EnableSeasonalContent'
|
||||
];
|
||||
|
||||
keys.forEach(function (key) {
|
||||
var el = page.querySelector('#' + key);
|
||||
if (el) {
|
||||
if (el.type === 'checkbox') {
|
||||
el.checked = config[key];
|
||||
} else {
|
||||
el.value = config[key];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Handle Seasonal UI logic
|
||||
var seasonalCheckbox = page.querySelector('#EnableSeasonalContent');
|
||||
var normalDesc = page.querySelector('#customMediaIdsDesc');
|
||||
var seasonalDesc = page.querySelector('#seasonalMediaIdsDesc');
|
||||
|
||||
function updateDesc() {
|
||||
if (seasonalCheckbox && seasonalCheckbox.checked) {
|
||||
if (normalDesc) normalDesc.style.display = 'none';
|
||||
if (seasonalDesc) seasonalDesc.style.display = 'block';
|
||||
} else {
|
||||
if (normalDesc) normalDesc.style.display = 'block';
|
||||
if (seasonalDesc) seasonalDesc.style.display = 'none';
|
||||
}
|
||||
}
|
||||
|
||||
if (seasonalCheckbox) {
|
||||
seasonalCheckbox.addEventListener('change', updateDesc);
|
||||
updateDesc();
|
||||
}
|
||||
|
||||
Dashboard.hideLoadingMsg();
|
||||
});
|
||||
},
|
||||
saveConfiguration: function (page) {
|
||||
Dashboard.showLoadingMsg();
|
||||
|
||||
var config = {};
|
||||
var keys = [
|
||||
'IsEnabled', 'ShuffleInterval', 'RetryInterval', 'MinSwipeDistance',
|
||||
'LoadingCheckInterval', 'MaxPlotLength', 'MaxMovies', 'MaxTvShows',
|
||||
'MaxItems', 'PreloadCount', 'FadeTransitionDuration', 'MaxPaginationDots',
|
||||
'SlideAnimationEnabled', 'EnableVideoBackdrop', 'UseSponsorBlock',
|
||||
'WaitForTrailerToEnd', 'StartMuted', 'FullWidthVideo', 'EnableMobileVideo',
|
||||
'ShowTrailerButton', 'AlwaysShowArrows', 'EnableKeyboardControls',
|
||||
'EnableCustomMediaIds', 'CustomMediaIds', 'EnableLoadingScreen',
|
||||
'EnableSeasonalContent'
|
||||
];
|
||||
|
||||
keys.forEach(function (key) {
|
||||
var el = page.querySelector('#' + key);
|
||||
if (el) {
|
||||
if (el.type === 'checkbox') {
|
||||
config[key] = el.checked;
|
||||
} else {
|
||||
config[key] = (el.type === 'number') ? parseInt(el.value, 10) : el.value;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ApiClient.updatePluginConfiguration(MediaBarEnhancedConfigurationPage.pluginId, config).then(function (result) {
|
||||
Dashboard.processPluginConfigurationUpdateResult(result);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
document.querySelector('#MediaBarEnhancedConfigurationPage').addEventListener('pageshow', function () {
|
||||
MediaBarEnhancedConfigurationPage.loadConfiguration(this);
|
||||
});
|
||||
|
||||
document.querySelector('#mediaBarEnhancedConfigForm').addEventListener('submit', function (e) {
|
||||
e.preventDefault();
|
||||
MediaBarEnhancedConfigurationPage.saveConfiguration(document.querySelector('#MediaBarEnhancedConfigurationPage'));
|
||||
return false;
|
||||
});
|
||||
</script>
|
||||
|
||||
<style>
|
||||
.jellyfin-tab-button.active {
|
||||
color: #fff !important;
|
||||
border-bottom: 2px solid #00a4dc !important;
|
||||
}
|
||||
</style>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
Reference in New Issue
Block a user