mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 01:01:24 +00:00
Merge pull request #1806 from NNTmux/2025-10-31-qlqw-eb87e
Refactor JavaScript functionality for improved performance and mainta…
This commit is contained in:
+29
-3
@@ -3,6 +3,7 @@ config.php
|
||||
docker/.zsh_history
|
||||
docker/composer-auth.json
|
||||
docker/php-overrides.local.ini
|
||||
docker-compose.yml
|
||||
docker-compose.override.yml
|
||||
.env
|
||||
install.lock
|
||||
@@ -20,7 +21,21 @@ test.php
|
||||
|
||||
/.idea/
|
||||
/vendor/*
|
||||
/storage/covers/*
|
||||
# Ignore all files in covers directories but keep folder structure
|
||||
# This includes symlinks - Git treats symlinks as files, so they're automatically ignored
|
||||
/storage/covers/**/*
|
||||
!/storage/covers/**/
|
||||
!/storage/covers/**/.gitignore
|
||||
!/storage/covers/**/no-cover.jpg
|
||||
!/storage/covers/**/no-backdrop.jpg
|
||||
/public/covers/**/*
|
||||
!/public/covers/**/
|
||||
!/public/covers/**/.gitignore
|
||||
!/public/covers/**/no-cover.jpg
|
||||
!/public/covers/**/no-backdrop.jpg
|
||||
|
||||
# Ignore symlinks in public/storage that point to storage/covers
|
||||
/public/storage/covers
|
||||
/storage/nzb/*
|
||||
/resources/tmp/*
|
||||
!/resources/tmp/unrar/
|
||||
@@ -28,8 +43,8 @@ test.php
|
||||
!/resources/tmp/imdb_cache/
|
||||
!/public/assets/*
|
||||
|
||||
# Ignore Vite build manifest (regenerated locally)
|
||||
/public/build/manifest.json
|
||||
# Ignore Vite build output (regenerated locally)
|
||||
/public/build/
|
||||
|
||||
# Logs
|
||||
npm-debug.log*
|
||||
@@ -44,3 +59,14 @@ node_modules/
|
||||
.vscode-test
|
||||
|
||||
/.phpunit.cache
|
||||
phpunit.xml.back
|
||||
|
||||
# IDE helper files (generated locally)
|
||||
_ide_helper.php
|
||||
|
||||
# Lock files (generated locally, should not be committed)
|
||||
*-lock
|
||||
composer.lock
|
||||
package-lock.json
|
||||
yarn.lock
|
||||
pnpm-lock.yaml
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="./bootstrap/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||
<coverage>
|
||||
<include>
|
||||
<directory suffix=".php">Blacklight</directory>
|
||||
<directory suffix=".php">app</directory>
|
||||
</include>
|
||||
<report>
|
||||
<clover outputFile="tests/build/logs/clover.xml"/>
|
||||
</report>
|
||||
</coverage>
|
||||
<testsuites>
|
||||
<testsuite name="Install">
|
||||
<directory suffix="Test.php">tests/Install</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Unit">
|
||||
<directory suffix="Test.php">tests/Unit</directory>
|
||||
</testsuite>
|
||||
<testsuite name="Feature">
|
||||
<directory suffix="Test.php">tests/Feature</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<php>
|
||||
<env name="APP_ENV" value="testing"/>
|
||||
<env name="BCRYPT_ROUNDS" value="4"/>
|
||||
<env name="CACHE_DRIVER" value="array"/>
|
||||
<env name="SESSION_DRIVER" value="array"/>
|
||||
<env name="QUEUE_DRIVER" value="sync"/>
|
||||
<env name="MAIL_DRIVER" value="array"/>
|
||||
</php>
|
||||
<logging/>
|
||||
</phpunit>
|
||||
+24
-7
@@ -4,17 +4,34 @@ import './bootstrap';
|
||||
import '../css/csp-safe.css';
|
||||
import './csp-safe.js';
|
||||
|
||||
// Theme initialization - must run early to prevent flash
|
||||
// Theme initialization - optimized to prevent flash of unstyled content
|
||||
(function() {
|
||||
const themePreference = document.querySelector('meta[name="theme-preference"]')?.content || 'light';
|
||||
'use strict';
|
||||
// Use requestAnimationFrame for better performance
|
||||
const applyTheme = function() {
|
||||
const metaTheme = document.querySelector('meta[name="theme-preference"]');
|
||||
const themePreference = metaTheme?.content || 'light';
|
||||
|
||||
if (themePreference === 'system') {
|
||||
// Use OS preference
|
||||
if (window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches) {
|
||||
if (themePreference === 'system') {
|
||||
// Use OS preference with proper media query listener
|
||||
const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
||||
if (mediaQuery.matches) {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
} else if (themePreference === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
} else {
|
||||
document.documentElement.classList.remove('dark');
|
||||
}
|
||||
} else if (themePreference === 'dark') {
|
||||
document.documentElement.classList.add('dark');
|
||||
};
|
||||
|
||||
// Apply theme immediately if DOM is ready, otherwise wait
|
||||
if (document.readyState === 'loading') {
|
||||
document.addEventListener('DOMContentLoaded', applyTheme);
|
||||
} else {
|
||||
applyTheme();
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
+875
-61
File diff suppressed because it is too large
Load Diff
@@ -247,7 +247,7 @@
|
||||
</a>
|
||||
<a href="{{ url('admin/movie-edit?id=' . ($movie['imdbid'] ?? $movie->imdbid ?? '') . '&update=1') }}"
|
||||
class="ml-auto px-6 py-2 bg-green-600 text-white rounded-lg hover:bg-green-700"
|
||||
onclick="return confirm('This will fetch and update movie data from TMDB. Continue?')">
|
||||
data-confirm="This will fetch and update movie data from TMDB. Continue?">
|
||||
<i class="fa fa-refresh mr-2"></i>Update from TMDB
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
<a href="{{ url('/admin/release-delete/' . $release->guid) }}"
|
||||
class="text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300"
|
||||
title="Delete release"
|
||||
onclick="return confirm('Are you sure you want to delete this release?')">
|
||||
data-confirm="Are you sure you want to delete this release?">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -94,7 +94,7 @@
|
||||
<a href="{{ url('admin/release-delete/' . $release->id) }}"
|
||||
class="text-red-600 dark:text-red-400 hover:text-red-900 dark:hover:text-red-300"
|
||||
title="Delete"
|
||||
onclick="return confirm('Are you sure you want to delete this release?')">
|
||||
data-confirm="Are you sure you want to delete this release?">
|
||||
<i class="fa fa-trash"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
@@ -278,7 +278,8 @@
|
||||
<button type="button"
|
||||
class="text-green-600 dark:text-green-400 hover:text-green-900 dark:hover:text-green-300 border-0 bg-transparent cursor-pointer p-0"
|
||||
title="Verify User"
|
||||
onclick="showVerifyModal(event, this.closest('form'))">
|
||||
data-show-verify-modal
|
||||
data-form-id="{{ $user->id }}">
|
||||
<i class="fa fa-check-circle"></i>
|
||||
</button>
|
||||
</form>
|
||||
@@ -330,7 +331,7 @@
|
||||
<i class="fa fa-check-circle text-green-600 dark:text-green-400 mr-2"></i>
|
||||
Verify User
|
||||
</h3>
|
||||
<button type="button" onclick="hideVerifyModal()" class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
|
||||
<button type="button" data-close-verify-modal class="text-gray-400 hover:text-gray-600 dark:hover:text-gray-300">
|
||||
<i class="fas fa-times text-xl"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -342,12 +343,12 @@
|
||||
</div>
|
||||
<div class="px-6 py-4 bg-gray-50 dark:bg-gray-900 border-t border-gray-200 dark:border-gray-700 flex justify-end space-x-3">
|
||||
<button type="button"
|
||||
onclick="hideVerifyModal()"
|
||||
data-close-verify-modal
|
||||
class="px-4 py-2 bg-gray-200 dark:bg-gray-700 text-gray-700 dark:text-gray-300 rounded-lg hover:bg-gray-300 dark:hover:bg-gray-600 transition font-medium">
|
||||
<i class="fas fa-times mr-2"></i>Cancel
|
||||
</button>
|
||||
<button type="button"
|
||||
onclick="submitVerifyForm()"
|
||||
data-submit-verify-form
|
||||
class="px-4 py-2 bg-green-600 dark:bg-green-700 text-white rounded-lg hover:bg-green-700 dark:hover:bg-green-800 transition font-medium">
|
||||
<i class="fa fa-check mr-2"></i>Verify
|
||||
</button>
|
||||
|
||||
@@ -279,7 +279,7 @@
|
||||
<!-- Preview/Sample Image Modal -->
|
||||
<div id="previewModal" class="hidden fixed inset-0 bg-black bg-opacity-75 items-center justify-center p-4" style="display: none; z-index: 9999 !important;">
|
||||
<div class="relative max-w-4xl w-full">
|
||||
<button type="button" onclick="closePreviewModal()" class="absolute top-4 right-4 text-white hover:text-gray-300 text-3xl font-bold z-10">
|
||||
<button type="button" data-close-preview-modal class="absolute top-4 right-4 text-white hover:text-gray-300 text-3xl font-bold z-10">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
<div class="text-center mb-2">
|
||||
@@ -299,7 +299,7 @@
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 dark:text-gray-200 flex items-center">
|
||||
<i class="fas fa-info-circle mr-2 text-blue-600 dark:text-blue-400 dark:text-blue-400"></i> Media Information
|
||||
</h3>
|
||||
<button type="button" onclick="closeMediainfoModal()" class="text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300 text-2xl font-bold">
|
||||
<button type="button" data-close-mediainfo-modal class="text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300 text-2xl font-bold">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
@@ -319,7 +319,7 @@
|
||||
<h3 class="text-lg font-semibold text-gray-800 dark:text-gray-200 dark:text-gray-200 flex items-center">
|
||||
<i class="fas fa-file-archive mr-2 text-green-600 dark:text-green-400"></i> File List
|
||||
</h3>
|
||||
<button type="button" onclick="closeFilelistModal()" class="text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300 text-2xl font-bold">
|
||||
<button type="button" data-close-filelist-modal class="text-gray-400 dark:text-gray-500 hover:text-gray-600 dark:text-gray-400 dark:hover:text-gray-300 text-2xl font-bold">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -348,7 +348,7 @@
|
||||
<!-- Preview/Sample Image Modal -->
|
||||
<div id="previewModal" class="hidden fixed inset-0 bg-black bg-opacity-75 items-center justify-center p-4">
|
||||
<div class="relative max-w-4xl w-full">
|
||||
<button type="button" onclick="closePreviewModal()" class="absolute top-4 right-4 text-white hover:text-gray-300 text-3xl font-bold z-10">
|
||||
<button type="button" data-close-preview-modal class="absolute top-4 right-4 text-white hover:text-gray-300 text-3xl font-bold z-10">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
<div class="text-center mb-2">
|
||||
|
||||
@@ -236,7 +236,7 @@
|
||||
<div class="flex space-x-2">
|
||||
<a href="{{ route('profileedit', ['action' => 'newapikey']) }}"
|
||||
class="px-6 py-2 text-blue-700 bg-blue-100 rounded-lg hover:bg-blue-200 transition"
|
||||
onclick="return confirm('Are you sure you want to generate a new API key?')">
|
||||
data-confirm="Are you sure you want to generate a new API key?">
|
||||
<i class="fas fa-key mr-2"></i>New API Key
|
||||
</a>
|
||||
<button type="submit" class="px-6 py-2 bg-blue-600 dark:bg-blue-700 text-white rounded-lg hover:bg-blue-700 dark:hover:bg-blue-800 transition">
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
@if(!($isadmin ?? false) && !$publicview)
|
||||
<a href="{{ url('profile_delete?id=' . $user->id) }}"
|
||||
class="px-4 py-2 bg-red-600 dark:bg-red-700 text-white text-sm rounded hover:bg-red-700 dark:hover:bg-red-800 transition"
|
||||
onclick="return confirm('Are you sure you want to delete your account? This action cannot be undone.')">
|
||||
data-confirm="Are you sure you want to delete your account? This action cannot be undone.">
|
||||
<i class="fa fa-trash mr-1"></i>Delete Account
|
||||
</a>
|
||||
@endif
|
||||
|
||||
@@ -282,82 +282,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@push('scripts')
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
// Copy to clipboard functionality using modern Clipboard API
|
||||
document.querySelectorAll('.copy-btn').forEach(function(btn) {
|
||||
btn.addEventListener('click', function() {
|
||||
const targetId = this.getAttribute('data-copy-target');
|
||||
const input = document.getElementById(targetId);
|
||||
if (input) {
|
||||
input.select();
|
||||
input.setSelectionRange(0, 99999);
|
||||
navigator.clipboard.writeText(input.value).then(() => {
|
||||
// Visual feedback
|
||||
const icon = this.querySelector('i');
|
||||
icon.classList.remove('fa-copy');
|
||||
icon.classList.add('fa-check');
|
||||
this.classList.add('text-green-600');
|
||||
setTimeout(() => {
|
||||
icon.classList.remove('fa-check');
|
||||
icon.classList.add('fa-copy');
|
||||
this.classList.remove('text-green-600');
|
||||
}, 2000);
|
||||
}).catch(() => {
|
||||
// Fallback for older browsers
|
||||
document.execCommand('copy');
|
||||
const icon = this.querySelector('i');
|
||||
icon.classList.remove('fa-copy');
|
||||
icon.classList.add('fa-check');
|
||||
this.classList.add('text-green-600');
|
||||
setTimeout(() => {
|
||||
icon.classList.remove('fa-check');
|
||||
icon.classList.add('fa-copy');
|
||||
this.classList.remove('text-green-600');
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// API Token copy button
|
||||
const copyApiTokenBtn = document.getElementById('copyApiToken');
|
||||
if (copyApiTokenBtn) {
|
||||
copyApiTokenBtn.addEventListener('click', function() {
|
||||
const input = document.getElementById('apiTokenInput');
|
||||
if (input) {
|
||||
input.select();
|
||||
input.setSelectionRange(0, 99999);
|
||||
navigator.clipboard.writeText(input.value).then(() => {
|
||||
// Visual feedback
|
||||
const icon = this.querySelector('i');
|
||||
icon.classList.remove('fa-copy');
|
||||
icon.classList.add('fa-check');
|
||||
this.classList.add('text-green-600');
|
||||
setTimeout(() => {
|
||||
icon.classList.remove('fa-check');
|
||||
icon.classList.add('fa-copy');
|
||||
this.classList.remove('text-green-600');
|
||||
}, 2000);
|
||||
}).catch(() => {
|
||||
// Fallback for older browsers
|
||||
document.execCommand('copy');
|
||||
const icon = this.querySelector('i');
|
||||
icon.classList.remove('fa-copy');
|
||||
icon.classList.add('fa-check');
|
||||
this.classList.add('text-green-600');
|
||||
setTimeout(() => {
|
||||
icon.classList.remove('fa-check');
|
||||
icon.classList.add('fa-copy');
|
||||
this.classList.remove('text-green-600');
|
||||
}, 2000);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@endpush
|
||||
{{-- Copy to clipboard functionality moved to csp-safe.js --}}
|
||||
@endsection
|
||||
|
||||
|
||||
@@ -383,7 +383,7 @@
|
||||
<!-- Preview/Sample Image Modal -->
|
||||
<div id="previewModal" class="hidden fixed inset-0 bg-black bg-opacity-75 items-center justify-center p-4" style="display: none; z-index: 9999 !important;">
|
||||
<div class="relative max-w-4xl w-full">
|
||||
<button type="button" onclick="closePreviewModal()" class="absolute top-4 right-4 text-white hover:text-gray-300 text-3xl font-bold z-10">
|
||||
<button type="button" data-close-preview-modal class="absolute top-4 right-4 text-white hover:text-gray-300 text-3xl font-bold z-10">
|
||||
<i class="fas fa-times"></i>
|
||||
</button>
|
||||
<div class="text-center mb-2">
|
||||
|
||||
@@ -286,47 +286,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function switchSeason(seasonNumber) {
|
||||
// Hide all season content
|
||||
document.querySelectorAll('.season-content').forEach(content => {
|
||||
content.classList.add('hidden');
|
||||
});
|
||||
|
||||
// Remove active styling from all tabs
|
||||
document.querySelectorAll('.season-tab').forEach(tab => {
|
||||
tab.classList.remove('border-blue-500', 'text-blue-600');
|
||||
tab.classList.add('border-transparent', 'text-gray-500');
|
||||
|
||||
// Update badge styling
|
||||
const badge = tab.querySelector('span');
|
||||
if (badge) {
|
||||
badge.classList.remove('bg-blue-100', 'text-blue-800');
|
||||
badge.classList.add('bg-gray-100', 'text-gray-600');
|
||||
}
|
||||
});
|
||||
|
||||
// Show selected season content
|
||||
const selectedContent = document.querySelector(`.season-content[data-season="${seasonNumber}"]`);
|
||||
if (selectedContent) {
|
||||
selectedContent.classList.remove('hidden');
|
||||
}
|
||||
|
||||
// Add active styling to selected tab
|
||||
const selectedTab = document.querySelector(`.season-tab[data-season="${seasonNumber}"]`);
|
||||
if (selectedTab) {
|
||||
selectedTab.classList.remove('border-transparent', 'text-gray-500');
|
||||
selectedTab.classList.add('border-blue-500', 'text-blue-600');
|
||||
|
||||
// Update badge styling
|
||||
const badge = selectedTab.querySelector('span');
|
||||
if (badge) {
|
||||
badge.classList.remove('bg-gray-100', 'text-gray-600');
|
||||
badge.classList.add('bg-blue-100', 'text-blue-800');
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
{{-- Season switcher functionality moved to csp-safe.js --}}
|
||||
@endforeach
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user