From fa02ba0654a377005f6b65e39c157e6a4f10de05 Mon Sep 17 00:00:00 2001 From: DariusIII Date: Mon, 3 Nov 2025 01:17:50 +0100 Subject: [PATCH] Update remove crap managment --- Blacklight/Books.php | 23 +++- Blacklight/TmuxRun.php | 9 +- Blacklight/libraries/Forking.php | 6 +- .../libraries/Runners/PostProcessRunner.php | 64 +++++++++ Blacklight/processing/PostProcess.php | 12 +- Blacklight/processing/post/AniDB.php | 20 ++- app/Console/Commands/PostProcessGuid.php | 12 +- app/Console/Commands/ProcessPostProcess.php | 9 +- app/Console/Commands/RemoveCrapReleases.php | 51 ++++++++ .../Controllers/Admin/AdminTmuxController.php | 12 +- app/Services/AnimeProcessor.php | 4 +- app/Services/BooksProcessor.php | 4 +- app/Services/Tmux/TmuxPaneManager.php | 6 +- app/Services/Tmux/TmuxTaskRunner.php | 123 +++++++++++++++--- resources/css/csp-safe.css | 19 +++ resources/js/csp-safe.js | 76 +++++++++-- .../views/admin/site/tmux-edit.blade.php | 39 +++++- 17 files changed, 421 insertions(+), 68 deletions(-) create mode 100644 app/Console/Commands/RemoveCrapReleases.php diff --git a/Blacklight/Books.php b/Blacklight/Books.php index ac322803c..4bcde305b 100755 --- a/Blacklight/Books.php +++ b/Blacklight/Books.php @@ -251,7 +251,7 @@ class Books * * @throws \Exception */ - public function processBookReleases(): void + public function processBookReleases(string $groupID = '', string $guidChar = ''): void { $bookids = []; if (ctype_digit((string) $this->bookreqids)) { @@ -263,13 +263,22 @@ class Books $total = \count($bookids); if ($total > 0) { foreach ($bookids as $i => $iValue) { + $query = Release::query() + ->whereNull('bookinfo_id') + ->whereIn('categories_id', [$iValue]) + ->orderByDesc('postdate') + ->limit($this->bookqty); + + if ($guidChar !== '') { + $query->where('leftguid', 'like', $guidChar.'%'); + } + + if ($groupID !== '') { + $query->where('groups_id', $groupID); + } + $this->processBookReleasesHelper( - Release::query() - ->whereNull('bookinfo_id') - ->whereIn('categories_id', [$iValue]) - ->orderByDesc('postdate') - ->limit($this->bookqty) - ->get(['searchname', 'id', 'categories_id']), $iValue + $query->get(['searchname', 'id', 'categories_id']), $iValue ); } } diff --git a/Blacklight/TmuxRun.php b/Blacklight/TmuxRun.php index 9c176d8a5..d769d150e 100755 --- a/Blacklight/TmuxRun.php +++ b/Blacklight/TmuxRun.php @@ -153,7 +153,12 @@ class TmuxRun extends Tmux $log = $this->writelog($runVar['panes']['two'][2]); shell_exec( "tmux respawnp -t{$runVar['constants']['tmux_session']}:2.2 ' \ - {$runVar['commands']['_phpn']} {$runVar['paths']['misc']}update/postprocess.php amazon true $log; date +\"{$this->_dateFormat}\"; {$runVar['commands']['_sleep']} {$runVar['settings']['post_timer_amazon']}' 2>&1 1> /dev/null" + {$runVar['commands']['_phpn']} artisan update:postprocess music true 2>&1 | tee -a $log; \ + {$runVar['commands']['_phpn']} artisan update:postprocess book true 2>&1 | tee -a $log; \ + {$runVar['commands']['_phpn']} artisan update:postprocess console true 2>&1 | tee -a $log; \ + {$runVar['commands']['_phpn']} artisan update:postprocess games true 2>&1 | tee -a $log; \ + {$runVar['commands']['_phpn']} artisan update:postprocess xxx true 2>&1 | tee -a $log; \ + date +\"{$this->_dateFormat}\"; {$runVar['commands']['_sleep']} {$runVar['settings']['post_timer_amazon']}' 2>&1 1> /dev/null" ); break; case (int) $runVar['settings']['post_amazon'] === 1 && (int) $runVar['settings']['processbooks'] === 0 @@ -239,7 +244,7 @@ class TmuxRun extends Tmux "tmux respawnp -t{$runVar['constants']['tmux_session']}:2.1 ' \ {$runVar['commands']['_php']} artisan multiprocessing:postprocess tv 2>&1 | tee -a $log; \ {$runVar['commands']['_php']} artisan multiprocessing:postprocess mov 2>&1 | tee -a $log; \ - {$runVar['commands']['_php']} {$runVar['paths']['misc']}update/postprocess.php anime true $log; \ + {$runVar['commands']['_php']} artisan multiprocessing:postprocess anime 2>&1 | tee -a $log; \ $log; \ {$runVar['commands']['_php']} {$runVar['paths']['misc']}testing/PostProc/check_covers.php true $log; \ date +\"{$this->_dateFormat}\"; {$runVar['commands']['_sleep']} {$runVar['settings']['post_timer_non']}' 2>&1 1> /dev/null" ); diff --git a/Blacklight/libraries/Forking.php b/Blacklight/libraries/Forking.php index 47f114f3f..533294b1d 100755 --- a/Blacklight/libraries/Forking.php +++ b/Blacklight/libraries/Forking.php @@ -199,13 +199,17 @@ class Forking break; case 'postProcess_ama': - $this->processSingle(); + $this->postProcessRunner->processBooks(); break; case 'postProcess_add': $this->postProcessRunner->processAdditional(); break; + case 'postProcess_ani': + $this->postProcessRunner->processAnime(); + break; + case 'postProcess_mov': $renamedOnly = (isset($this->workTypeOptions[0]) && $this->workTypeOptions[0] === true); $this->postProcessRunner->processMovies($renamedOnly); diff --git a/Blacklight/libraries/Runners/PostProcessRunner.php b/Blacklight/libraries/Runners/PostProcessRunner.php index 085a84c27..4aed7248a 100644 --- a/Blacklight/libraries/Runners/PostProcessRunner.php +++ b/Blacklight/libraries/Runners/PostProcessRunner.php @@ -212,4 +212,68 @@ class PostProcessRunner extends BaseRunner return count(DB::select($checkSql)) > 0; } + + public function processAnime(): void + { + if ((int) Settings::settingValue('lookupanidb') <= 0) { + $this->headerNone(); + + return; + } + + $checkSql = ' + SELECT id + FROM releases + WHERE categories_id = 5070 + AND anidbid IS NULL + LIMIT 1'; + if (count(DB::select($checkSql)) === 0) { + $this->headerNone(); + + return; + } + + $sql = ' + SELECT DISTINCT LEFT(leftguid, 1) AS id + FROM releases + WHERE categories_id = 5070 + AND anidbid IS NULL + LIMIT 16'; + $queue = DB::select($sql); + + $maxProcesses = (int) Settings::settingValue('postthreadsnon'); + $this->runPostProcess($queue, $maxProcesses, 'anime', 'anime postprocessing'); + } + + public function processBooks(): void + { + if ((int) Settings::settingValue('lookupbooks') <= 0) { + $this->headerNone(); + + return; + } + + $checkSql = ' + SELECT id + FROM releases + WHERE categories_id BETWEEN 7000 AND 7999 + AND bookinfo_id IS NULL + LIMIT 1'; + if (count(DB::select($checkSql)) === 0) { + $this->headerNone(); + + return; + } + + $sql = ' + SELECT DISTINCT LEFT(leftguid, 1) AS id + FROM releases + WHERE categories_id BETWEEN 7000 AND 7999 + AND bookinfo_id IS NULL + LIMIT 16'; + $queue = DB::select($sql); + + $maxProcesses = (int) Settings::settingValue('postthreadsnon'); + $this->runPostProcess($queue, $maxProcesses, 'books', 'books postprocessing'); + } } diff --git a/Blacklight/processing/PostProcess.php b/Blacklight/processing/PostProcess.php index 1772601bb..2bd2ecd5f 100755 --- a/Blacklight/processing/PostProcess.php +++ b/Blacklight/processing/PostProcess.php @@ -112,23 +112,27 @@ class PostProcess /** * Lookup anidb if enabled. * + * @param string $groupID (Optional) ID of a group to work on. + * @param string $guidChar (Optional) First letter of a release GUID to use to get work. * * @throws \Exception */ - public function processAnime(): void + public function processAnime(string $groupID = '', string $guidChar = ''): void { - $this->animeProcessor->process(); + $this->animeProcessor->process($groupID, $guidChar); } /** * Process books using amazon.com. * + * @param string $groupID (Optional) ID of a group to work on. + * @param string $guidChar (Optional) First letter of a release GUID to use to get work. * * @throws \Exception */ - public function processBooks(): void + public function processBooks(string $groupID = '', string $guidChar = ''): void { - $this->booksProcessor->process(); + $this->booksProcessor->process($groupID, $guidChar); } /** diff --git a/Blacklight/processing/post/AniDB.php b/Blacklight/processing/post/AniDB.php index 4a6e0d374..c31e39f57 100755 --- a/Blacklight/processing/post/AniDB.php +++ b/Blacklight/processing/post/AniDB.php @@ -56,14 +56,26 @@ class AniDB /** * Queues anime releases for processing. * + * @param string $groupID (Optional) ID of a group to work on. + * @param string $guidChar (Optional) First letter of a release GUID to use to get work. + * * @throws \Exception */ - public function processAnimeReleases(): void + public function processAnimeReleases(string $groupID = '', string $guidChar = ''): void { - $results = Release::query() + $query = Release::query() ->whereNull('anidbid') - ->where('categories_id', Category::TV_ANIME) - ->orderByDesc('postdate') + ->where('categories_id', Category::TV_ANIME); + + if ($guidChar !== '') { + $query->where('leftguid', 'like', $guidChar.'%'); + } + + if ($groupID !== '') { + $query->where('groups_id', $groupID); + } + + $results = $query->orderByDesc('postdate') ->limit($this->aniqty) ->get(); diff --git a/app/Console/Commands/PostProcessGuid.php b/app/Console/Commands/PostProcessGuid.php index dad49fa3a..21abd450b 100644 --- a/app/Console/Commands/PostProcessGuid.php +++ b/app/Console/Commands/PostProcessGuid.php @@ -18,7 +18,7 @@ class PostProcessGuid extends Command * @var string */ protected $signature = 'postprocess:guid - {type : Type: additional, nfo, movie, or tv} + {type : Type: additional, nfo, movie, tv, anime, or books} {guid : First character of release guid (a-f, 0-9)} {renamed? : For movie/tv: process renamed only (optional)}'; @@ -70,8 +70,16 @@ class PostProcessGuid extends Command (new PostProcess)->processTv('', $guid, $renamed); break; + case 'anime': + (new PostProcess)->processAnime('', $guid); + break; + + case 'books': + (new PostProcess)->processBooks('', $guid); + break; + default: - $this->error('Invalid type. Must be: additional, nfo, movie, or tv.'); + $this->error('Invalid type. Must be: additional, nfo, movie, tv, anime, or books.'); return self::FAILURE; } diff --git a/app/Console/Commands/ProcessPostProcess.php b/app/Console/Commands/ProcessPostProcess.php index f783b074b..e140dafca 100644 --- a/app/Console/Commands/ProcessPostProcess.php +++ b/app/Console/Commands/ProcessPostProcess.php @@ -13,7 +13,7 @@ class ProcessPostProcess extends Command * @var string */ protected $signature = 'multiprocessing:postprocess - {type : Type: ama, add, mov, nfo, sha, or tv} + {type : Type: ama, add, ani, mov, nfo, sha, or tv} {renamed=false : For mov/tv: only post-process renamed releases (true/false)}'; /** @@ -31,11 +31,12 @@ class ProcessPostProcess extends Command $type = $this->argument('type'); $renamed = $this->argument('renamed'); - if (! \in_array($type, ['ama', 'add', 'mov', 'nfo', 'sha', 'tv'], true)) { - $this->error('Type must be one of: ama, add, mov, nfo, sha, tv'); + if (! \in_array($type, ['ama', 'add', 'ani', 'mov', 'nfo', 'sha', 'tv'], true)) { + $this->error('Type must be one of: ama, add, ani, mov, nfo, sha, tv'); $this->line(''); - $this->line('ama => Do amazon processing (no multiprocessing due to API restrictions)'); + $this->line('ama => Do amazon/books processing'); $this->line('add => Do additional (rar|zip) processing'); + $this->line('ani => Do anime processing'); $this->line('mov => Do movie processing'); $this->line('nfo => Do NFO processing'); $this->line('sha => Do sharing processing (no multiprocessing)'); diff --git a/app/Console/Commands/RemoveCrapReleases.php b/app/Console/Commands/RemoveCrapReleases.php new file mode 100644 index 000000000..0ae554fab --- /dev/null +++ b/app/Console/Commands/RemoveCrapReleases.php @@ -0,0 +1,51 @@ +option('type') ?? ''; + $time = $this->option('time') ?? 'full'; + $blacklistId = $this->option('blacklist-id') ?? ''; + $delete = $this->option('delete'); + + if (! $delete) { + $this->warn('Running in DRY-RUN mode. Use --delete to actually remove releases.'); + } + + try { + $remover = new ReleaseRemover; + $result = $remover->removeCrap($delete, $time, $type, $blacklistId); + + if ($result === true) { + return self::SUCCESS; + } + + $this->error($result); + + return self::FAILURE; + } catch (\Exception $e) { + $this->error($e->getMessage()); + + return self::FAILURE; + } + } +} diff --git a/app/Http/Controllers/Admin/AdminTmuxController.php b/app/Http/Controllers/Admin/AdminTmuxController.php index 9cde3a931..38c0f5389 100644 --- a/app/Http/Controllers/Admin/AdminTmuxController.php +++ b/app/Http/Controllers/Admin/AdminTmuxController.php @@ -20,7 +20,17 @@ class AdminTmuxController extends BasePageController switch ($action) { case 'submit': - Settings::settingsUpdate($request->all()); + $data = $request->all(); + + // Handle fix_crap checkbox array - convert to comma-separated string + if (isset($data['fix_crap']) && is_array($data['fix_crap'])) { + $data['fix_crap'] = implode(',', $data['fix_crap']); + } elseif (! isset($data['fix_crap'])) { + // If no checkboxes selected, save empty string + $data['fix_crap'] = ''; + } + + Settings::settingsUpdate($data); return redirect()->to('admin/tmux-edit')->with('success', 'Tmux settings updated successfully'); diff --git a/app/Services/AnimeProcessor.php b/app/Services/AnimeProcessor.php index ddc57c4aa..40f71ad79 100644 --- a/app/Services/AnimeProcessor.php +++ b/app/Services/AnimeProcessor.php @@ -14,10 +14,10 @@ class AnimeProcessor $this->echooutput = $echooutput; } - public function process(): void + public function process(string $groupID = '', string $guidChar = ''): void { if ((int) Settings::settingValue('lookupanidb') !== 0) { - (new AniDB)->processAnimeReleases(); + (new AniDB)->processAnimeReleases($groupID, $guidChar); } } } diff --git a/app/Services/BooksProcessor.php b/app/Services/BooksProcessor.php index 626c33c4a..c0737830b 100644 --- a/app/Services/BooksProcessor.php +++ b/app/Services/BooksProcessor.php @@ -14,10 +14,10 @@ class BooksProcessor $this->echooutput = $echooutput; } - public function process(): void + public function process(string $groupID = '', string $guidChar = ''): void { if ((int) Settings::settingValue('lookupbooks') !== 0) { - (new Books)->processBookReleases(); + (new Books)->processBookReleases($groupID, $guidChar); } } } diff --git a/app/Services/Tmux/TmuxPaneManager.php b/app/Services/Tmux/TmuxPaneManager.php index bcc600c77..a93a3e1f8 100644 --- a/app/Services/Tmux/TmuxPaneManager.php +++ b/app/Services/Tmux/TmuxPaneManager.php @@ -87,8 +87,12 @@ class TmuxPaneManager { $killFlag = $kill ? '-k' : ''; + // Escape the command for tmux by replacing double quotes with escaped quotes + $escapedCommand = str_replace('"', '\\"', $command); + $escapedCommand = str_replace('$', '\\$', $escapedCommand); + $result = Process::timeout(10)->run( - "tmux respawnp {$killFlag} -t {$this->sessionName}:{$target} '{$command}'" + "tmux respawnp {$killFlag} -t {$this->sessionName}:{$target} \"{$escapedCommand}\"" ); return $result->successful(); diff --git a/app/Services/Tmux/TmuxTaskRunner.php b/app/Services/Tmux/TmuxTaskRunner.php index daeb2b919..f44089481 100644 --- a/app/Services/Tmux/TmuxTaskRunner.php +++ b/app/Services/Tmux/TmuxTaskRunner.php @@ -71,7 +71,7 @@ class TmuxTaskRunner // Add sleep timer at the end if specified if (isset($options['sleep'])) { $sleepCommand = $this->buildSleepCommand($options['sleep']); - $parts[] = "date +'%Y-%m-%d %T'"; + $parts[] = 'date +"%Y-%m-%d %T"'; $parts[] = $sleepCommand; } @@ -334,16 +334,12 @@ class TmuxTaskRunner */ protected function runMainSequential(array $runVar): bool { - // Full sequential mode - runs sequential script + // Full sequential mode - runs group:update-all for each group $pane = '0.1'; - $script = base_path('misc/update/nix/tmux/bin/sequential.php'); - - if (! file_exists($script)) { - return $this->disablePane($pane, 'Sequential', 'script not found'); - } $niceness = Settings::settingValue('niceness') ?? 2; - $command = "nice -n{$niceness} php {$script}"; + $artisan = base_path('artisan'); + $command = "nice -n{$niceness} php {$artisan} group:update-all"; $command = $this->buildCommand($command, ['log_pane' => 'sequential']); return $this->paneManager->respawnPane($pane, $command); @@ -387,26 +383,115 @@ class TmuxTaskRunner */ protected function runRemoveCrapTask(array $runVar): bool { - $enabled = (int) ($runVar['settings']['fix_crap'] ?? 0); + $option = $runVar['settings']['fix_crap_opt'] ?? 'Disabled'; $pane = '1.1'; - if ($enabled !== 1) { + // Handle disabled state + if ($option === 'Disabled' || $option === 0 || $option === '0') { return $this->disablePane($pane, 'Remove Crap', 'disabled in settings'); } - $option = (int) ($runVar['settings']['fix_crap_opt'] ?? 1); - $script = base_path('misc/update/nix/tmux/bin/removecrap.php'); + $niceness = Settings::settingValue('niceness') ?? 2; + $artisan = base_path('artisan'); + $sleep = (int) ($runVar['settings']['crap_timer'] ?? 300); - if (! file_exists($script)) { - return $this->disablePane($pane, 'Remove Crap', 'script not found'); + // Handle 'All' mode - run all types with 2 hour time limit + if ($option === 'All') { + $command = "nice -n{$niceness} php {$artisan} releases:remove-crap --time=2 --delete"; + $command = $this->buildCommand($command, ['log_pane' => 'removecrap', 'sleep' => $sleep]); + // Wrap in while loop to keep pane alive + $loopCommand = "while true; do {$command}; done"; + + return $this->paneManager->respawnPane($pane, $loopCommand); } - $niceness = Settings::settingValue('niceness') ?? 2; - $command = "nice -n{$niceness} php {$script} {$option}"; - $sleep = (int) ($runVar['settings']['crap_timer'] ?? 300); - $command = $this->buildCommand($command, ['log_pane' => 'removecrap', 'sleep' => $sleep]); + // Handle 'Custom' mode - cycle through selected types + if ($option === 'Custom') { + $selectedTypes = $runVar['settings']['fix_crap'] ?? ''; - return $this->paneManager->respawnPane($pane, $command); + if (empty($selectedTypes)) { + return $this->disablePane($pane, 'Remove Crap', 'no crap types selected'); + } + + $types = is_array($selectedTypes) ? $selectedTypes : explode(',', $selectedTypes); + $types = array_filter($types); // Remove empty values + + if (empty($types)) { + return $this->disablePane($pane, 'Remove Crap', 'no crap types selected'); + } + + // Get the next type to process + $stateFile = storage_path('tmux/removecrap_state.json'); + $state = $this->loadCrapState($stateFile); + + // Determine current type index + $currentIndex = $state['current_index'] ?? 0; + $isFirstRun = $state['first_run'] ?? true; + + // Validate index + if ($currentIndex >= count($types)) { + $currentIndex = 0; + $isFirstRun = false; + } + + $currentType = $types[$currentIndex]; + + // Determine time limit: full on first run, 4 hours otherwise + $time = $isFirstRun ? 'full' : '4'; + + // Build and run command + $command = "nice -n{$niceness} php {$artisan} releases:remove-crap --type={$currentType} --time={$time} --delete"; + $command = $this->buildCommand($command, ['log_pane' => 'removecrap', 'sleep' => $sleep]); + + // Update state for next run + $nextIndex = $currentIndex + 1; + if ($nextIndex >= count($types)) { + $nextIndex = 0; + $isFirstRun = false; + } + + $this->saveCrapState($stateFile, [ + 'current_index' => $nextIndex, + 'first_run' => $isFirstRun, + 'types' => $types, + ]); + + // Wrap in while loop to keep pane alive + $loopCommand = "while true; do {$command}; done"; + + return $this->paneManager->respawnPane($pane, $loopCommand); + } + + // Default fallback - disabled + return $this->disablePane($pane, 'Remove Crap', 'invalid configuration'); + } + + /** + * Load crap removal state + */ + protected function loadCrapState(string $file): array + { + if (! file_exists($file)) { + return ['current_index' => 0, 'first_run' => true]; + } + + $content = file_get_contents($file); + $state = json_decode($content, true); + + return $state ?: ['current_index' => 0, 'first_run' => true]; + } + + /** + * Save crap removal state + */ + protected function saveCrapState(string $file, array $state): void + { + $dir = dirname($file); + if (! is_dir($dir)) { + mkdir($dir, 0755, true); + } + + file_put_contents($file, json_encode($state, JSON_PRETTY_PRINT)); } /** diff --git a/resources/css/csp-safe.css b/resources/css/csp-safe.css index 8128afb97..6e034f75e 100644 --- a/resources/css/csp-safe.css +++ b/resources/css/csp-safe.css @@ -627,3 +627,22 @@ code.api-token::-webkit-scrollbar-thumb:hover { } } +/* Tmux Edit - Remove Crap Types Container Styles */ +#crap_types_container { + transition: opacity 0.3s ease, display 0.3s ease; +} + +/* Checkbox hover effects for crap types */ +.hover\:bg-gray-100:hover { + transition: background-color 0.2s ease; +} + +.dark .hover\:bg-gray-700:hover { + transition: background-color 0.2s ease; +} + +/* Form checkbox focus ring */ +.form-checkbox:focus-visible { + outline: 2px solid transparent; + outline-offset: 2px; +} diff --git a/resources/js/csp-safe.js b/resources/js/csp-safe.js index da69c7771..b28636a12 100644 --- a/resources/js/csp-safe.js +++ b/resources/js/csp-safe.js @@ -383,7 +383,7 @@ window.showConfirm = function(options) { const messageText = document.getElementById('confirmationModalMessage'); const confirmText = document.getElementById('confirmationModalConfirmText'); const cancelText = document.getElementById('confirmationModalCancelText'); - + if (titleText) titleText.textContent = config.title; if (messageText) messageText.textContent = config.message; if (confirmText) confirmText.textContent = config.confirmText; @@ -2649,7 +2649,7 @@ function initMoviesLayoutToggle() { applyLayout(currentLayout); // Apply layout anyway return; } - + fetch('/movies/update-layout', { method: 'POST', headers: { @@ -2771,29 +2771,29 @@ function initAdminDashboardCharts() { }, 100); return; } - + initializeAllDashboardCharts(); } function initializeAllDashboardCharts() { // Check if any chart canvas elements exist - const hasUserStatsCharts = document.getElementById('downloadsChart') || + const hasUserStatsCharts = document.getElementById('downloadsChart') || document.getElementById('apiHitsChart') || document.getElementById('downloadsMinuteChart') || document.getElementById('apiHitsMinuteChart'); - + const hasSystemCharts = document.getElementById('cpuHistory24hChart') || document.getElementById('ramHistory24hChart') || document.getElementById('cpuHistory30dChart') || document.getElementById('ramHistory30dChart'); - + if (!hasUserStatsCharts && !hasSystemCharts) { return; // Not on admin dashboard or charts not present } // Initialize user statistics charts initializeUserStatCharts(); - + // Initialize system metrics charts initializeSystemMetricsCharts(); } @@ -3477,8 +3477,8 @@ function initAdminRegexFormValidation() { // and have matching delimiters if (value.length > 0) { const firstChar = value[0]; - const delimiters = ['/', '#', '~', '%', '@', '!']; - + const delimiters = ['/', '#', '~', '%', '@', '!',]; + if (delimiters.includes(firstChar)) { // Check if regex has matching closing delimiter let delimiterCount = 0; @@ -3531,8 +3531,8 @@ function initAdminRegexFormValidation() { const value = this.value.trim(); if (value) { const firstChar = value[0]; - const delimiters = ['/', '#', '~', '%', '@', '!']; - + const delimiters = ['/', '#', '~', '%', '@', '!',]; + if (delimiters.includes(firstChar)) { let delimiterCount = 0; for (let i = 1; i < value.length; i++) { @@ -3541,7 +3541,7 @@ function initAdminRegexFormValidation() { break; } } - + if (delimiterCount === 0) { this.classList.add('border-red-500'); this.classList.remove('border-green-500'); @@ -3564,7 +3564,7 @@ function initAdminTmuxSelectColors() { // This function is for future tmux color selection functionality // Currently, no color selection is needed in tmux settings // If color pickers are added to tmux-edit page in the future, add them here - + // Check if we're on a page that might have color inputs const colorInputs = document.querySelectorAll('input[type="color"], select[data-color-select]'); if (colorInputs.length > 0) { @@ -4248,3 +4248,53 @@ function initFlashMessages() { initFlashMessages(); } })(); + +// Tmux Edit - Remove Crap Releases Toggle +function toggleCrapTypes(value) { + const container = document.getElementById('crap_types_container'); + if (container) { + if (value === 'Custom') { + container.style.display = 'block'; + // Add a slight animation effect + setTimeout(() => { + container.style.opacity = '1'; + }, 10); + } else { + container.style.opacity = '0.5'; + setTimeout(() => { + container.style.display = 'none'; + container.style.opacity = '1'; + }, 200); + } + } +} + +// Initialize tmux edit page functionality +function initTmuxEdit() { + // Initialize crap types toggle on page load + const checkedRadio = document.querySelector('input[name="fix_crap_opt"]:checked'); + if (checkedRadio) { + toggleCrapTypes(checkedRadio.value); + } + + // Add event listeners to all radio buttons + document.querySelectorAll('input[name="fix_crap_opt"]').forEach(function(radio) { + radio.addEventListener('change', function() { + toggleCrapTypes(this.value); + }); + }); +} + +// Initialize on DOMContentLoaded if on tmux-edit page +if (document.readyState === 'loading') { + document.addEventListener('DOMContentLoaded', function() { + if (document.getElementById('crap_types_container')) { + initTmuxEdit(); + } + }); +} else { + if (document.getElementById('crap_types_container')) { + initTmuxEdit(); + } +} + diff --git a/resources/views/admin/site/tmux-edit.blade.php b/resources/views/admin/site/tmux-edit.blade.php index 592ce4adf..6389d46ff 100644 --- a/resources/views/admin/site/tmux-edit.blade.php +++ b/resources/views/admin/site/tmux-edit.blade.php @@ -304,15 +304,41 @@

Remove Crap Releases

- - @foreach($yesno_ids as $index => $val) - +
+ @foreach($fix_crap_radio_ids as $index => $val) + @endforeach - +
+
+ +
+ @php + $selectedTypes = explode(',', $site['fix_crap'] ?? ''); + @endphp + @foreach($fix_crap_check_ids as $index => $val) + + @endforeach +
+
+
+
@@ -322,6 +348,7 @@
+

Console & Monitoring Tools