del old files
This commit is contained in:
44
config.yaml
44
config.yaml
@@ -1,7 +1,39 @@
|
|||||||
# config for Jellyfin file modificator for customization
|
# Zielverzeichnis für Operationen
|
||||||
start_directory: '.' # Startverzeichnis für die Suche
|
destination_directory: './'
|
||||||
|
|
||||||
modifications:
|
# Kopierregeln
|
||||||
|
copy_rules:
|
||||||
|
- sources:
|
||||||
|
- source: './img/icon-transparent.png'
|
||||||
|
target: './assets/img/icon-transparent.png'
|
||||||
|
- source: './img/banner-light.png'
|
||||||
|
target: './assets/img/banner-light.png'
|
||||||
|
- source: './img/banner-dark.png'
|
||||||
|
target: './assets/img/banner-dark.png'
|
||||||
|
|
||||||
|
- source: './img/bc8d51405ec040305a87.ico'
|
||||||
|
target: './bc8d51405ec040305a87.ico'
|
||||||
|
- source: './img/favicon.ico'
|
||||||
|
target: './favicon.ico'
|
||||||
|
|
||||||
|
mode: 'replace' # Überschreibt vorhandene Dateien/Ordner
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
- sources:
|
||||||
|
- './seasonal'
|
||||||
|
- './ui'
|
||||||
|
|
||||||
|
- source: './img/background.png'
|
||||||
|
target: './assets/img/background.png'
|
||||||
|
- source: './img/favicon.png'
|
||||||
|
target: './assets/img/favicon.png'
|
||||||
|
- source: './img/logo.png'
|
||||||
|
target: './assets/img/logo.png'
|
||||||
|
mode: 'copy' # Kopiert Dateien/Ordner
|
||||||
|
|
||||||
|
# Modifikationsregeln
|
||||||
|
modification_rules:
|
||||||
- file_pattern: 'session-login-index-html..*.bundle.js'
|
- file_pattern: 'session-login-index-html..*.bundle.js'
|
||||||
insert_rules:
|
insert_rules:
|
||||||
- after_text: '<div class="padded-left padded-right padded-bottom-page margin-auto-y">'
|
- after_text: '<div class="padded-left padded-right padded-bottom-page margin-auto-y">'
|
||||||
@@ -10,6 +42,11 @@ modifications:
|
|||||||
# Instancename, Jellyseer I-Frame
|
# Instancename, Jellyseer I-Frame
|
||||||
- file_pattern: 'index.html'
|
- file_pattern: 'index.html'
|
||||||
insert_rules:
|
insert_rules:
|
||||||
|
# Seasonals
|
||||||
|
#MARK: NEED MODIFIKATION
|
||||||
|
- before_text: '</body>'
|
||||||
|
insert_text: '<div class="seasonals-container"></div><script src="seasonals.js"></script><link rel="stylesheet" href="seasonals.css">'
|
||||||
|
|
||||||
# Page title and requests tab
|
# Page title and requests tab
|
||||||
- before_text: '<link href=".*" rel="stylesheet">'
|
- before_text: '<link href=".*" rel="stylesheet">'
|
||||||
insert_text: >
|
insert_text: >
|
||||||
@@ -82,4 +119,3 @@ modifications:
|
|||||||
# request tab on main page
|
# request tab on main page
|
||||||
- after_text: 'id="favoritesTab" data-index="1"> <div class="sections"></div> </div>'
|
- after_text: 'id="favoritesTab" data-index="1"> <div class="sections"></div> </div>'
|
||||||
insert_text: '<div class="tabContent pageTabContent" id="requestsTab" data-index="2"> <div class="sections"><iframe class="requestIframe" src="https://jellyseerr.mahom03-spacecloud.de"></iframe></div> </div>'
|
insert_text: '<div class="tabContent pageTabContent" id="requestsTab" data-index="2"> <div class="sections"><iframe class="requestIframe" src="https://jellyseerr.mahom03-spacecloud.de"></iframe></div> </div>'
|
||||||
|
|
||||||
|
@@ -1,121 +0,0 @@
|
|||||||
# Zielverzeichnis für Operationen
|
|
||||||
destination_directory: './'
|
|
||||||
|
|
||||||
# Kopierregeln
|
|
||||||
copy_rules:
|
|
||||||
- sources:
|
|
||||||
- source: './img/icon-transparent.png'
|
|
||||||
target: './assets/img/icon-transparent.png'
|
|
||||||
- source: './img/banner-light.png'
|
|
||||||
target: './assets/img/banner-light.png'
|
|
||||||
- source: './img/banner-dark.png'
|
|
||||||
target: './assets/img/banner-dark.png'
|
|
||||||
|
|
||||||
- source: './img/bc8d51405ec040305a87.ico'
|
|
||||||
target: './bc8d51405ec040305a87.ico'
|
|
||||||
- source: './img/favicon.ico'
|
|
||||||
target: './favicon.ico'
|
|
||||||
|
|
||||||
mode: 'replace' # Überschreibt vorhandene Dateien/Ordner
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- sources:
|
|
||||||
- './seasonal'
|
|
||||||
- './ui'
|
|
||||||
|
|
||||||
- source: './img/background.png'
|
|
||||||
target: './assets/img/background.png'
|
|
||||||
- source: './img/favicon.png'
|
|
||||||
target: './assets/img/favicon.png'
|
|
||||||
- source: './img/logo.png'
|
|
||||||
target: './assets/img/logo.png'
|
|
||||||
mode: 'copy' # Kopiert Dateien/Ordner
|
|
||||||
|
|
||||||
# Modifikationsregeln
|
|
||||||
modification_rules:
|
|
||||||
- file_pattern: 'session-login-index-html..*.bundle.js'
|
|
||||||
insert_rules:
|
|
||||||
- after_text: '<div class="padded-left padded-right padded-bottom-page margin-auto-y">'
|
|
||||||
insert_text: '<img id="login-logo" src="/web/assets/img/banner-dark.png" width=350px style="padding: 0px;display:block; margin-left: auto; margin-right: auto;">'
|
|
||||||
|
|
||||||
# Instancename, Jellyseer I-Frame
|
|
||||||
- file_pattern: 'index.html'
|
|
||||||
insert_rules:
|
|
||||||
# Seasonals
|
|
||||||
#MARK: NEED MODIFIKATION
|
|
||||||
- before_text: '</body>'
|
|
||||||
insert_text: '<div class="seasonals-container"></div><script src="seasonals.js"></script><link rel="stylesheet" href="seasonals.css">'
|
|
||||||
|
|
||||||
# Page title and requests tab
|
|
||||||
- before_text: '<link href=".*" rel="stylesheet">'
|
|
||||||
insert_text: >
|
|
||||||
<script>
|
|
||||||
document.addEventListener("DOMContentLoaded", function () {
|
|
||||||
// Check if the title is "Jellyfin" before changing it
|
|
||||||
if (document.title === "Jellyfin") {
|
|
||||||
document.title = "SpaceCloud - Cinema";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a MutationObserver to prevent any changes to the title
|
|
||||||
const observer = new MutationObserver(function (mutations) {
|
|
||||||
mutations.forEach(function (mutation) {
|
|
||||||
if (mutation.type === 'childList') {
|
|
||||||
// Only change the title if it's set to "Jellyfin"
|
|
||||||
if (document.title === "Jellyfin") {
|
|
||||||
document.title = "SpaceCloud - Cinema";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Observe the document title for changes
|
|
||||||
observer.observe(document.querySelector('title'), { childList: true });
|
|
||||||
|
|
||||||
// Set up a fallback in case of attempts to change the title through direct assignment
|
|
||||||
Object.defineProperty(document, 'title', {
|
|
||||||
set: function (value) {
|
|
||||||
// Only allow the title to change if the new value is "Jellyfin"
|
|
||||||
if (value === "Jellyfin") {
|
|
||||||
document.querySelector('title').textContent = "SpaceCloud - Cinema";
|
|
||||||
} else {
|
|
||||||
document.querySelector('title').textContent = value;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
get: function () {
|
|
||||||
return document.querySelector('title').textContent;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script>const createRequestTab = () => {const title = document.createElement("div");title.classList.add("emby-button-foreground");title.innerText = "Anfragen";const button = document.createElement("button");button.type = "button";button.is = "empty-button";button.classList.add("emby-tab-button", "emby-button", "lastFocused");button.setAttribute("data-index", "2");button.setAttribute("id", "requestTab");button.appendChild(title);(function e() {const tabb = document.querySelector(".emby-tabs-slider");tabb ? !document.querySelector("#requestTab") && tabb.appendChild(button) : setTimeout(e, 500)})();}</script>
|
|
||||||
|
|
||||||
replace_rules:
|
|
||||||
# Page title
|
|
||||||
- old_text: '<title>Jellyfin</title>'
|
|
||||||
new_text: '<title>SpaceCloud - Cinema</title>'
|
|
||||||
|
|
||||||
# Instancename, Jellyseer I-Frame
|
|
||||||
- file_pattern: 'main.jellyfin.bundle.js'
|
|
||||||
replace_rules:
|
|
||||||
# Set limit on how many days items should be in the next up section (last number)
|
|
||||||
- old_text: 't("maxDaysForNextUp",e.toString(),!1);var t=parseInt(this.get("maxDaysForNextUp",!1),10);return 0===t?0:t||365}}'
|
|
||||||
new_text: 't("maxDaysForNextUp",e.toString(),!1);var t=parseInt(this.get("maxDaysForNextUp",!1),10);return 0===t?0:t||28}}'
|
|
||||||
# Default user page size (last number), 99 fits perfect on most desktops
|
|
||||||
- old_text: 'this.get("libraryPageSize",!1),10);return 0===t?0:t||100}'
|
|
||||||
new_text: 'this.get("libraryPageSize",!1),10);return 0===t?0:t||99}'
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
- file_pattern: 'home-html..*.chunk.js'
|
|
||||||
insert_rules:
|
|
||||||
# featured iframe and requests iframe style
|
|
||||||
- after_text: 'data-backdroptype="movie,series,book">'
|
|
||||||
insert_text: >
|
|
||||||
<style> .featurediframe {width: 95vw; height: 24em; display: block; border: 0; margin: -1em auto 0;} @media (min-width: 2100px) {.featurediframe {height: 33em;}} @media (max-width: 1599px) {.featurediframe {margin-top: 1.2em;}} @media (max-width: 800px) {.featurediframe {margin-top: 0.8em; height: 25em;}} </style> <iframe class="featurediframe" src="/web/ui/spotlight.html"></iframe>
|
|
||||||
<style>:root { --save-gut: max(env(safe-area-inset-left), .3%) } .requestIframe { margin: 0 .4em; padding: 0 var(--save-gut); width: calc(100% - (.4em * 2) - (var(--save-gut) * 2)); height: 90vh; border: none; position: absolute; top: 5.3em } @media (max-width: 1599px) { .requestIframe { height: 83vh; top: 8.2em; } }</style><script>setTimeout(() => { createRequestTab() }, 500)</script>
|
|
||||||
|
|
||||||
# request tab on main page
|
|
||||||
- after_text: 'id="favoritesTab" data-index="1"> <div class="sections"></div> </div>'
|
|
||||||
insert_text: '<div class="tabContent pageTabContent" id="requestsTab" data-index="2"> <div class="sections"><iframe class="requestIframe" src="https://jellyseerr.mahom03-spacecloud.de"></iframe></div> </div>'
|
|
@@ -1,229 +0,0 @@
|
|||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
import yaml
|
|
||||||
import shutil
|
|
||||||
import glob
|
|
||||||
|
|
||||||
def load_configuration(config_path):
|
|
||||||
"""
|
|
||||||
Load configuration from a YAML file.
|
|
||||||
"""
|
|
||||||
with open(config_path, 'r', encoding='utf-8') as config_file:
|
|
||||||
return yaml.safe_load(config_file)
|
|
||||||
|
|
||||||
def copy_with_mode(src, dest, mode='copy'):
|
|
||||||
"""
|
|
||||||
Copy files or directories with different modes and specific source/target paths.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# Ensure full paths are used
|
|
||||||
src = os.path.abspath(src)
|
|
||||||
dest = os.path.abspath(dest)
|
|
||||||
|
|
||||||
# Ensure destination directory exists
|
|
||||||
os.makedirs(os.path.dirname(dest), exist_ok=True)
|
|
||||||
|
|
||||||
# Determine copy mode
|
|
||||||
if mode == 'copy':
|
|
||||||
# Skip if destination already exists
|
|
||||||
if os.path.exists(dest):
|
|
||||||
print(f'Skipping {src}: Destination already exists')
|
|
||||||
return False
|
|
||||||
|
|
||||||
elif mode == 'replace':
|
|
||||||
# Remove existing destination before copying
|
|
||||||
if os.path.exists(dest):
|
|
||||||
if os.path.isdir(dest):
|
|
||||||
shutil.rmtree(dest)
|
|
||||||
else:
|
|
||||||
os.remove(dest)
|
|
||||||
|
|
||||||
elif mode == 'update':
|
|
||||||
# Only copy if source is newer
|
|
||||||
if os.path.exists(dest):
|
|
||||||
src_mtime = os.path.getmtime(src)
|
|
||||||
dest_mtime = os.path.getmtime(dest)
|
|
||||||
if src_mtime <= dest_mtime:
|
|
||||||
print(f'Skipping {src}: Destination is up to date')
|
|
||||||
return False
|
|
||||||
|
|
||||||
# Perform copy
|
|
||||||
if os.path.isdir(src):
|
|
||||||
shutil.copytree(src, dest)
|
|
||||||
else:
|
|
||||||
shutil.copy2(src, dest)
|
|
||||||
|
|
||||||
print(f'Copied: {src} -> {dest}')
|
|
||||||
return True
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f'Error copying {src}: {e}')
|
|
||||||
return False
|
|
||||||
|
|
||||||
def matches_file_pattern(filename, pattern):
|
|
||||||
"""
|
|
||||||
Check if filename matches the given pattern.
|
|
||||||
"""
|
|
||||||
return re.search(pattern, filename) is not None
|
|
||||||
|
|
||||||
def apply_insert_rules(content, insert_rules):
|
|
||||||
"""
|
|
||||||
Apply insertion rules to the content.
|
|
||||||
"""
|
|
||||||
modified_content = content
|
|
||||||
modified = False
|
|
||||||
|
|
||||||
for rule in insert_rules:
|
|
||||||
insert_text = rule.get('insert_text')
|
|
||||||
|
|
||||||
# Insert after specific text
|
|
||||||
if 'after_text' in rule:
|
|
||||||
search_text = rule.get('after_text')
|
|
||||||
if insert_text not in modified_content:
|
|
||||||
modified_content = modified_content.replace(
|
|
||||||
search_text,
|
|
||||||
f'{search_text}\n{insert_text}'
|
|
||||||
)
|
|
||||||
modified = True
|
|
||||||
|
|
||||||
# Insert before specific text
|
|
||||||
elif 'before_text' in rule:
|
|
||||||
search_text = rule.get('before_text')
|
|
||||||
if insert_text not in modified_content:
|
|
||||||
modified_content = modified_content.replace(
|
|
||||||
search_text,
|
|
||||||
f'{insert_text}\n{search_text}'
|
|
||||||
)
|
|
||||||
modified = True
|
|
||||||
|
|
||||||
return modified_content, modified
|
|
||||||
|
|
||||||
def apply_replace_rules(content, replace_rules):
|
|
||||||
"""
|
|
||||||
Apply replacement rules to the content.
|
|
||||||
"""
|
|
||||||
modified_content = content
|
|
||||||
modified = False
|
|
||||||
|
|
||||||
for rule in replace_rules:
|
|
||||||
old_text = rule.get('old_text')
|
|
||||||
new_text = rule.get('new_text')
|
|
||||||
|
|
||||||
# Replace text if found
|
|
||||||
if old_text in modified_content:
|
|
||||||
modified_content = modified_content.replace(old_text, new_text)
|
|
||||||
modified = True
|
|
||||||
|
|
||||||
return modified_content, modified
|
|
||||||
|
|
||||||
def process_copy_and_modify_rules(config):
|
|
||||||
"""
|
|
||||||
Process copy, insertion, and replacement rules.
|
|
||||||
"""
|
|
||||||
successful_operations = {
|
|
||||||
'copies': 0,
|
|
||||||
'modifications': 0
|
|
||||||
}
|
|
||||||
|
|
||||||
# Process copy rules
|
|
||||||
for copy_rule in config.get('copy_rules', []):
|
|
||||||
sources = copy_rule.get('sources', [])
|
|
||||||
mode = copy_rule.get('mode', 'copy')
|
|
||||||
|
|
||||||
for source_info in sources:
|
|
||||||
# Support both simple string and dictionary input
|
|
||||||
if isinstance(source_info, str):
|
|
||||||
src = source_info
|
|
||||||
dest = os.path.join(
|
|
||||||
config.get('destination_directory', '.'),
|
|
||||||
os.path.basename(src)
|
|
||||||
)
|
|
||||||
elif isinstance(source_info, dict):
|
|
||||||
src = source_info.get('source')
|
|
||||||
dest = source_info.get('target')
|
|
||||||
|
|
||||||
# Fallback if target is not specified
|
|
||||||
if not dest:
|
|
||||||
dest = os.path.join(
|
|
||||||
config.get('destination_directory', '.'),
|
|
||||||
os.path.basename(src)
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print(f'Invalid source configuration: {source_info}')
|
|
||||||
continue
|
|
||||||
|
|
||||||
# Expand potential wildcards
|
|
||||||
matching_sources = glob.glob(src)
|
|
||||||
|
|
||||||
for matched_src in matching_sources:
|
|
||||||
# Determine full destination path
|
|
||||||
if os.path.isdir(matched_src):
|
|
||||||
full_dest = os.path.join(dest, os.path.basename(matched_src))
|
|
||||||
else:
|
|
||||||
full_dest = dest
|
|
||||||
|
|
||||||
# Perform copy
|
|
||||||
if copy_with_mode(matched_src, full_dest, mode):
|
|
||||||
successful_operations['copies'] += 1
|
|
||||||
|
|
||||||
# Process modification rules
|
|
||||||
destination_dir = config.get('destination_directory', '.')
|
|
||||||
|
|
||||||
for mod_rule in config.get('modification_rules', []):
|
|
||||||
search_pattern = mod_rule.get('file_pattern')
|
|
||||||
insert_rules = mod_rule.get('insert_rules', [])
|
|
||||||
replace_rules = mod_rule.get('replace_rules', [])
|
|
||||||
|
|
||||||
# Walk through destination directory
|
|
||||||
for root, _, files in os.walk(destination_dir):
|
|
||||||
for filename in files:
|
|
||||||
# Check if file matches pattern
|
|
||||||
if matches_file_pattern(filename, search_pattern):
|
|
||||||
full_path = os.path.join(root, filename)
|
|
||||||
|
|
||||||
try:
|
|
||||||
# Read file content
|
|
||||||
with open(full_path, 'r', encoding='utf-8') as file:
|
|
||||||
content = file.read()
|
|
||||||
|
|
||||||
# Apply insert rules
|
|
||||||
content_after_insert, insert_modified = apply_insert_rules(
|
|
||||||
content, insert_rules
|
|
||||||
)
|
|
||||||
|
|
||||||
# Apply replace rules
|
|
||||||
final_content, replace_modified = apply_replace_rules(
|
|
||||||
content_after_insert, replace_rules
|
|
||||||
)
|
|
||||||
|
|
||||||
# Save modified file
|
|
||||||
if insert_modified or replace_modified:
|
|
||||||
with open(full_path, 'w', encoding='utf-8') as file:
|
|
||||||
file.write(final_content)
|
|
||||||
|
|
||||||
successful_operations['modifications'] += 1
|
|
||||||
print(f'Modified: {full_path}')
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
print(f'Error processing file {full_path}: {e}')
|
|
||||||
|
|
||||||
return successful_operations
|
|
||||||
|
|
||||||
def main():
|
|
||||||
# Check command-line argument
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print("Please provide the path to the configuration file.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
config_path = sys.argv[1]
|
|
||||||
|
|
||||||
# Load configuration and process rules
|
|
||||||
config = load_configuration(config_path)
|
|
||||||
results = process_copy_and_modify_rules(config)
|
|
||||||
|
|
||||||
print(f'\nTotal successful copies: {results["copies"]}')
|
|
||||||
print(f'Total file modifications: {results["modifications"]}')
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
main()
|
|
Reference in New Issue
Block a user