mirror of
https://github.com/ranaldsgift/KefinTweaks.git
synced 2026-11-05 15:52:47 +01:00
Add proper installation and uninstallation support from the Plugins page
This commit is contained in:
@@ -10,14 +10,13 @@ I think it's also worth mentioning that before the 1.0 release, you can expect t
|
||||
|
||||
Note: The Slideshow at the top of the Home Screen in the video below is from the [MediaBar](https://github.com/IAmParadox27/jellyfin-plugin-media-bar) plugin by [IAmParadox27](https://github.com/IAmParadox27) and [MakD](https://github.com/MakD).
|
||||
|
||||
[](https://streamable.com/ypnn6n)
|
||||
[](https://youtu.be/4ikW4CFSn3I)
|
||||
|
||||
## Table of Contents
|
||||
|
||||
- [Installation](#installation)
|
||||
- [Prerequisites](#prerequisites)
|
||||
- [Setup Instructions](#setup-instructions)
|
||||
- [Alternate Installation Options](#alternate-installation-options)
|
||||
- [Configuration](#configuration)
|
||||
- [Features Overview](#features-overview)
|
||||
- [Data Caching](#data-caching)
|
||||
@@ -76,44 +75,29 @@ Note: The Slideshow at the top of the Home Screen in the video below is from the
|
||||
|
||||
### Setup Instructions
|
||||
|
||||
0a. **Install Prerequisites listed above**
|
||||
0b. **If you are using JellyfinEnhanced, you MUST disable the "Watchlist" feature from the plugin settings**
|
||||
0. **Install the Prerequisites listed above**
|
||||
1. **Add a new script to your JS Injector Plugin**
|
||||
2. **Copy the the code below and paste it into the new script:**
|
||||
2. **Copy the the code below, paste it into the new script, save your changes and refresh the page**
|
||||
|
||||
```javascript
|
||||
const script = document.createElement("script");
|
||||
script.src = `https://ranaldsgift.github.io/KefinTweaks/injector.js?v=${new Date().getTime()}`;
|
||||
script.src = `https://cdn.jsdelivr.net/gh/ranaldsgift/KefinTweaks/kefinTweaks-plugin.js`;
|
||||
script.async = true;
|
||||
document.head.appendChild(script);
|
||||
```
|
||||
|
||||
3. **Save your changes**
|
||||
If you are hosting the script yourself, replace the `https://cdn.jsdelivr.net/gh/ranaldsgift` with your hosted location. You should be able to include the scripts in your jelly-web folder and access it from `/web/KefinTweaks` if you like.
|
||||
|
||||
3. **Navigate to the Plugins page and click on KefinTweaks**
|
||||
4. **Choose your preferred plugin version, or specify a custom source if you are self hosting the scripts**
|
||||
5. **Press Install! KefinTweaks will automatically load without refreshing the page**
|
||||
|
||||
<div align="center">
|
||||
<img src="pages/images/injector.png" alt="injector" style="max-width: 100%; height: auto;"/>
|
||||
</div>
|
||||
<img src="pages/images/plugin-install.gif" alt="injector" style="max-width: 100%; height: auto;"/>
|
||||
</div>
|
||||
<br/>
|
||||
<hr>
|
||||
|
||||
### Alternate Installation Options
|
||||
|
||||
Some people may prefer to not include these scripts from a remote source and rather host them locally or at some other location and pull them from there. This is supported and easily achievable just follow these steps:
|
||||
|
||||
1. Download your prefered release, extract it and move the files to your preferred hosting location.
|
||||
2. Modify the line below in your JS Injector script for KefinTweaks:
|
||||
```script.src = `https://ranaldsgift.github.io/KefinTweaks/injector.js?v=${new Date().getTime()}`;```
|
||||
- Replace the `https://ranaldsgift.github.io/KefinTweaks/injector.js` with the location you've chosen to host the scripts.
|
||||
- Optionally remove the `?v=${new Date().getTime()}` if you prefer the script to not auto-refresh when you make local changes.
|
||||

|
||||
3. Copy the contents of [kefintweaks-default-config.js](https://raw.githubusercontent.com/ranaldsgift/KefinTweaks/refs/heads/main/kefinTweaks-default-config.js) into JS Injector by adding a new script or updating the existing one.
|
||||

|
||||
- Ensure the name is "KefinTweaks-Config"
|
||||
4. Update the "kefinTweaksRoot" and the "scriptRoot" values in the KefinTweaks-Config in JS Injector so that they reflect the locations you've chosen to host the scripts.
|
||||
5. Save your changes!
|
||||
|
||||
Also, it's probably worth noting that you should be able to include the scripts in your jelly-web folder and access it from `/web/KefinTweaks` if you like.
|
||||
|
||||
## Configuration
|
||||
|
||||
KefinTweaks includes a comprehensive configuration interface accessible to administrators. The configuration UI allows you to customize all aspects of KefinTweaks without editing code files.
|
||||
@@ -122,9 +106,9 @@ KefinTweaks includes a comprehensive configuration interface accessible to admin
|
||||
|
||||
The configuration interface can be accessed in multiple ways:
|
||||
|
||||
1. **From User Preferences**: Navigate to your User Preferences page and find the "Administration" section. Click the "Configure KefinTweaks" button.
|
||||
2. **From Dashboard**: In the Dashboard side menu, find the "KefinTweaks" button under the Plugins section.
|
||||
3. **From Left Navigation Menu**: A "Configure" link will appear in the left navigation menu beneath a KefinTweaks heading.
|
||||
1. **From Dashboard**: In the Dashboard side menu, find the "KefinTweaks" button under the Plugins section.
|
||||
2. **From Left Navigation Menu**: A "Configure" link will appear in the left navigation menu beneath a KefinTweaks heading.
|
||||
3. **From User Preferences**: Navigate to your User Preferences page and find the "Administration" section. Click the "Configure KefinTweaks" button.
|
||||
|
||||
### Configuration Features
|
||||
|
||||
@@ -163,6 +147,19 @@ On first load, KefinTweaks automatically:
|
||||
These tasks only run for administrator users and happen automatically in the background.
|
||||
<hr>
|
||||
|
||||
## Uninstallation
|
||||
|
||||
1. **Navigate to the Plugins page and click on KefinTweaks**
|
||||
2. **Press Uninstall and click to confirm**
|
||||
|
||||
<div align="center">
|
||||
<img src="pages/images/plugin-uninstall.gif" alt="injector" style="max-width: 100%; height: auto;"/>
|
||||
</div>
|
||||
<br/>
|
||||
<hr>
|
||||
|
||||
|
||||
|
||||
## Features Overview
|
||||
|
||||
KefinTweaks provides a modular system of enhancements that can be individually enabled or disabled based on your needs. Each script is designed to work independently while sharing common utilities and dependencies.
|
||||
@@ -612,6 +609,7 @@ This README and the inline comments in kefinTweaks.js and the other scripts is t
|
||||
<hr>
|
||||
|
||||
### Version History
|
||||
- **v0.3.2**: Add proper installation and uninstallation support from the Plugins page. New feature: Playlist sorting.
|
||||
- **v0.3.1**: New Home Screen Section feature: Spotlights! Improved Configuration UI.
|
||||
- **v0.3.0**: KefinTweaks configuration for admins in the Jellyfin UI!
|
||||
- **v0.2.4**: New Feature: Watchlist Export/Import
|
||||
|
||||
+51
-128
@@ -6,7 +6,7 @@
|
||||
'use strict';
|
||||
|
||||
console.log('[KefinTweaks Injector] Initializing...');
|
||||
const versionNumber = "0.3.1";
|
||||
const versionNumber = "0.3.2";
|
||||
|
||||
// Configuration: Start with defaults, then merge user config
|
||||
// This allows new scripts to work out of the box without requiring config updates
|
||||
@@ -198,8 +198,8 @@
|
||||
name: 'playlist',
|
||||
script: 'playlist.js',
|
||||
css: null,
|
||||
dependencies: ['cardBuilder', 'utils'],
|
||||
description: 'Modifies playlist view page behavior to navigate to item details instead of playing, and adds play button to playlist items'
|
||||
dependencies: ['cardBuilder', 'utils', 'modal'],
|
||||
description: 'Modifies playlist view page behavior to navigate to item details instead of playing, adds play button to playlist items, and adds sorting functionality'
|
||||
},
|
||||
{
|
||||
name: 'itemDetailsCollections',
|
||||
@@ -227,25 +227,6 @@
|
||||
// Use this for development
|
||||
//const urlSuffix = '';
|
||||
const urlSuffix = `?v=${new Date().getTime()}`;
|
||||
|
||||
// Fetch version date from GitHub releases API
|
||||
async function fetchVersionDate(version) {
|
||||
try {
|
||||
const response = await fetch(`https://api.github.com/repos/ranaldsgift/KefinTweaks/releases/tags/v${version}`);
|
||||
if (!response.ok) {
|
||||
// Try latest release if tag doesn't exist
|
||||
const latestResponse = await fetch(`https://api.github.com/repos/ranaldsgift/KefinTweaks/releases/latest`);
|
||||
if (!latestResponse.ok) throw new Error('Failed to fetch release data');
|
||||
const data = await latestResponse.json();
|
||||
return new Date(data.published_at);
|
||||
}
|
||||
const data = await response.json();
|
||||
return new Date(data.published_at);
|
||||
} catch (error) {
|
||||
console.warn('[KefinTweaks Injector] Failed to fetch version date from GitHub:', error);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// Inject dashboard drawer version badge CSS using dynamic version number
|
||||
function injectVersionBadgeCSS() {
|
||||
@@ -336,21 +317,32 @@
|
||||
|
||||
// Get the root path for scripts from configuration
|
||||
function getScriptRoot() {
|
||||
const configScriptRoot = window.KefinTweaksConfig?.scriptRoot;
|
||||
|
||||
// Handle legacy configuration pointing to the root directory
|
||||
if (configScriptRoot === 'https://ranaldsgift.github.io/KefinTweaks/') {
|
||||
return 'https://ranaldsgift.github.io/KefinTweaks/scripts/';
|
||||
const kefinTweaksRoot = window.KefinTweaksConfig?.kefinTweaksRoot;
|
||||
|
||||
// If kefinTweaksRoot is not set or empty, return null (scripts should not load)
|
||||
if (!kefinTweaksRoot || kefinTweaksRoot === '') {
|
||||
console.warn('[KefinTweaks Injector] kefinTweaksRoot is not configured');
|
||||
return null;
|
||||
}
|
||||
|
||||
return window.KefinTweaksConfig?.scriptRoot || 'https://ranaldsgift.github.io/KefinTweaks/scripts/';
|
||||
|
||||
// Ensure root ends with /
|
||||
const root = kefinTweaksRoot.endsWith('/') ? kefinTweaksRoot : kefinTweaksRoot + '/';
|
||||
|
||||
// Return scripts path
|
||||
return root + 'scripts/';
|
||||
}
|
||||
|
||||
// Load a CSS file
|
||||
function loadCSS(filename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const scriptRoot = getScriptRoot();
|
||||
if (!scriptRoot) {
|
||||
reject(new Error('kefinTweaksRoot is not configured'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if CSS is already loaded (match by root and filename, ignore suffix)
|
||||
const existingLink = document.querySelector(`link[href*="${getScriptRoot()}${filename}"]`);
|
||||
const existingLink = document.querySelector(`link[href*="${scriptRoot}${filename}"]`);
|
||||
if (existingLink) {
|
||||
console.log(`[KefinTweaks Injector] CSS already loaded: ${filename}`);
|
||||
resolve();
|
||||
@@ -360,7 +352,7 @@
|
||||
const link = document.createElement('link');
|
||||
link.rel = 'stylesheet';
|
||||
link.type = 'text/css';
|
||||
link.href = `${getScriptRoot()}${filename}${urlSuffix}`;
|
||||
link.href = `${scriptRoot}${filename}${urlSuffix}`;
|
||||
|
||||
link.onload = () => {
|
||||
console.log(`[KefinTweaks Injector] CSS loaded: ${filename}`);
|
||||
@@ -379,8 +371,14 @@
|
||||
// Load a JavaScript file
|
||||
function loadScript(filename) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const scriptRoot = getScriptRoot();
|
||||
if (!scriptRoot) {
|
||||
reject(new Error('kefinTweaksRoot is not configured'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if script is already loaded
|
||||
const existingScript = document.querySelector(`script[src*="${getScriptRoot()}${filename}"]`);
|
||||
const existingScript = document.querySelector(`script[src*="${scriptRoot}${filename}"]`);
|
||||
if (existingScript) {
|
||||
console.log(`[KefinTweaks Injector] Script already loaded: ${filename}`);
|
||||
resolve();
|
||||
@@ -388,7 +386,7 @@
|
||||
}
|
||||
|
||||
const script = document.createElement('script');
|
||||
script.src = `${getScriptRoot()}${filename}${urlSuffix}`;
|
||||
script.src = `${scriptRoot}${filename}${urlSuffix}`;
|
||||
script.async = true;
|
||||
|
||||
script.onload = () => {
|
||||
@@ -438,8 +436,13 @@
|
||||
|
||||
// Load a single script (assumes dependencies are already loaded)
|
||||
async function loadScriptSync(scriptDef) {
|
||||
const scriptRoot = getScriptRoot();
|
||||
if (!scriptRoot) {
|
||||
throw new Error('kefinTweaksRoot is not configured');
|
||||
}
|
||||
|
||||
// Check if already loaded (match by root and filename, ignore suffix)
|
||||
const isAlreadyLoaded = document.querySelector(`script[src*="${getScriptRoot()}${scriptDef.script}"]`);
|
||||
const isAlreadyLoaded = document.querySelector(`script[src*="${scriptRoot}${scriptDef.script}"]`);
|
||||
if (isAlreadyLoaded) {
|
||||
console.log(`[KefinTweaks Injector] Script already loaded: ${scriptDef.name}`);
|
||||
return;
|
||||
@@ -460,6 +463,13 @@
|
||||
async function initialize() {
|
||||
console.log(`[KefinTweaks Injector] Starting KefinTweaks v${versionNumber} initialization...`);
|
||||
|
||||
// Check if kefinTweaksRoot is configured
|
||||
const scriptRoot = getScriptRoot();
|
||||
if (!scriptRoot) {
|
||||
console.log('[KefinTweaks Injector] kefinTweaksRoot is not configured. Please configure KefinTweaks using the installer before scripts can be loaded.');
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate configuration
|
||||
if (!validateConfiguration()) {
|
||||
console.error('[KefinTweaks Injector] Configuration validation failed. Aborting.');
|
||||
@@ -713,96 +723,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure KefinTweaks-Config exists in JS Injector
|
||||
async function ensureKefinTweaksConfig() {
|
||||
try {
|
||||
console.log('[KefinTweaks Startup] Ensuring KefinTweaks-Config exists in JS Injector...');
|
||||
|
||||
const pluginId = await findPlugin('JavaScript Injector') || await findPlugin('JS Injector');
|
||||
if (!pluginId) {
|
||||
console.warn('[KefinTweaks Startup] JavaScript Injector plugin not found');
|
||||
return false;
|
||||
}
|
||||
|
||||
const injectorConfig = await getPluginConfig(pluginId);
|
||||
|
||||
// Ensure CustomJavaScripts array exists
|
||||
if (!injectorConfig.CustomJavaScripts) {
|
||||
injectorConfig.CustomJavaScripts = [];
|
||||
}
|
||||
|
||||
// Check if KefinTweaks-Config already exists
|
||||
const existingScript = injectorConfig.CustomJavaScripts.find(
|
||||
script => script.Name === 'KefinTweaks-Config'
|
||||
);
|
||||
|
||||
if (existingScript) {
|
||||
console.log('[KefinTweaks Startup] KefinTweaks-Config already exists in JS Injector');
|
||||
return true;
|
||||
}
|
||||
|
||||
// Load default config
|
||||
let defaultConfig;
|
||||
if (window.KefinTweaksDefaultConfig) {
|
||||
defaultConfig = window.KefinTweaksDefaultConfig;
|
||||
} else {
|
||||
// Try to load it
|
||||
try {
|
||||
const defaultConfigUrl = window.KefinTweaksConfig?.kefinTweaksRoot
|
||||
? `${window.KefinTweaksConfig.kefinTweaksRoot}kefinTweaks-default-config.js`
|
||||
: 'https://ranaldsgift.github.io/KefinTweaks/kefinTweaks-default-config.js';
|
||||
|
||||
await new Promise((resolve, reject) => {
|
||||
const script = document.createElement('script');
|
||||
script.src = defaultConfigUrl;
|
||||
script.onload = () => resolve();
|
||||
script.onerror = () => reject(new Error('Failed to load default config'));
|
||||
document.head.appendChild(script);
|
||||
});
|
||||
|
||||
defaultConfig = window.KefinTweaksDefaultConfig;
|
||||
} catch (error) {
|
||||
console.error('[KefinTweaks Startup] Error loading default config:', error);
|
||||
// Create minimal config
|
||||
defaultConfig = {
|
||||
kefinTweaksRoot: 'https://ranaldsgift.github.io/KefinTweaks/',
|
||||
scriptRoot: 'https://ranaldsgift.github.io/KefinTweaks/scripts/',
|
||||
scripts: {},
|
||||
homeScreen: {},
|
||||
exclusiveElsewhere: {},
|
||||
search: {},
|
||||
skins: [],
|
||||
themes: [],
|
||||
customMenuLinks: []
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// Create the script content
|
||||
const scriptContent = `// KefinTweaks Configuration
|
||||
// This file is automatically generated by KefinTweaks Configuration UI
|
||||
// Do not edit manually unless you know what you're doing
|
||||
|
||||
window.KefinTweaksConfig = ${JSON.stringify(defaultConfig, null, 2)};`;
|
||||
|
||||
// Add new script
|
||||
injectorConfig.CustomJavaScripts.push({
|
||||
Name: 'KefinTweaks-Config',
|
||||
Script: scriptContent,
|
||||
Enabled: true,
|
||||
RequiresAuthentication: false
|
||||
});
|
||||
|
||||
// Save the configuration
|
||||
await savePluginConfig(pluginId, injectorConfig);
|
||||
window.KefinTweaksConfig = defaultConfig;
|
||||
console.log('[KefinTweaks Startup] KefinTweaks-Config added to JS Injector');
|
||||
return true;
|
||||
} catch (error) {
|
||||
console.error('[KefinTweaks Startup] Error ensuring KefinTweaks-Config:', error);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure Watchlist tab exists in CustomTabs
|
||||
async function ensureWatchlistTab() {
|
||||
@@ -885,6 +805,12 @@ window.KefinTweaksConfig = ${JSON.stringify(defaultConfig, null, 2)};`;
|
||||
async function startupTask() {
|
||||
console.log('[KefinTweaks Startup] Starting startup task...');
|
||||
|
||||
// Check if kefinTweaksRoot is configured - startup tasks only run after installation
|
||||
if (!window.KefinTweaksConfig?.kefinTweaksRoot || window.KefinTweaksConfig.kefinTweaksRoot === '') {
|
||||
console.log('[KefinTweaks Startup] kefinTweaksRoot is not configured, skipping startup tasks');
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if user is admin (wait up to 5s for login)
|
||||
const isAdmin = await checkAdminWithTimeout(5000);
|
||||
|
||||
@@ -894,10 +820,7 @@ window.KefinTweaksConfig = ${JSON.stringify(defaultConfig, null, 2)};`;
|
||||
}
|
||||
|
||||
try {
|
||||
// Task 1: Ensure KefinTweaks-Config exists in JS Injector
|
||||
await ensureKefinTweaksConfig();
|
||||
|
||||
// Task 2: Ensure Watchlist tab exists in CustomTabs
|
||||
// Task: Ensure Watchlist tab exists in CustomTabs
|
||||
await ensureWatchlistTab();
|
||||
|
||||
console.log('[KefinTweaks Startup] Startup task completed successfully');
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
window.KefinTweaksDefaultConfig = {
|
||||
"kefinTweaksRoot": "https://ranaldsgift.github.io/KefinTweaks/",
|
||||
"scriptRoot": "https://ranaldsgift.github.io/KefinTweaks/scripts/",
|
||||
"kefinTweaksRoot": "",
|
||||
"scripts": {
|
||||
"homeScreen": true,
|
||||
"search": true,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
-309
@@ -1,309 +0,0 @@
|
||||
// KefinTweaks - Central Configuration and Script Loader
|
||||
// Copy this entire file into your Jellyfin JS injector plugin
|
||||
// Modify the configuration below to enable/disable features and customize settings
|
||||
//
|
||||
// Full compatibility with Jellyfin 10.10.7
|
||||
// Untested compatibility with Jellyfin 10.11+
|
||||
//
|
||||
// FEATURES OVERVIEW:
|
||||
// =================
|
||||
// For a detailed feature overview see README.md at https://github.com/ranaldsgift/KefinTweaks
|
||||
//
|
||||
// PREREQUISITES:
|
||||
// ============
|
||||
// - JS Injector plugin https://github.com/n00bcodr/Jellyfin-JavaScript-Injector
|
||||
// - Custom Tabs plugin for watchlist functionality https://github.com/IAmParadox27/jellyfin-plugin-custom-tabs
|
||||
// - JellyfinEnhanced plugin for Jellyseerr search functionality and ExclusiveElsewhere https://github.com/n00bcodr/Jellyfin-Enhanced
|
||||
//
|
||||
// INSTALLATION:
|
||||
// ============
|
||||
// 0a. Install required prerequisites listed above
|
||||
// 0b. If you are using JellyfinEnhanced, you MUST disable the "Watchlist" feature from the plugin settings
|
||||
// 1. Add a new script to your JS Injector plugin
|
||||
// 2. Copy this entire file into the new script
|
||||
// (Optional) Enable/disable features, or customize their configuration by editing the script below
|
||||
// 3. Ensure the script is enabled
|
||||
// 4. Save your changes
|
||||
//
|
||||
// CONFIGURATION GUIDE:
|
||||
// ===================
|
||||
// - Scripts: Enable/disable individual features
|
||||
// - Home Screen: Configure custom sections and discovery settings
|
||||
// - Exclusive Elsewhere: Only useful if you want to display an icon or logo instead of text
|
||||
// - Search: Enable Jellyseerr integration adds an option to search for Jellyseerr results only
|
||||
//
|
||||
// Considerations for the home screen sections:
|
||||
// - Default Jellyfin sections (order 1-10)
|
||||
// - New releases sections (order 30-49) - Newest movies and episodes
|
||||
// - Seasonal sections (order 50-59) - Holiday-themed content
|
||||
// - One-off sections: Watchlist, TV Networks, section (order 60-69) - Your watchlist
|
||||
// - Discovery sections (order 1000+) - Intelligent recommendations based on your library
|
||||
// - Custom sections can be placed anywhere in the order by using the order field in the configuration
|
||||
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
// ============================================================================
|
||||
// CENTRAL CONFIGURATION
|
||||
// ============================================================================
|
||||
|
||||
const KEFIN_TWEAKS_CONFIG = {
|
||||
// ============================================================================
|
||||
// SCRIPT ROOT CONFIGURATION
|
||||
// ============================================================================
|
||||
// Configure where scripts are loaded from
|
||||
kefinTweaksRoot: 'https://ranaldsgift.github.io/KefinTweaks/',
|
||||
scriptRoot: 'https://ranaldsgift.github.io/KefinTweaks/scripts/',
|
||||
|
||||
// ============================================================================
|
||||
// SCRIPT ENABLE/DISABLE FLAGS
|
||||
// ============================================================================
|
||||
// Toggle individual features on/off. Dependencies are automatically managed.
|
||||
scripts: {
|
||||
// Major feature enhancements
|
||||
homeScreen: true, // Custom home screen sections and discovery engine
|
||||
search: true, // Enhanced search with better UI and Jellyseerr integration
|
||||
// REQUIREMENTS: Watchlist requires Custom Tabs plugin https://github.com/IAmParadox27/jellyfin-plugin-custom-tabs
|
||||
// If you are using JellyfinEnhanced, you MUST disable the "Watchlist" feature from the plugin settings
|
||||
watchlist: true, // Complete watchlist management with progress tracking
|
||||
|
||||
// UI and navigation improvements
|
||||
headerTabs: true, // Improved header tab functionality and behavior
|
||||
customMenuLinks: true, // Load and add custom menu links from configuration
|
||||
breadcrumbs: true, // Breadcrumb navigation for Movies, Series, Seasons, Episodes, Music
|
||||
playlist: true, // Enhanced playlist view with better navigation
|
||||
itemDetailsCollections: true, // Shows collections on item details pages (Included In section)
|
||||
flattenSingleSeasonShows: true, // Flattens single-season shows to display episodes directly on series page
|
||||
collections: true, // Collection sorting functionality
|
||||
|
||||
// Reviews and recommendations
|
||||
// updoot: false, // This is unsupported for now but will be worked on in the future
|
||||
|
||||
// Branding and external integrations
|
||||
// REQUIRES: ExclusiveElsewhere requires JellyfinEnhanced plugin https://github.com/n00bcodr/Jellyfin-Enhanced
|
||||
exclusiveElsewhere: false, // Custom branding when items aren't available on streaming services
|
||||
|
||||
// Performance and stability improvements
|
||||
backdropLeakFix: true, // Fixes memory leaks from backdrop images when tab isn't focused
|
||||
dashboardButtonFix: true, // Proper back button behavior on dashboard
|
||||
infiniteScroll: true, // Smooth infinite scrolling. Supports Movie and TV libraries. Music to be added in the future.
|
||||
|
||||
// Quality of life improvements
|
||||
removeContinue: true, // Add "Remove from Continue Watching" functionality
|
||||
subtitleSearch: true, // Search and download subtitles directly from video OSD
|
||||
|
||||
// UI customization
|
||||
skinManager: true // Skin selection and management - adds skin dropdown to header and display preferences
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// HOME SCREEN CONFIGURATION
|
||||
// ============================================================================
|
||||
// Configure custom home screen sections and discovery features
|
||||
homeScreen: {
|
||||
// NEW AND TRENDING SECTIONS
|
||||
// Automatically curated sections showing latest content
|
||||
enableNewAndTrending: true, // Master toggle for new and trending sections
|
||||
enableNewMovies: true, // Show newest movies section
|
||||
enableNewEpisodes: true, // Show newest episodes from last 7 days
|
||||
enableTrending: false, // Show trending sections (currently stubs, order 32-33)
|
||||
|
||||
// DISCOVERY SECTIONS
|
||||
// Intelligent recommendations based on your library content
|
||||
// Includes:
|
||||
// - [Genre] Movies (random genres with sufficient movie count)
|
||||
// - Directed by [Director] (top directors from your library)
|
||||
// - Written by [Writer] (top writers from your library)
|
||||
// - Starring [Actor] (top actors from your library)
|
||||
// - Because you watched [Movie] (similar content based on watch history)
|
||||
// - Because you liked [Movie] (similar content based on favorites)
|
||||
enableDiscovery: true, // Enables discovery sections on the home screen
|
||||
|
||||
// Discovery section behavior and filtering
|
||||
enableInfiniteScroll: true, // Use infinite scroll vs Load More button
|
||||
minPeopleAppearances: 10, // Minimum movie appearances for people to be featured
|
||||
minGenreMovieCount: 50, // Minimum movie count for genres to be included
|
||||
minimumShowsForNetwork: 5, // Minimum show count for TV networks to be featured
|
||||
|
||||
// WATCHLIST SECTION
|
||||
// Requires watchlist script to be enabled
|
||||
enableWatchlist: true, // Show watchlist section on home screen
|
||||
|
||||
// SEASONAL SECTIONS
|
||||
// Holiday-themed content sections
|
||||
enableSeasonal: true, // Master toggle for seasonal sections
|
||||
seasonalItemLimit: 16, // Maximum items to show in seasonal sections
|
||||
|
||||
// CUSTOM SECTIONS
|
||||
// Add your own playlist/collection-based sections
|
||||
customSections: [
|
||||
// Add more custom sections here
|
||||
/* Example:
|
||||
{
|
||||
// Optionally provide a name, otherwise the name of the playlist/collection will be used
|
||||
name: 'Your Custom Section',
|
||||
|
||||
// The ID of the playlist/collection to display in the section, get this from Jellyfin playlist/collection URL
|
||||
id: 'acc84f03475eb51602b13cde158d21ad',
|
||||
|
||||
// The maximum number of items to display in the section on the home screen
|
||||
maxItems: 20,
|
||||
|
||||
// The order of the section for it to appear on the home screen
|
||||
order: 5
|
||||
},
|
||||
*/
|
||||
],
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// EXCLUSIVE ELSEWHERE CONFIGURATION
|
||||
// ============================================================================
|
||||
// Configure exclusive elsewhere branding behavior
|
||||
exclusiveElsewhere: {
|
||||
hideServerName: false // Set to true to hide server name, useful when you want to only show a logo or icon via CSS
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// SEARCH CONFIGURATION
|
||||
// ============================================================================
|
||||
// Configure search functionality
|
||||
search: {
|
||||
enableJellyseerr: false // Enable Jellyseerr integration for request functionality
|
||||
},
|
||||
|
||||
// ============================================================================
|
||||
// SKIN CONFIGURATION
|
||||
// ============================================================================
|
||||
// Configure additional skins available in the skin manager
|
||||
// These will be merged with skins from userConfig.js
|
||||
// Each skin's url field should be an array of objects with majorServerVersions and urls arrays
|
||||
// This allows you to specify different CSS bundles for different server versions
|
||||
// Each skin can also have colorSchemes array for color variations specific to that skin
|
||||
// Each skin should have an author field indicating who created the skin
|
||||
skins: [
|
||||
// Add additional skins here that will be available to all users
|
||||
// These are example skins - replace with your own or remove if not needed
|
||||
/* Example of adding more skins:
|
||||
{
|
||||
name: 'Custom Theme',
|
||||
author: 'username',
|
||||
url: [
|
||||
{
|
||||
majorServerVersions: [10, 11],
|
||||
urls: ['https://cdn.jsdelivr.net/gh/username/custom-theme.css']
|
||||
}
|
||||
],
|
||||
colorSchemes: []
|
||||
},
|
||||
{
|
||||
name: 'Multi-file Theme',
|
||||
author: 'username',
|
||||
url: [
|
||||
{
|
||||
majorServerVersions: [10, 11],
|
||||
urls: [
|
||||
'https://cdn.jsdelivr.net/gh/username/theme-base.css',
|
||||
'https://cdn.jsdelivr.net/gh/username/theme-extensions.css'
|
||||
]
|
||||
}
|
||||
],
|
||||
colorSchemes: [
|
||||
{
|
||||
name: 'Dark Blue',
|
||||
url: 'https://cdn.jsdelivr.net/gh/username/theme-dark-blue.css'
|
||||
},
|
||||
{
|
||||
name: 'Light Green',
|
||||
url: 'https://cdn.jsdelivr.net/gh/username/theme-light-green.css'
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
name: 'Version-Specific Theme',
|
||||
author: 'username',
|
||||
url: [
|
||||
{
|
||||
majorServerVersions: [10],
|
||||
urls: ['https://cdn.jsdelivr.net/gh/username/theme-v10.css']
|
||||
},
|
||||
{
|
||||
majorServerVersions: [11],
|
||||
urls: [
|
||||
'https://cdn.jsdelivr.net/gh/username/theme-v11.css',
|
||||
'https://cdn.jsdelivr.net/gh/username/theme-v11-fixes.css'
|
||||
]
|
||||
}
|
||||
],
|
||||
colorSchemes: []
|
||||
},
|
||||
*/
|
||||
],
|
||||
|
||||
// Default skin to use when no skin is selected
|
||||
// This overrides the default selection from userConfig.js
|
||||
defaultSkin: null, // Set to skin name (e.g., 'ElegantFin') or null to use userConfig default
|
||||
|
||||
|
||||
// ============================================================================
|
||||
// THEME CONFIGURATION
|
||||
// ============================================================================
|
||||
// Configure additional themes available in the theme manager
|
||||
// These will be merged with themes from userConfig.js
|
||||
// Each theme should have a name and URL pointing to a CSS file
|
||||
themes: [
|
||||
// Add additional themes here that will be available to all users
|
||||
// These are example themes - replace with your own or remove if not needed
|
||||
/* Example of adding more themes:
|
||||
{
|
||||
name: 'Custom Dark Theme',
|
||||
url: 'https://cdn.jsdelivr.net/gh/username/custom-dark-theme.css'
|
||||
},
|
||||
{
|
||||
name: 'Custom Light Theme',
|
||||
url: 'https://cdn.jsdelivr.net/gh/username/custom-light-theme.css'
|
||||
},
|
||||
*/
|
||||
],
|
||||
|
||||
// ============================================================================
|
||||
// CUSTOM MENU LINKS CONFIGURATION
|
||||
// ============================================================================
|
||||
// Configure custom menu links to be added to the custom menu
|
||||
customMenuLinks: [
|
||||
// Add your custom menu links here
|
||||
/* Example:
|
||||
{
|
||||
name: 'My Custom Link', // Display name for the menu item
|
||||
icon: 'link', // Material icon name (optional, defaults to 'link')
|
||||
url: '#/userpluginsettings.html?pageUrl=https://domain.com/custom-page', // URL to navigate to
|
||||
openInNewTab: false // Whether to open in new tab (optional, defaults to false)
|
||||
},
|
||||
{
|
||||
name: 'External Link',
|
||||
icon: 'open_in_new',
|
||||
url: 'https://example.com',
|
||||
openInNewTab: true
|
||||
},
|
||||
*/
|
||||
],
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// CONFIGURATION EXPOSURE
|
||||
// ============================================================================
|
||||
// Make configuration available to individual scripts
|
||||
window.KefinTweaksConfig = KEFIN_TWEAKS_CONFIG;
|
||||
|
||||
// ============================================================================
|
||||
// SCRIPT LOADER INITIALIZATION
|
||||
// ============================================================================
|
||||
// Load the injector script which handles loading individual scripts based on configuration
|
||||
const script = document.createElement("script");
|
||||
script.src = `${KEFIN_TWEAKS_CONFIG.kefinTweaksRoot}injector.js?v=${new Date().getTime()}`;
|
||||
script.async = true;
|
||||
document.head.appendChild(script);
|
||||
|
||||
console.log('[KefinTweaks] Central configuration loaded. Available at window.KefinTweaksConfig');
|
||||
})();
|
||||
|
||||
+383
-59
@@ -1,63 +1,387 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const KEFIN_TWEAKS_CONFIG = {
|
||||
kefinTweaksRoot: 'https://ranaldsgift.github.io/KefinTweaks/',
|
||||
scriptRoot: 'https://ranaldsgift.github.io/KefinTweaks/scripts/',
|
||||
|
||||
scripts: {
|
||||
collections: true,
|
||||
homeScreen: true,
|
||||
search: true,
|
||||
watchlist: true,
|
||||
headerTabs: true,
|
||||
customMenuLinks: true,
|
||||
breadcrumbs: true,
|
||||
playlist: true,
|
||||
itemDetailsCollections: true,
|
||||
flattenSingleSeasonShows: true,
|
||||
exclusiveElsewhere: false,
|
||||
backdropLeakFix: true,
|
||||
dashboardButtonFix: true,
|
||||
infiniteScroll: true,
|
||||
removeContinue: true,
|
||||
subtitleSearch: true,
|
||||
skinManager: true
|
||||
window.KefinTweaksConfig = {
|
||||
"kefinTweaksRoot": "",
|
||||
"scripts": {
|
||||
"homeScreen": true,
|
||||
"search": true,
|
||||
"watchlist": true,
|
||||
"headerTabs": true,
|
||||
"customMenuLinks": true,
|
||||
"breadcrumbs": true,
|
||||
"playlist": true,
|
||||
"itemDetailsCollections": true,
|
||||
"flattenSingleSeasonShows": true,
|
||||
"collections": true,
|
||||
"exclusiveElsewhere": false,
|
||||
"backdropLeakFix": true,
|
||||
"dashboardButtonFix": true,
|
||||
"infiniteScroll": true,
|
||||
"removeContinue": true,
|
||||
"subtitleSearch": true,
|
||||
"skinManager": true
|
||||
},
|
||||
"homeScreen": {
|
||||
"defaultItemLimit": 16,
|
||||
"defaultSortOrder": "Random",
|
||||
"defaultCardFormat": "Poster",
|
||||
"recentlyReleased": {
|
||||
"enabled": true,
|
||||
"order": 30,
|
||||
"movies": {
|
||||
"name": "Recently Released Movies",
|
||||
"enabled": true,
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "ReleaseDate",
|
||||
"sortOrderDirection": "Descending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 30
|
||||
},
|
||||
"episodes": {
|
||||
"name": "Recently Aired Episodes",
|
||||
"enabled": true,
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "PremiereDate",
|
||||
"sortOrderDirection": "Descending",
|
||||
"cardFormat": "Backdrop",
|
||||
"order": 31
|
||||
}
|
||||
},
|
||||
homeScreen: {
|
||||
enableNewAndTrending: true,
|
||||
enableNewMovies: true,
|
||||
enableNewEpisodes: true,
|
||||
enableTrending: false,
|
||||
enableDiscovery: true,
|
||||
enableInfiniteScroll: true,
|
||||
minPeopleAppearances: 10,
|
||||
minGenreMovieCount: 50,
|
||||
minimumShowsForNetwork: 5,
|
||||
enableWatchlist: true,
|
||||
enableSeasonal: true,
|
||||
seasonalItemLimit: 16,
|
||||
customSections: [],
|
||||
"trending": {
|
||||
"name": "Trending",
|
||||
"enabled": false,
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 32
|
||||
},
|
||||
exclusiveElsewhere: {
|
||||
hideServerName: false
|
||||
"popularTVNetworks": {
|
||||
"name": "Popular TV Networks",
|
||||
"enabled": true,
|
||||
"minimumShowsForNetwork": 5,
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 61
|
||||
},
|
||||
search: {
|
||||
enableJellyseerr: false
|
||||
"watchlist": {
|
||||
"name": "Watchlist",
|
||||
"enabled": true,
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "DateAdded",
|
||||
"sortOrderDirection": "Descending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 60
|
||||
},
|
||||
skins: [],
|
||||
defaultSkin: null,
|
||||
themes: [],
|
||||
customMenuLinks: [],
|
||||
};
|
||||
|
||||
window.KefinTweaksConfig = KEFIN_TWEAKS_CONFIG;
|
||||
|
||||
const script = document.createElement("script");
|
||||
script.src = `${KEFIN_TWEAKS_CONFIG.kefinTweaksRoot}injector.js?v=${new Date().getTime()}`;
|
||||
script.async = true;
|
||||
document.head.appendChild(script);
|
||||
|
||||
console.log('[KefinTweaks] Central configuration loaded. Available at window.KefinTweaksConfig');
|
||||
})();
|
||||
|
||||
"watchAgain": {
|
||||
"name": "Watch Again",
|
||||
"enabled": true,
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 62
|
||||
},
|
||||
"upcoming": {
|
||||
"name": "Upcoming",
|
||||
"enabled": true,
|
||||
"itemLimit": 48,
|
||||
"cardFormat": "Thumb",
|
||||
"order": 20
|
||||
},
|
||||
"imdbTop250": {
|
||||
"name": "IMDb Top 250",
|
||||
"enabled": true,
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 21
|
||||
},
|
||||
"seasonal": {
|
||||
"enabled": true,
|
||||
"defaultItemLimit": 16,
|
||||
"defaultSortOrder": "Random",
|
||||
"defaultCardFormat": "Poster",
|
||||
"seasons": [
|
||||
{
|
||||
"id": "halloween",
|
||||
"name": "Halloween",
|
||||
"enabled": true,
|
||||
"startDate": "10-01",
|
||||
"endDate": "10-31",
|
||||
"sections": [
|
||||
{
|
||||
"id": "halloween-tag",
|
||||
"enabled": true,
|
||||
"name": "Halloween Movies",
|
||||
"type": "Tag",
|
||||
"source": "halloween",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 50
|
||||
},
|
||||
{
|
||||
"id": "halloween-horror",
|
||||
"enabled": true,
|
||||
"name": "Horror Genre",
|
||||
"type": "Genre",
|
||||
"source": "Horror",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 51
|
||||
},
|
||||
{
|
||||
"id": "halloween-thriller",
|
||||
"enabled": true,
|
||||
"name": "Thriller Genre",
|
||||
"type": "Genre",
|
||||
"source": "Thriller",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 52
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "thanksgiving",
|
||||
"name": "Thanksgiving",
|
||||
"enabled": true,
|
||||
"startDate": "11-20",
|
||||
"endDate": "11-30",
|
||||
"order": 50,
|
||||
"sections": [
|
||||
{
|
||||
"id": "seasonal-2-section-0",
|
||||
"enabled": true,
|
||||
"name": "Thanksgiving Movies",
|
||||
"type": "Tag",
|
||||
"source": "thanksgiving",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 50,
|
||||
"spotlight": true,
|
||||
"discoveryEnabled": false,
|
||||
"searchTerm": "",
|
||||
"includeItemTypes": [
|
||||
"Movie"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "seasonal-2-section-1",
|
||||
"enabled": true,
|
||||
"name": "Thanksgiving Episodes",
|
||||
"type": "Parent",
|
||||
"source": "",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Thumb",
|
||||
"order": 51,
|
||||
"spotlight": false,
|
||||
"discoveryEnabled": false,
|
||||
"searchTerm": "thanksgiving",
|
||||
"includeItemTypes": [
|
||||
"Episode"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "christmas",
|
||||
"name": "Christmas",
|
||||
"enabled": true,
|
||||
"startDate": "12-01",
|
||||
"endDate": "12-31",
|
||||
"sections": [
|
||||
{
|
||||
"id": "christmas-genre",
|
||||
"enabled": true,
|
||||
"name": "Christmas Movies",
|
||||
"type": "Genre",
|
||||
"source": "Christmas",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 60
|
||||
},
|
||||
{
|
||||
"id": "christmas-family",
|
||||
"enabled": true,
|
||||
"name": "Family Movies",
|
||||
"type": "Genre",
|
||||
"source": "Family",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"order": 61
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"discovery": {
|
||||
"enabled": true,
|
||||
"infiniteScroll": true,
|
||||
"minPeopleAppearances": 10,
|
||||
"minGenreMovieCount": 50,
|
||||
"defaultItemLimit": 16,
|
||||
"defaultSortOrder": "Random",
|
||||
"defaultCardFormat": "Poster",
|
||||
"sectionTypes": {
|
||||
"spotlightGenre": {
|
||||
"enabled": true,
|
||||
"name": "Top Rated [Genre] Movies",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"spotlightNetwork": {
|
||||
"enabled": true,
|
||||
"name": "Top Rated Shows from [Studio]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"genreMovies": {
|
||||
"enabled": true,
|
||||
"name": "[Genre] Movies",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"studioShows": {
|
||||
"enabled": true,
|
||||
"name": "Shows from [Studio]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"collections": {
|
||||
"enabled": true,
|
||||
"name": "[Collection Name]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster",
|
||||
"minimumItems": 10
|
||||
},
|
||||
"becauseYouWatched": {
|
||||
"enabled": true,
|
||||
"name": "Because you watched [Movie]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"becauseYouLiked": {
|
||||
"enabled": true,
|
||||
"name": "Because you liked [Movie]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"starringTopActor": {
|
||||
"enabled": true,
|
||||
"name": "Starring [Actor]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"directedByTopDirector": {
|
||||
"enabled": true,
|
||||
"name": "Directed by [Director]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"writtenByTopWriter": {
|
||||
"enabled": true,
|
||||
"name": "Written by [Writer]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"becauseYouRecentlyWatched": {
|
||||
"enabled": true,
|
||||
"name": "Because you recently watched [Movie]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"starringActorRecentlyWatched": {
|
||||
"enabled": true,
|
||||
"name": "Starring [Actor] because you recently watched [Movie]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"directedByDirectorRecentlyWatched": {
|
||||
"enabled": true,
|
||||
"name": "Directed by [Director] because you recently watched [Movie]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
},
|
||||
"writtenByWriterRecentlyWatched": {
|
||||
"enabled": true,
|
||||
"name": "Written by [Writer] because you recently watched [Movie]",
|
||||
"itemLimit": 16,
|
||||
"sortOrder": "Random",
|
||||
"sortOrderDirection": "Ascending",
|
||||
"cardFormat": "Poster"
|
||||
}
|
||||
},
|
||||
"spotlightDiscoveryChance": 0.5,
|
||||
"spotlight": {
|
||||
"autoPlay": true,
|
||||
"interval": 5000,
|
||||
"showDots": true,
|
||||
"showNavButtons": true,
|
||||
"showClearArt": true
|
||||
},
|
||||
"randomizeOrder": false
|
||||
},
|
||||
"customSections": []
|
||||
},
|
||||
"exclusiveElsewhere": {
|
||||
"hideServerName": false
|
||||
},
|
||||
"search": {
|
||||
"enableJellyseerr": false
|
||||
},
|
||||
"skins": [
|
||||
{
|
||||
"name": "Default",
|
||||
"author": "Jellyfin",
|
||||
"url": null,
|
||||
"colorSchemes": [],
|
||||
"enabled": true,
|
||||
"hidden": true
|
||||
}
|
||||
],
|
||||
"defaultSkin": null,
|
||||
"themes": [],
|
||||
"customMenuLinks": []
|
||||
};
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 29 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.9 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 1.2 MiB |
+21
-22
@@ -45,8 +45,12 @@
|
||||
return new Promise((resolve, reject) => {
|
||||
try {
|
||||
const defaultConfigUrl = window.KefinTweaksConfig?.kefinTweaksRoot
|
||||
? `${window.KefinTweaksConfig.kefinTweaksRoot}kefinTweaks-default-config.js`
|
||||
: 'https://ranaldsgift.github.io/KefinTweaks/kefinTweaks-default-config.js';
|
||||
? `${window.KefinTweaksConfig.kefinTweaksRoot}kefinTweaks-default-config.js`;
|
||||
|
||||
if (!defaultConfigUrl) {
|
||||
reject(new Error('No default config URL found'));
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if already loaded
|
||||
if (window.KefinTweaksDefaultConfig) {
|
||||
@@ -115,9 +119,8 @@
|
||||
|
||||
const currentConfigSource = currentLoadedConfig || window.KefinTweaksCurrentConfig || window.KefinTweaksConfig || {};
|
||||
const currentKefinRoot = currentConfigSource.kefinTweaksRoot || defaultConfig.kefinTweaksRoot;
|
||||
const currentScriptRoot = currentConfigSource.scriptRoot || defaultConfig.scriptRoot;
|
||||
defaultConfig.kefinTweaksRoot = currentKefinRoot;
|
||||
defaultConfig.scriptRoot = currentScriptRoot;
|
||||
// Note: scriptRoot is no longer used - scripts are loaded from kefinTweaksRoot + '/scripts/'
|
||||
|
||||
// Save defaults to JS Injector for future use
|
||||
await saveConfigToJavaScriptInjector(defaultConfig);
|
||||
@@ -132,8 +135,7 @@
|
||||
console.error('[KefinTweaks Configuration] Error loading default config as fallback:', fallbackError);
|
||||
// Return empty config structure as last resort
|
||||
return {
|
||||
kefinTweaksRoot: 'https://ranaldsgift.github.io/KefinTweaks/',
|
||||
scriptRoot: 'https://ranaldsgift.github.io/KefinTweaks/scripts/',
|
||||
kefinTweaksRoot: '',
|
||||
scripts: {},
|
||||
homeScreen: {},
|
||||
exclusiveElsewhere: {},
|
||||
@@ -361,10 +363,10 @@
|
||||
|
||||
const modal = window.ModalSystem.create({
|
||||
id: 'scriptRootEditConfirmation',
|
||||
title: 'Edit Script Root URLs',
|
||||
title: 'Edit KefinTweaks Root URL',
|
||||
content: `
|
||||
<div class="listItemBodyText" style="margin-bottom: 1em; max-width: 600px;">
|
||||
Editing the Root URLs is useful if you are hosting the scripts yourself or if you want to use a specific KefinTweaks version. There is no validation done for the URLs provided for these settings so please ensure they are valid. In any case, you can easily revert these settings.
|
||||
Editing the Root URL is useful if you are hosting the scripts yourself or if you want to use a specific KefinTweaks version. Scripts will be loaded from this root URL + '/scripts/'. There is no validation done for the URL provided so please ensure it is valid. In any case, you can easily revert this setting.
|
||||
</div>
|
||||
`,
|
||||
footer: `
|
||||
@@ -417,8 +419,8 @@
|
||||
<div class="listItem" style="border-bottom: 1px solid rgba(255,255,255,0.1); padding-bottom: 1em; margin-bottom: 1em;">
|
||||
<div class="listItemContent" style="display: flex; justify-content: space-between; align-items: center;">
|
||||
<div>
|
||||
<h3 class="listItemBodyText" style="margin-bottom: 0.25em;">Script Root Configuration</h3>
|
||||
<div class="listItemBodyText secondary">Configure where KefinTweaks scripts are loaded from</div>
|
||||
<h3 class="listItemBodyText" style="margin-bottom: 0.25em;">KefinTweaks Root Configuration</h3>
|
||||
<div class="listItemBodyText secondary">Configure where KefinTweaks scripts are loaded from. Scripts will be loaded from this root URL + '/scripts/'</div>
|
||||
</div>
|
||||
<button class="emby-button raised paper-icon-button-light" id="editScriptRootBtn">
|
||||
<span class="material-icons" aria-hidden="true">edit</span>
|
||||
@@ -429,17 +431,10 @@
|
||||
<div class="listItem">
|
||||
<div class="listItemContent">
|
||||
<div class="listItemBodyText" style="margin-bottom: 0.5em;">KefinTweaks Root URL</div>
|
||||
<input type="text" id="kefinTweaksRoot" class="fld emby-input" value="${config.kefinTweaksRoot || ''}" placeholder="https://ranaldsgift.github.io/KefinTweaks/" style="width: 100%; max-width: 600px;">
|
||||
<div class="listItemBodyText secondary" style="margin-top: 0.5em; font-size: 0.9em;">Base URL for KefinTweaks resources</div>
|
||||
<input type="text" id="kefinTweaksRoot" class="fld emby-input" value="${config.kefinTweaksRoot || ''}" placeholder="https://cdn.jsdelivr.net/gh/ranaldsgift/KefinTweaks@latest/" style="width: 100%; max-width: 600px;">
|
||||
<div class="listItemBodyText secondary" style="margin-top: 0.5em; font-size: 0.9em;">Base URL for KefinTweaks resources. Scripts will be loaded from this URL + '/scripts/'</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="listItem">
|
||||
<div class="listItemContent">
|
||||
<div class="listItemBodyText" style="margin-bottom: 0.5em;">Script Root URL</div>
|
||||
<input type="text" id="scriptRoot" class="fld emby-input" value="${config.scriptRoot || ''}" placeholder="https://ranaldsgift.github.io/KefinTweaks/scripts/" style="width: 100%; max-width: 600px;">
|
||||
<div class="listItemBodyText secondary" style="margin-top: 0.5em; font-size: 0.9em;">URL where individual script files are located</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4138,7 +4133,6 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
|
||||
// Collect all form values
|
||||
const config = {
|
||||
kefinTweaksRoot: document.getElementById('kefinTweaksRoot')?.value || '',
|
||||
scriptRoot: document.getElementById('scriptRoot')?.value || '',
|
||||
scripts: {},
|
||||
homeScreen: {},
|
||||
exclusiveElsewhere: {},
|
||||
@@ -4148,6 +4142,11 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
|
||||
themes: [],
|
||||
customMenuLinks: []
|
||||
};
|
||||
|
||||
// Remove scriptRoot if it exists (legacy field, no longer used)
|
||||
if (config.scriptRoot) {
|
||||
delete config.scriptRoot;
|
||||
}
|
||||
|
||||
// Collect script toggles
|
||||
document.querySelectorAll('[data-script-key]').forEach(checkbox => {
|
||||
@@ -4435,10 +4434,10 @@ window.KefinTweaksConfig = ${JSON.stringify(config, null, 2)};`;
|
||||
try {
|
||||
const defaultConfig = await loadDefaultConfig();
|
||||
|
||||
// Retain script URLs from existing config
|
||||
// Retain kefinTweaksRoot from existing config
|
||||
const existingConfig = await getKefinTweaksConfig();
|
||||
defaultConfig.kefinTweaksRoot = existingConfig.kefinTweaksRoot;
|
||||
defaultConfig.scriptRoot = existingConfig.scriptRoot;
|
||||
// Note: scriptRoot is no longer used - scripts are loaded from kefinTweaksRoot + '/scripts/'
|
||||
|
||||
await saveConfigToJavaScriptInjector(defaultConfig);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user