diff --git a/app/Console/Commands/TmuxMonitor.php b/app/Console/Commands/TmuxMonitor.php index 76bed7fdb..320baa665 100644 --- a/app/Console/Commands/TmuxMonitor.php +++ b/app/Console/Commands/TmuxMonitor.php @@ -224,8 +224,15 @@ class TmuxMonitor extends Command return; } - // These tasks would be implemented in TmuxTaskRunner - // For now, we're keeping the structure similar to the original - // but using the modern service architecture + // Run utility tasks (window 1) + $this->taskRunner->runPaneTask('fixnames', [], $runVar); + $this->taskRunner->runPaneTask('removecrap', [], $runVar); + + // Run post-processing tasks (window 2) + $this->taskRunner->runPaneTask('ppadditional', [], $runVar); + $this->taskRunner->runPaneTask('tv', [], $runVar); + $this->taskRunner->runPaneTask('movies', [], $runVar); + $this->taskRunner->runPaneTask('amazon', [], $runVar); + $this->taskRunner->runPaneTask('xxx', [], $runVar); } } diff --git a/app/Extensions/util/PhpYenc.php b/app/Extensions/util/PhpYenc.php deleted file mode 100644 index 5baac4e28..000000000 --- a/app/Extensions/util/PhpYenc.php +++ /dev/null @@ -1,232 +0,0 @@ -. - * - * @author niel - * @copyright 2016 nZEDb - */ - -namespace App\Extensions\util; - -/** - * Class PhpYenc. - * Optimized yEnc encoder/decoder implementation. - */ -class PhpYenc -{ - /** - * Pre-computed decode translation table for non-escaped characters. - * Maps yEnc encoded byte to decoded byte: (byte - 42) % 256 - * @var array|null - */ - private static ?array $decodeTable = null; - - /** - * Pre-computed decode translation table for escaped characters. - * Maps yEnc escaped byte to decoded byte: ((byte - 64) - 42) % 256 - * @var array|null - */ - private static ?array $escapeDecodeTable = null; - - /** - * Initialize the decode translation tables (lazy initialization). - */ - private static function initDecodeTables(): void - { - if (self::$decodeTable !== null) { - return; - } - - self::$decodeTable = []; - self::$escapeDecodeTable = []; - - for ($i = 0; $i < 256; $i++) { - $char = \chr($i); - // Standard decode: (byte - 42) % 256 - self::$decodeTable[$char] = \chr(($i - 42 + 256) % 256); - // Escape decode: ((byte - 64) - 42) % 256 - self::$escapeDecodeTable[$char] = \chr((($i - 64 - 42) + 512) % 256); - } - } - - public static function decode(&$text, bool $ignore = false): bool|string - { - $crc = ''; - // Extract the yEnc string itself. - if (preg_match( - '/=ybegin.*size=(\d+).*\r\n(.*)(?:\r\n)?=yend.*size=(\d+)(.*)/ims', - $text, - $encoded - )) { - if (preg_match('/crc32=([0-9a-fA-F]+)/i', $encoded[4], $trailer)) { - $crc = trim($trailer[1]); - } - - $headerSize = (int) $encoded[1]; - $trailerSize = (int) $encoded[3]; - $encoded = $encoded[2]; - } else { - return false; - } - - // Make sure the header and trailer file sizes match up. - if ($headerSize !== $trailerSize) { - $message = 'Header and trailer file sizes do not match. This is a violation of the yEnc specification.'; - throw new \RuntimeException($message); - } - - // Remove line breaks from the string (use str_replace with array for speed). - $encoded = str_replace(["\r\n", "\r", "\n"], '', $encoded); - - // Fast decode using optimized method - $decoded = self::fastDecode($encoded); - - // Make sure the decoded file size is the same as the size specified in the header. - $decodedLength = \strlen($decoded); - if ($decodedLength !== $headerSize) { - $message = 'Header file size ('.$headerSize.') and actual file size ('.$decodedLength.') do not match. The file is probably corrupt.'; - - throw new \RuntimeException($message); - } - - // Check the CRC value - if ($crc !== '' && (strcasecmp($crc, sprintf('%X', crc32($decoded))) !== 0)) { - $message = 'CRC32 checksums do not match. The file is probably corrupt.'; - - throw new \RuntimeException($message); - } - - return $decoded; - } - - /** - * Fast yEnc decode using strtr and optimized escape handling. - * - * @param string $encoded The encoded string (without headers/line breaks) - * @return string The decoded string - */ - private static function fastDecode(string $encoded): string - { - self::initDecodeTables(); - - /** @var array $decodeTable */ - $decodeTable = self::$decodeTable; - /** @var array $escapeDecodeTable */ - $escapeDecodeTable = self::$escapeDecodeTable; - - // Check if there are any escape sequences - $escapePos = strpos($encoded, '='); - - if ($escapePos === false) { - // No escape sequences - use fast strtr translation - return strtr($encoded, $decodeTable); - } - - // Handle escape sequences - // First, process escape sequences by splitting on '=' - $parts = explode('=', $encoded); - $result = strtr($parts[0], $decodeTable); - - $count = \count($parts); - for ($i = 1; $i < $count; $i++) { - $part = $parts[$i]; - if ($part === '') { - continue; - } - // First character after '=' is the escaped character - $result .= $escapeDecodeTable[$part[0]]; - // Rest of the part is normal encoded data - if (isset($part[1])) { - $result .= strtr(substr($part, 1), $decodeTable); - } - } - - return $result; - } - - /** - * Decode a string of text encoded with yEnc. Ignores all errors. - * - * @param string $text The encoded text to decode. - * @return string The decoded yEnc string, or the input string, if it's not yEnc. - */ - public static function decodeIgnore(string &$text): string - { - if (preg_match('/^(=yBegin.*=yEnd[^$]*)$/ims', $text, $input)) { - // Extract the encoded data, removing headers and line breaks - $input = preg_replace('/(^=yBegin.*\r\n)/im', '', $input[1], 1); - $input = preg_replace('/(^=yPart.*\r\n)/im', '', $input, 1); - $input = preg_replace('/(^=yEnd.*)/im', '', $input, 1); - $input = str_replace(["\r\n", "\r", "\n"], '', trim($input)); - - // Use the fast decode method - $text = self::fastDecode($input); - } - - return $text; - } - - public static function enabled(): bool - { - return true; - } - - public static function encode($data, $filename, int $lineLength = 128, bool $crc32 = true): string - { - // yEnc 1.3 draft doesn't allow line lengths of more than 254 bytes. - if ($lineLength > 254) { - $lineLength = 254; - } - - if ($lineLength < 1) { - $message = $lineLength.' is not a valid line length.'; - - throw new \RuntimeException($message); - } - - $encoded = ''; - $stringLength = \strlen($data); - // Encode each character of the string one at a time. - foreach ($data as $i => $iValue) { - $value = ((\ord($iValue) + 42) % 256); - - // Escape NULL, TAB, LF, CR, space, . and = characters. - $encoded .= match ($value) { - 0, 10, 13, 61 => ('='.\chr(($value + 64) % 256)), - default => \chr($value), - }; - } - - $encoded = - '=ybegin line='. - $lineLength. - ' size='. - $stringLength. - ' name='. - trim($filename). - "\r\n". - trim(chunk_split($encoded, $lineLength)). - "\r\n=yend size=". - $stringLength; - - // Add a CRC32 checksum if desired. - if ($crc32 === true) { - $encoded .= ' crc32='.strtolower(sprintf('%X', crc32($data))); - } - - return $encoded; - } -} diff --git a/app/Facades/Yenc.php b/app/Facades/Yenc.php new file mode 100644 index 000000000..b9f0b1c25 --- /dev/null +++ b/app/Facades/Yenc.php @@ -0,0 +1,29 @@ +_echo = config('nntmux.echocli'); $this->_tmux = $tmux ?? new Tmux; + $this->_yencService = $yencService ?? app(YencService::class); $this->_nntpRetries = Settings::settingValue('nntpretries') !== '' ? (int) Settings::settingValue('nntpretries') : 0 + 1; $this->initializeConfig(); @@ -773,7 +779,7 @@ class NNTPService extends \Net_NNTP_Client if ($line === ".\r\n") { $body = implode('', $bodyParts); - return PhpYenc::decodeIgnore($body); + return $this->_yencService->decodeIgnore($body); } if ($line[0] === '.' && isset($line[1]) && $line[1] === '.') { $line = substr($line, 1); @@ -1086,7 +1092,7 @@ class NNTPService extends \Net_NNTP_Client // Join all parts and attempt to yEnc decode $body = implode('', $bodyParts); - return PhpYenc::decodeIgnore($body); + return $this->_yencService->decodeIgnore($body); } // Check for line that starts with double period, remove one. diff --git a/app/Services/Tmux/Scripts/groupfixrelnames.php b/app/Services/Tmux/Scripts/groupfixrelnames.php index 6149187c9..0e7f63e14 100644 --- a/app/Services/Tmux/Scripts/groupfixrelnames.php +++ b/app/Services/Tmux/Scripts/groupfixrelnames.php @@ -1,3 +1,4 @@ +#!/usr/bin/env php error('This script is not intended to be run manually, it is called from Multiprocessing.'); + fwrite(STDERR, "This script is not intended to be run manually, it is called from Multiprocessing.\n"); exit(1); } @@ -21,12 +20,12 @@ if (! isset($argv[1])) { [$type, $guidChar, $maxPerRun, $thread] = explode(' ', $argv[1]); // Build artisan command based on type -$artisan = base_path('artisan'); +$artisan = dirname(__DIR__, 4).'/artisan'; switch ($type) { case 'standard': if ($guidChar === null || $maxPerRun === null || ! is_numeric($maxPerRun)) { - cli()->error('Invalid arguments for standard type'); + fwrite(STDERR, "Invalid arguments for standard type\n"); exit(1); } @@ -35,7 +34,7 @@ switch ($type) { case 'predbft': if (! isset($maxPerRun) || ! is_numeric($maxPerRun) || ! isset($thread) || ! is_numeric($thread)) { - cli()->error('Invalid arguments for predbft type'); + fwrite(STDERR, "Invalid arguments for predbft type\n"); exit(1); } @@ -43,7 +42,7 @@ switch ($type) { break; default: - cli()->error("Unknown type: {$type}"); + fwrite(STDERR, "Unknown type: {$type}\n"); exit(1); } diff --git a/app/Services/Tmux/Scripts/monitor.php b/app/Services/Tmux/Scripts/monitor.php index 79bf2c589..ea47b5877 100644 --- a/app/Services/Tmux/Scripts/monitor.php +++ b/app/Services/Tmux/Scripts/monitor.php @@ -7,84 +7,14 @@ * This script runs in tmux pane 0.0 and continuously monitors the system, * collecting statistics and spawning tasks in other panes. * - * This is the modernized version that uses the new service architecture. + * This is a simple wrapper that calls the tmux:monitor artisan command. */ -// Bootstrap Laravel -// From: app/Services/Tmux/Scripts/monitor.php -// To: bootstrap/autoload.php (4 levels up) -require_once __DIR__.'/../../../../bootstrap/autoload.php'; +$artisan = dirname(__DIR__, 4).'/artisan'; -use App\Models\Settings; -use App\Services\Tmux\TmuxMonitorService; -use App\Services\Tmux\TmuxTaskRunner; -use App\Services\Tmux\TmuxOutput; +// Pass any arguments to the artisan command +$args = array_slice($argv, 1); +$argString = implode(' ', array_map('escapeshellarg', $args)); -try { - // Get session name - $sessionName = Settings::settingValue('tmux_session') ?? 'nntmux'; - - // Initialize services - $monitor = new TmuxMonitorService; - $taskRunner = new TmuxTaskRunner($sessionName); - $output = new TmuxOutput; - - // Initialize monitor - $runVar = $monitor->initializeMonitor(); - - // Spawn IRC scraper immediately - try { - $taskRunner->runIRCScraper(['constants' => $runVar['constants']]); - } catch (Exception $e) { - logger()->error('Failed to spawn IRC scraper: '.$e->getMessage()); - } - - cli()->header('Tmux Monitor Started'); - echo "Session: {$sessionName}\n"; - echo "Press Ctrl+C to stop (or set exit flag in settings)\n\n"; - - // Main monitoring loop - while ($monitor->shouldContinue()) { - // Collect statistics - $runVar = $monitor->collectStatistics(); - - // Update display - $output->updateMonitorPane($runVar); - - // Run pane tasks if tmux is running - if ((int) ($runVar['settings']['is_running'] ?? 0) === 1) { - $sequential = (int) ($runVar['constants']['sequential'] ?? 0); - - // Determine which panes to run based on sequential mode - $panesToRun = match ($sequential) { - 0 => ['main', 'fixnames', 'removecrap', 'ppadditional', 'tv', 'movies', 'amazon', 'xxx'], - 1 => ['main', 'fixnames', 'removecrap', 'ppadditional', 'tv', 'movies', 'amazon', 'xxx'], - 2 => ['main', 'fixnames', 'amazon'], - default => [], - }; - - // Run each pane task using TmuxTaskRunner - foreach ($panesToRun as $paneName) { - try { - $taskRunner->runPaneTask($paneName, [], $runVar); - } catch (Exception $e) { - logger()->error("Failed to run pane {$paneName}: ".$e->getMessage()); - } - } - } - - // Increment iteration and sleep - $monitor->incrementIteration(); - sleep(10); - } - - cli()->info('Monitor stopped by exit flag'); - -} catch (Exception $e) { - cli()->error('Monitor failed: '.$e->getMessage()); - logger()->error('Tmux monitor error', [ - 'message' => $e->getMessage(), - 'trace' => $e->getTraceAsString(), - ]); - exit(1); -} +passthru("php {$artisan} tmux:monitor {$argString}", $exitCode); +exit($exitCode); diff --git a/app/Services/Tmux/Scripts/postprocess_pre.php b/app/Services/Tmux/Scripts/postprocess_pre.php index d316c5209..2ed8cd889 100644 --- a/app/Services/Tmux/Scripts/postprocess_pre.php +++ b/app/Services/Tmux/Scripts/postprocess_pre.php @@ -1,3 +1,4 @@ +#!/usr/bin/env php |null + */ + private ?array $decodeTable = null; + + /** + * Pre-computed decode translation table for escaped characters. + * Maps yEnc escaped byte to decoded byte: ((byte - 64) - 42) % 256 + * + * @var array|null + */ + private ?array $escapeDecodeTable = null; + + /** + * Initialize the decode translation tables (lazy initialization). + */ + private function initDecodeTables(): void + { + if ($this->decodeTable !== null) { + return; + } + + $this->decodeTable = []; + $this->escapeDecodeTable = []; + + for ($i = 0; $i < 256; $i++) { + $char = \chr($i); + // Standard decode: (byte - 42) % 256 + $this->decodeTable[$char] = \chr(($i - 42 + 256) % 256); + // Escape decode: ((byte - 64) - 42) % 256 + $this->escapeDecodeTable[$char] = \chr((($i - 64 - 42) + 512) % 256); + } + } + + /** + * Decode a yEnc encoded string. + * + * @param string $text The yEnc encoded text + * @param bool $ignore Whether to ignore errors (unused, kept for compatibility) + * @return string|false The decoded string, or false if not valid yEnc + * + * @throws RuntimeException If the data is corrupt or invalid + */ + public function decode(string &$text, bool $ignore = false): string|false + { + $crc = ''; + + // Extract the yEnc string itself. + // The pattern needs to handle binary content between =ybegin and =yend + if (preg_match( + '/=ybegin[^\r\n]*size=(\d+)[^\r\n]*\r\n([\s\S]*?)\r\n=yend[^\r\n]*size=(\d+)([^\r\n]*)/i', + $text, + $encoded + )) { + if (preg_match('/crc32=([0-9a-fA-F]+)/i', $encoded[4], $trailer)) { + $crc = trim($trailer[1]); + } + + $headerSize = (int) $encoded[1]; + $trailerSize = (int) $encoded[3]; + $encoded = $encoded[2]; + } else { + return false; + } + + // Make sure the header and trailer file sizes match up. + if ($headerSize !== $trailerSize) { + throw new RuntimeException( + 'Header and trailer file sizes do not match. This is a violation of the yEnc specification.' + ); + } + + // Remove line breaks from the string (use str_replace with array for speed). + $encoded = str_replace(["\r\n", "\r", "\n"], '', $encoded); + + // Fast decode using optimized method + $decoded = $this->fastDecode($encoded); + + // Make sure the decoded file size is the same as the size specified in the header. + $decodedLength = \strlen($decoded); + if ($decodedLength !== $headerSize) { + throw new RuntimeException( + "Header file size ({$headerSize}) and actual file size ({$decodedLength}) do not match. The file is probably corrupt." + ); + } + + // Check the CRC value + if ($crc !== '' && strcasecmp($crc, sprintf('%X', crc32($decoded))) !== 0) { + throw new RuntimeException('CRC32 checksums do not match. The file is probably corrupt.'); + } + + return $decoded; + } + + /** + * Fast yEnc decode using strtr and optimized escape handling. + * + * @param string $encoded The encoded string (without headers/line breaks) + * @return string The decoded string + */ + private function fastDecode(string $encoded): string + { + $this->initDecodeTables(); + + /** @var array $decodeTable */ + $decodeTable = $this->decodeTable; + /** @var array $escapeDecodeTable */ + $escapeDecodeTable = $this->escapeDecodeTable; + + // Check if there are any escape sequences + $escapePos = strpos($encoded, '='); + + if ($escapePos === false) { + // No escape sequences - use fast strtr translation + return strtr($encoded, $decodeTable); + } + + // Handle escape sequences + // First, process escape sequences by splitting on '=' + $parts = explode('=', $encoded); + $result = strtr($parts[0], $decodeTable); + + $count = \count($parts); + for ($i = 1; $i < $count; $i++) { + $part = $parts[$i]; + if ($part === '') { + continue; + } + // First character after '=' is the escaped character + $result .= $escapeDecodeTable[$part[0]]; + // Rest of the part is normal encoded data + if (isset($part[1])) { + $result .= strtr(substr($part, 1), $decodeTable); + } + } + + return $result; + } + + /** + * Decode a string of text encoded with yEnc. Ignores all errors. + * + * @param string $text The encoded text to decode. + * @return string The decoded yEnc string, or the input string if it's not yEnc. + */ + public function decodeIgnore(string &$text): string + { + if (preg_match('/^(=yBegin.*=yEnd[^$]*)$/ims', $text, $input)) { + // Extract the encoded data, removing headers and line breaks + $input = preg_replace('/(^=yBegin.*\r\n)/im', '', $input[1], 1); + $input = preg_replace('/(^=yPart.*\r\n)/im', '', $input, 1); + $input = preg_replace('/(^=yEnd.*)/im', '', $input, 1); + $input = str_replace(["\r\n", "\r", "\n"], '', trim($input)); + + // Use the fast decode method + $text = $this->fastDecode($input); + } + + return $text; + } + + /** + * Check if yEnc encoding/decoding is enabled. + * + * @return bool Always returns true (PHP implementation is always available) + */ + public function enabled(): bool + { + return true; + } + + /** + * Check if the given text appears to be yEnc encoded. + * + * @param string $text The text to check + * @return bool True if the text appears to be yEnc encoded + */ + public function isYencEncoded(string $text): bool + { + return (bool) preg_match('/^=yBegin.*=yEnd/ims', $text); + } + + /** + * Encode data using yEnc encoding. + * + * @param string $data The data to encode + * @param string $filename The filename to include in the header + * @param int $lineLength Maximum line length (1-254, default 128) + * @param bool $includeCrc32 Whether to include CRC32 checksum + * @return string The yEnc encoded string + * + * @throws RuntimeException If line length is invalid + */ + public function encode(string $data, string $filename, int $lineLength = 128, bool $includeCrc32 = true): string + { + // yEnc 1.3 draft doesn't allow line lengths of more than 254 bytes. + if ($lineLength > 254) { + $lineLength = 254; + } + + if ($lineLength < 1) { + throw new RuntimeException("{$lineLength} is not a valid line length."); + } + + $encoded = ''; + $stringLength = \strlen($data); + + // Encode each character of the string one at a time. + for ($i = 0; $i < $stringLength; $i++) { + $value = ((\ord($data[$i]) + 42) % 256); + + // Escape NULL, TAB, LF, CR, space, . and = characters. + $encoded .= match ($value) { + 0, 9, 10, 13, 32, 46, 61 => '='.\chr(($value + 64) % 256), + default => \chr($value), + }; + } + + $result = '=ybegin line='.$lineLength. + ' size='.$stringLength. + ' name='.trim($filename). + "\r\n". + trim(chunk_split($encoded, $lineLength)). + "\r\n=yend size=".$stringLength; + + // Add a CRC32 checksum if desired. + if ($includeCrc32) { + $result .= ' crc32='.strtolower(sprintf('%X', crc32($data))); + } + + return $result; + } + + /** + * Extract metadata from a yEnc encoded string without decoding. + * + * @param string $text The yEnc encoded text + * @return array{name: string|null, size: int|null, line: int|null, crc32: string|null}|null + */ + public function extractMetadata(string $text): ?array + { + if (! preg_match('/=ybegin\s+(.+?)\r\n/i', $text, $headerMatch)) { + return null; + } + + $header = $headerMatch[1]; + $metadata = [ + 'name' => null, + 'size' => null, + 'line' => null, + 'crc32' => null, + ]; + + // Extract name + if (preg_match('/name=(.+?)(?:\s|$)/i', $header, $match)) { + $metadata['name'] = trim($match[1]); + } + + // Extract size + if (preg_match('/size=(\d+)/i', $header, $match)) { + $metadata['size'] = (int) $match[1]; + } + + // Extract line length + if (preg_match('/line=(\d+)/i', $header, $match)) { + $metadata['line'] = (int) $match[1]; + } + + // Extract CRC32 from trailer + if (preg_match('/=yend.*crc32=([0-9a-fA-F]+)/i', $text, $match)) { + $metadata['crc32'] = strtoupper($match[1]); + } + + return $metadata; + } +} + diff --git a/bootstrap/autoload.php b/bootstrap/autoload.php deleted file mode 100644 index ed22ec486..000000000 --- a/bootstrap/autoload.php +++ /dev/null @@ -1,17 +0,0 @@ -make(); - -$dotenv = Dotenv::create($repository, dirname(__DIR__, 1), null)->load(); - -/** @var Kernel $kernel */ -$kernel = app(Kernel::class); -$kernel->bootstrap(); diff --git a/config/app.php b/config/app.php index c9e465391..b56ff81cf 100644 --- a/config/app.php +++ b/config/app.php @@ -24,6 +24,7 @@ return [ 'RedisManager' => Illuminate\Support\Facades\Redis::class, 'UserVerification' => Jrean\UserVerification\Facades\UserVerification::class, 'Gravatar' => Creativeorange\Gravatar\Facades\Gravatar::class, + 'Yenc' => App\Facades\Yenc::class, ])->toArray(), ]; diff --git a/misc/testing/DB/add_movieinfo_id.php b/misc/testing/DB/add_movieinfo_id.php deleted file mode 100644 index ac594e2e8..000000000 --- a/misc/testing/DB/add_movieinfo_id.php +++ /dev/null @@ -1,51 +0,0 @@ -whereNotNull('imdbid')->where('imdbid', '<>', '0000000')->get(['imdbid', 'id']); - -DB::statement(' - DROP TABLE IF EXISTS movie_temp; - CREATE TABLE movie_temp ( - releases_id INT(11), - imdbid VARCHAR(15) - ) - ENGINE=InnoDB - DEFAULT CHARACTER SET utf8 - COLLATE utf8_unicode_ci; - '); - -$count = $sql->count(); - -echo 'Copying '.$count.' imdbid values'.PHP_EOL; - -foreach ($sql as $movie) { - DB::table('movie_temp')->insert(['releases_id' => $movie['id'], 'imdbid' => $movie['imdbid']]); - echo '.'; -} - -echo PHP_EOL.'Finished copying '.$sql->count().' imdbid values'.PHP_EOL; - -echo 'Updating releases table with new values'.PHP_EOL; - -foreach (DB::table('movie_temp')->get() as $imdbid) { - $movieinfo = MovieInfo::query()->where('imdbid', $imdbid->imdbid)->first(['id']); - Release::query()->where('id', $imdbid->releases_id)->update(['movieinfo_id' => $movieinfo['id']]); - echo '.'; -} - -echo 'Finished inserting new values into releases table'.PHP_EOL; - -$check = Release::query()->whereNotNull('movieinfo_id')->count('id'); - -if ($check === $count) { - DB::statement('DROP TABLE movie_temp'); -} diff --git a/misc/testing/DB/change_imdb_column.php b/misc/testing/DB/change_imdb_column.php deleted file mode 100644 index d38a1b700..000000000 --- a/misc/testing/DB/change_imdb_column.php +++ /dev/null @@ -1,52 +0,0 @@ -whereNotNull('imdbid')->where('imdbid', '<>', '0000000')->get(['imdbid', 'id']); - -DB::unprepared(' - DROP TABLE IF EXISTS movie_temp; - CREATE TABLE movie_temp ( - releases_id INT(11), - imdbid VARCHAR(15) - ) - ENGINE=InnoDB - DEFAULT CHARACTER SET utf8 - COLLATE utf8_unicode_ci; - '); -DB::commit(); -$count = $sql->count(); - -echo 'Copying '.$count.' imdbid values'.PHP_EOL; - -foreach ($sql as $movie) { - DB::table('movie_temp')->insert(['releases_id' => $movie['id'], 'imdbid' => str_pad($movie['imdbid'], 7, '0', STR_PAD_LEFT)]); - echo '.'; -} - -echo PHP_EOL.'Finished copying '.$sql->count().' imdbid values'.PHP_EOL; - -DB::statement('ALTER TABLE releases DROP imdbid'); -DB::statement('ALTER TABLE releases ADD imdbid VARCHAR(15) DEFAULT NULL'); - -echo 'Updating releases table with new values'.PHP_EOL; - -foreach (DB::table('movie_temp')->get() as $imdbid) { - DB::table('releases')->where('id', $imdbid->releases_id)->update(['imdbid' => $imdbid->imdbid]); - echo '.'; -} - -echo 'Finished inserting new values into releases table'.PHP_EOL; - -$check = Release::query()->whereNotNull('imdbid')->where('imdbid', '<>', '0000000')->count('id'); - -if ($check === $count) { - DB::statement('DROP TABLE movie_temp'); -} diff --git a/misc/testing/DB/mark_as_passworded.php b/misc/testing/DB/mark_as_passworded.php deleted file mode 100644 index 8c382281e..000000000 --- a/misc/testing/DB/mark_as_passworded.php +++ /dev/null @@ -1,25 +0,0 @@ -where('passworded', '=', 1)->select(['releases_id'])->groupBy('releases_id')->get(); - -$count1 = $count2 = 0; -if ($passFiles->isNotEmpty()) { - $count1 = $passFiles->count(); - if ($count1 > 0) { - foreach ($passFiles as $passFile) { - $release = Release::query()->where('id', $passFile->releases_id)->where('passwordstatus', '=', 0)->update(['passwordstatus' => Releases::PASSWD_RAR]); - if ($release !== 0) { - $count2++; - } - echo '.'; - } - } -} -cli()->info($count2.' releases marked as passworded'); diff --git a/misc/testing/DB/move_tmux_to_settings.php b/misc/testing/DB/move_tmux_to_settings.php deleted file mode 100644 index e3c98b349..000000000 --- a/misc/testing/DB/move_tmux_to_settings.php +++ /dev/null @@ -1,18 +0,0 @@ -get(); - -foreach ($tmux as $item) { - echo 'Inserting '.$item->setting.' into settings table'.PHP_EOL; - App\Models\Settings::insertOrIgnore( - [ - 'section' => 'site', - 'subsection' => 'tmux', - 'name' => $item->setting, - 'value' => $item->value, - 'setting' => $item->setting, - ] - ); -} diff --git a/misc/testing/DB/reset_postprocessing.php b/misc/testing/DB/reset_postprocessing.php deleted file mode 100755 index 526a294eb..000000000 --- a/misc/testing/DB/reset_postprocessing.php +++ /dev/null @@ -1,323 +0,0 @@ -header('Resetting all postprocessing'); - $qry = DB::select('SELECT id FROM releases'); - $affected = 0; - $total = \count($qry); - foreach ($qry as $releases) { - DB::update( - sprintf( - ' - UPDATE releases - SET consoleinfo_id = NULL, gamesinfo_id = 0, imdbid = NULL, musicinfo_id = NULL, - bookinfo_id = NULL, videos_id = 0, tv_episodes_id = 0, xxxinfo_id = 0, passwordstatus = -1, haspreview = -1, - jpgstatus = 0, videostatus = 0, audiostatus = 0, nfostatus = -1 - WHERE id = %d', - $releases->id - ) - ); - cli()->overWritePrimary('Resetting Releases: '.cli()->percentString(++$affected, $total)); - } -} -if (isset($argv[1]) && ($argv[1] === 'consoles' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::select('TRUNCATE TABLE consoleinfo'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all Console postprocessing'); - $where = ' WHERE consoleinfo_id IS NOT NULL AND categories_id BETWEEN '.Category::GAME_ROOT.' AND '.Category::GAME_OTHER; - } else { - cli()->header('Resetting all failed Console postprocessing'); - $where = ' WHERE consoleinfo_id IN (-2, 0) AND categories_id BETWEEN '.Category::GAME_ROOT.' AND '.Category::GAME_OTHER; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - if (! empty($qry)) { - $total = \count($qry); - } else { - $total = 0; - } - $concount = 0; - foreach ($qry as $releases) { - DB::update('UPDATE releases SET consoleinfo_id = NULL WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting Console Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' consoleinfoIDs reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'games' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::select('TRUNCATE TABLE gamesinfo'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all Games postprocessing'); - $where = ' WHERE gamesinfo_id != 0 AND categories_id = 4050'; - } else { - cli()->header('Resetting all failed Games postprocessing'); - $where = ' WHERE gamesinfo_id IN (-2, 0) AND categories_id = 4050'; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - - $total = 0; - if (! empty($qry)) { - $total = \count($qry); - } - - $concount = 0; - foreach ($qry as $releases) { - DB::update('UPDATE releases SET gamesinfo_id = 0 WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting Games Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' gameinfo_IDs reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'movies' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::select('TRUNCATE TABLE movieinfo'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all Movie postprocessing'); - $where = ' WHERE imdbid IS NOT NULL AND categories_id BETWEEN '.Category::MOVIE_ROOT.' AND '.Category::MOVIE_OTHER; - } else { - cli()->header('Resetting all failed Movie postprocessing'); - $where = ' WHERE imdbid IN (-2, 0) AND categories_id BETWEEN '.Category::MOVIE_ROOT.' AND '.Category::MOVIE_OTHER; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - if (! empty($qry)) { - $total = \count($qry); - } else { - $total = 0; - } - $concount = 0; - foreach ($qry as $releases) { - DB::update('UPDATE releases SET imdbid = NULL WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting Movie Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' imdbIDs reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'music' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::select('TRUNCATE TABLE musicinfo'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all Music postprocessing'); - $where = ' WHERE musicinfo_id IS NOT NULL AND categories_id BETWEEN '.Category::MUSIC_ROOT.' AND '.Category::MUSIC_OTHER; - } else { - cli()->header('Resetting all failed Music postprocessing'); - $where = ' WHERE musicinfo_id IN (-2, 0) AND categories_id BETWEEN '.Category::MUSIC_ROOT.' AND '.Category::MUSIC_OTHER; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - $total = \count($qry); - $concount = 0; - foreach ($qry as $releases) { - DB::update(sprintf('UPDATE releases SET musicinfo_id = NULL WHERE id = %s ', $releases->id)); - cli()->overWritePrimary('Resetting Music Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' musicinfo_ids reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'misc' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all Additional postprocessing'); - $where = ' WHERE ((haspreview != -1 AND haspreview != 0) OR (passwordstatus != -1 AND passwordstatus != 0) OR jpgstatus != 0 OR videostatus != 0 OR audiostatus != 0)'; - } else { - cli()->header('Resetting all failed Additional postprocessing'); - $where = ' WHERE ((haspreview < -1 OR haspreview = 0) OR (passwordstatus < -1 OR passwordstatus = 0) OR jpgstatus < 0 OR videostatus < 0 OR audiostatus < 0)'; - } - - $where .= ' AND categories_id IN ('.Category::OTHER_MISC.','.Category::OTHER_HASHED.')'; - - cli()->primary('SELECT id FROM releases'.$where); - $qry = DB::select('SELECT id FROM releases'.$where); - if (! empty($qry)) { - $total = \count($qry); - } else { - $total = 0; - } - $concount = 0; - foreach ($qry as $releases) { - DB::update('UPDATE releases SET passwordstatus = -1, haspreview = -1, jpgstatus = 0, videostatus = 0, audiostatus = 0 WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' Releases reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'tv' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::delete('DELETE v, va FROM videos v INNER JOIN videos_aliases va ON v.id = va.videos_id WHERE type = 0'); - DB::select('TRUNCATE TABLE tv_info'); - DB::select('TRUNCATE TABLE tv_episodes'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all TV postprocessing'); - $where = ' WHERE videos_id != 0 AND tv_episodes_id != 0 AND categories_id BETWEEN '.Category::TV_ROOT.' AND '.Category::TV_OTHER; - } else { - cli()->header('Resetting all failed TV postprocessing'); - $where = ' WHERE tv_episodes_id < 0 AND categories_id BETWEEN '.Category::TV_ROOT.' AND '.Category::TV_OTHER; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - if (! empty($qry)) { - $total = \count($qry); - } else { - $total = 0; - } - $concount = 0; - foreach ($qry as $releases) { - DB::update('UPDATE releases SET videos_id = 0, tv_episodes_id = 0 WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting TV Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' Video IDs reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'anime' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::select('TRUNCATE TABLE anidb_info'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all Anime postprocessing'); - $where = ' WHERE categories_id = '.Category::TV_ANIME; - } else { - cli()->header('Resetting all failed Anime postprocessing'); - $where = ' WHERE anidbid BETWEEN -2 AND -1 AND categories_id = '.Category::TV_ANIME; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - if (! empty($qry)) { - $total = \count($qry); - } else { - $total = 0; - } - $concount = 0; - foreach ($qry as $releases) { - DB::update('UPDATE releases SET anidbid = NULL WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting Anime Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' anidbIDs reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'books' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::select('TRUNCATE TABLE bookinfo'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all Book postprocessing'); - $where = ' WHERE bookinfo_id IS NOT NULL AND categories_id BETWEEN '.Category::BOOKS_ROOT.' AND '.Category::BOOKS_UNKNOWN; - } else { - cli()->header('Resetting all failed Book postprocessing'); - $where = ' WHERE bookinfo_id IN (-2, 0) AND categories_id BETWEEN '.Category::BOOKS_ROOT.' AND '.Category::BOOKS_UNKNOWN; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - $total = \count($qry); - $concount = 0; - foreach ($qry as $releases) { - DB::update('UPDATE releases SET bookinfo_id = NULL WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting Book Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' bookinfoIDs reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'xxx' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::select('TRUNCATE TABLE xxxinfo'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all XXX postprocessing'); - $where = ' WHERE xxxinfo_id != 0 AND categories_id BETWEEN '.Category::XXX_ROOT.' AND '.Category::XXX_X264; - } else { - cli()->header('Resetting all failed XXX postprocessing'); - $where = ' WHERE xxxinfo_id IN (-2, 0) AND categories_id BETWEEN '.Category::XXX_ROOT.' AND '.Category::XXX_X264; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - $concount = 0; - $total = \count($qry); - foreach ($qry as $releases) { - DB::update('UPDATE releases SET xxxinfo_id = 0 WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting XXX Releases: '.cli()->percentString( - ++$concount, - $total - )); - } - cli()->header(PHP_EOL.number_format($concount).' xxxinfo_IDs reset.'); -} -if (isset($argv[1]) && ($argv[1] === 'nfos' || $argv[1] === 'all')) { - $ran = true; - if (isset($argv[3]) && $argv[3] === 'truncate') { - DB::select('TRUNCATE TABLE release_nfos'); - } - if (isset($argv[2]) && $argv[2] === 'true') { - cli()->header('Resetting all NFO postprocessing'); - $where = ' WHERE nfostatus != -1'; - } else { - cli()->header('Resetting all failed NFO postprocessing'); - $where = ' WHERE nfostatus < -1'; - } - - $qry = DB::select('SELECT id FROM releases'.$where); - $concount = 0; - $total = \count($qry); - foreach ($qry as $releases) { - DB::update('UPDATE releases SET nfostatus = -1 WHERE id = '.$releases->id); - cli()->overWritePrimary('Resetting NFO Releases: '.cli()->percentString(++$concount, $total)); - } - cli()->header(PHP_EOL.number_format($concount).' NFOs reset.'); -} - -if ($ran === false) { - cli()->error( - 'This script will reset postprocessing per category.'.PHP_EOL - .'It can also truncate the associated tables.'.PHP_EOL - .'To reset only those that have previously failed, those without covers, samples, previews, etc. use the second argument false.'.PHP_EOL - .'To reset even those previously post processed, use the second argument true.'.PHP_EOL - .'To truncate the associated table, use the third argument truncate.'.PHP_EOL.PHP_EOL - .'php reset_postprocessing.php consoles true ...: To reset all consoles.'.PHP_EOL - .'php reset_postprocessing.php games true ...: To reset all games.'.PHP_EOL - .'php reset_postprocessing.php movies true ...: To reset all movies.'.PHP_EOL - .'php reset_postprocessing.php music true ...: To reset all music.'.PHP_EOL - .'php reset_postprocessing.php misc true ...: To reset all misc.'.PHP_EOL - .'php reset_postprocessing.php tv true ...: To reset all tv.'.PHP_EOL - .'php reset_postprocessing.php anime true ...: To reset all anime.'.PHP_EOL - .'php reset_postprocessing.php books true ...: To reset all books.'.PHP_EOL - .'php reset_postprocessing.php xxx true ...: To reset all xxx.'.PHP_EOL - .'php reset_postprocessing.php nfos true ...: To reset all nfos.'.PHP_EOL - .'php reset_postprocessing.php all true ...: To reset everything.'.PHP_EOL - ); - exit(); -} -echo PHP_EOL; diff --git a/misc/testing/Dev/clean_nzbs.php b/misc/testing/Dev/clean_nzbs.php deleted file mode 100644 index 118a85d07..000000000 --- a/misc/testing/Dev/clean_nzbs.php +++ /dev/null @@ -1,78 +0,0 @@ -error("This script can remove all nzbs not found in the db and all releases with no nzbs found. It can also move invalid nzbs.\n\n" - ."php $argv[0] true ...: For a dry run, to see how many would be moved.\n" - ."php $argv[0] move ...: Move NZBs that are possibly bad or have no release. They are moved into this folder: $dir"); - exit(); -} - -if (! File::isDirectory($dir) && ! File::makeDirectory($dir)) { - exit("ERROR: Could not create folder [$dir].".PHP_EOL); -} - -$releases = new Releases; -$nzb = app(NzbService::class); -$nzbParser = app(NzbParserService::class); -$releaseImage = new ReleaseImageService; - -$timestart = now()->toRfc2822String(); -$checked = $moved = 0; -$couldbe = ($argv[1] === 'true') ? 'could be ' : ''; - -cli()->header('Getting List of nzbs to check against db.'); -cli()->header("Checked / {$couldbe}moved\n"); - -$dirItr = new RecursiveDirectoryIterator(config('nntux_settings.path_to_nzbs')); -$itr = new RecursiveIteratorIterator($dirItr, RecursiveIteratorIterator::LEAVES_ONLY); - -foreach ($itr as $filePath) { - $guid = stristr($filePath->getFilename(), '.nzb.gz', true); - if (File::isFile($filePath) && $guid) { - $nzbfile = unzipGzipFile($filePath); - $nzbContents = $nzbParser->parseNzbFileList($nzbfile, ['no-file-key' => false, 'strip-count' => true]); - if (! $nzbfile || ! @simplexml_load_string($nzbfile) || count($nzbContents) === 0) { - if ($argv[1] === 'move') { - rename($filePath, $dir.$guid.'.nzb.gz'); - } - $releases->deleteSingle(['g' => $guid, 'i' => false], $nzb, $releaseImage); - $moved++; - } - $checked++; - echo "$checked / $moved\r"; - } -} - -cli()->header("\n".number_format($checked).' nzbs checked, '.number_format($moved).' nzbs '.$couldbe.'moved.'); -cli()->header('Getting List of releases to check against nzbs.'); -cli()->header("Checked / releases deleted\n"); - -$checked = $deleted = 0; - -$res = Release::query()->select(['id', 'guid', 'nzbstatus'])->get(); -foreach ($res as $row) { - $nzbpath = $nzb->getNzbPath($row->guid); - if (! File::isFile($nzbpath)) { - $deleted++; - $releases->deleteSingle(['g' => $row->guid, 'i' => $row->id], $nzb, $releaseImage); - } elseif ($row->nzbstatus !== 1) { - Release::where('id', $row->id)->update(['nzbstatus' => 1]); - } - $checked++; - echo "$checked / $deleted\r"; -} -cli()->header("\n".number_format($checked).' releases checked, '.number_format($deleted).' releases deleted.'); -cli()->header("Script started at [$timestart], finished at [".now()->toRfc2822String().']'); diff --git a/misc/testing/Dev/test-ReleaseCleaner.php b/misc/testing/Dev/test-ReleaseCleaner.php deleted file mode 100755 index 5de81ff2f..000000000 --- a/misc/testing/Dev/test-ReleaseCleaner.php +++ /dev/null @@ -1,72 +0,0 @@ -where('name', '=', $argv[1])->select(['id'])->first(); - -if ($group === null) { - exit('No group with name '.$argv[1].' found in the database.'); -} - -$releasesQuery = Release::query()->where('groups_id', $group->id); -if ((int) $argv[4] !== 0 && is_numeric($argv[4])) { - $releasesQuery->where('categories_id', '=', $argv[4]); -} -$releasesQuery->select(['name', 'searchname', 'fromname', 'size', 'id', 'postdate'])->orderBy('postdate')->limit($argv[2]); - -$releases = $releasesQuery->get(); - -if (\count($releases) === 0) { - exit('No releases found in your database for group '.$argv[1].PHP_EOL); -} - -$releaseCleaner = new ReleaseCleaningService; -$manticore = app(ManticoreSearchService::class); - -foreach ($releases as $release) { - echo '.'; - $newName = $releaseCleaner->releaseCleaner($release->name, $release->fromname, $argv[1]); - if (is_array($newName)) { - $newName = $newName['cleansubject']; - } - if ($newName !== $release['searchname']) { - echo 'Old name: '.$release->searchname.PHP_EOL; - echo 'New name: '.$newName.PHP_EOL.PHP_EOL; - - if ($rename === true) { - Release::query()->where('id', '=', $release->id)->update(['searchname' => $newName]); - $manticore->updateRelease($release->id); - } - } -} diff --git a/misc/testing/Dev/test_hash_algorithms.php b/misc/testing/Dev/test_hash_algorithms.php deleted file mode 100644 index f121c498b..000000000 --- a/misc/testing/Dev/test_hash_algorithms.php +++ /dev/null @@ -1,196 +0,0 @@ -_inputString = $inputString; - $this->_expectedString = [ - $expectedString, - strtolower($expectedString), - strtoupper($expectedString), - strrev($expectedString), - ]; - $this->_writeToFile = $writeToFile; - $this->_testStrings(); - } - - /** - * Test various hash algorithms on strings. - * - * @void - */ - protected function _testStrings() - { - if ($this->_writeToFile) { - File::put('hash_matches.txt', ''); - } - - $firstArray = $this->_hashesToArray($this->_inputString); - - $secondArray = []; - foreach ($firstArray as $key => $value) { - if (! $this->_writeToFile) { - if (\in_array($value, $this->_expectedString, false)) { - exit( - '['. - $this->_inputString. - ']=>['. - $key. - ']=>'. - $value. - ']'. - PHP_EOL - ); - } - } else { - File::put('hash_matches.txt', $key."\t\t".$value.PHP_EOL, FILE_APPEND); - } - $secondArray[$key] = $this->_hashesToArray($value); - } - - $thirdArray = []; - foreach ($secondArray as $key => $value) { - foreach ($value as $key2 => $value2) { - if (! $this->_writeToFile) { - if (\in_array($value2, $this->_expectedString, false)) { - exit( - '['. - $this->_inputString. - ']=>['. - $key. - ']=>['. - $firstArray[$key]. - ']=>['. - $key2. - ']=>['. - $value2. - ']'. - PHP_EOL - ); - } - } else { - File::put('hash_matches.txt', $key.' => '.$key2."\t\t".$value2.PHP_EOL, FILE_APPEND); - } - $thirdArray[$key][$key2] = $this->_hashesToArray($value2); - } - } - - foreach ($thirdArray as $key => $value) { - foreach ($value as $key2 => $value2) { - foreach ($value2 as $key3 => $value3) { - if (! $this->_writeToFile) { - if (in_array($value3, $this->_expectedString)) { - exit( - '['. - $this->_inputString. - ']=>['. - $key. - ']=>['. - $firstArray[$key]. - ']=>['. - $key2. - ']=>['. - $value2. - ']=>['. - $key3. - ']=>['. - $value3. - ']'. - PHP_EOL - ); - } - } else { - File::put( - 'hash_matches.txt', - $key.' => '.$key2.' => '.$key3."\t\t".$value3.PHP_EOL, - FILE_APPEND - ); - } - } - } - } - } - - /** - * Return various versions of a input string to hash. - * - * @param string $string - * @return array - */ - protected function _hashesToArray($string) - { - $strings = [ - 'input' => $string, - 'lower' => strtolower($string), - 'lower_reverse' => strtolower(strrev($string)), - 'upper_reverse' => strtoupper(strrev($string)), - 'upper' => strtoupper($string), - 'reverse' => strrev($string), - 'reverse_upper' => strrev(strtoupper($string)), - 'reverse_lower' => strrev(strtolower($string)), - ]; - - $hashTypes = ['md5', 'md4', 'sha1', 'sha256', 'sha512']; - $tmpArray = []; - foreach ($hashTypes as $hash) { - foreach ($strings as $key => $value) { - $tmpArray[$hash.'_'.$key] = hash($hash, $value, false); - } - } - - foreach ($strings as $key => $value) { - $tmpArray['input_'.$key] = $value; - $tmpArray['base64_'.$key] = base64_encode($value); - $tmpArray['crc32_'.$key] = crc32($value); - } - - return $tmpArray; - } -} - -new HashAlgorithms($argv[1], $argv[2], ((isset($argv[3]) && strtolower($argv[3]) === 'true') ? true : false)); diff --git a/misc/testing/NZB/nzb-reorg.php b/misc/testing/NZB/nzb-reorg.php deleted file mode 100755 index 768906234..000000000 --- a/misc/testing/NZB/nzb-reorg.php +++ /dev/null @@ -1,47 +0,0 @@ -toImmutable(); - -echo "\nReorganizing files to Level $newLevel from: $sourcePath This could take a while...\n"; -// $consoleTools = new \ConsoleTools(); -foreach ($objects as $filestoprocess => $nzbFile) { - if ($nzbFile->getExtension() != 'gz') { - continue; - } - - $newFileName = $nzb->getNzbPath( - str_replace('.nzb.gz', '', $nzbFile->getBasename()), - $newLevel, - true - ); - if ($newFileName != $nzbFile) { - rename($nzbFile, $newFileName); - chmod($newFileName, 0777); - } - $iFilesProcessed++; - if ($iFilesProcessed % 100 == 0) { - cli()->overWrite("Reorganized $iFilesProcessed"); - } -} - -Settings::query()->where(['name' => 'nzbsplitlevel'])->update(['value' => $argv[1]]); -cli()->overWrite("Processed $iFilesProcessed nzbs in ".$time->diffForHumans()."\n"); diff --git a/misc/testing/PostProc/check_covers.php b/misc/testing/PostProc/check_covers.php deleted file mode 100644 index a1ec6b798..000000000 --- a/misc/testing/PostProc/check_covers.php +++ /dev/null @@ -1,56 +0,0 @@ -echooutput = true; - - -$path2cover = storage_path('covers/movies/'); - -if (isset($argv[1]) && ($argv[1] === 'true' || $argv[1] === 'check')) { - $couldbe = $argv[1] === 'true' ? $couldbe = 'had ' : 'could have '; - $limit = $counterfixed = 0; - if (isset($argv[2]) && is_numeric($argv[2])) { - $limit = $argv[2]; - } - cli()->header('Scanning for releases missing covers'); - $res = DB::select('SELECT r.imdbid - FROM releases r - LEFT JOIN movieinfo m ON m.imdbid = r.imdbid - WHERE m.cover = 1 AND adddate > (NOW() - INTERVAL 24 HOUR) GROUP BY r.imdbid'); - - foreach ($res as $row) { - $nzbpath = $path2cover.$row->imdbid.'-cover.jpg'; - if (! file_exists($nzbpath)) { - $counterfixed++; - cli()->warning('Missing cover '.$nzbpath); - if ($argv[1] === 'true') { - $cover = $movie->updateMovieInfo($row->imdbid); - if ($cover === false || ! file_exists($nzbpath)) { - DB::update(sprintf('UPDATE movieinfo m SET m.cover = 0 WHERE m.imdbid = %d', $row->imdbid)); - } - } - } - - if (($limit > 0) && ($counterfixed >= $limit)) { - break; - } - } - cli()->header('Total releases missing covers that '.$couldbe.'their covers fixed = '.number_format($counterfixed)); -} else { - cli()->header("\nThis script checks if release covers actually exist on disk.\n\n" - ."Releases without covers may be reset for post-processing, thus regenerating them and related meta data.\n\n" - ."Useful for recovery after filesystem corruption, or as an alternative re-postprocessing tool.\n\n" - ."Optional LIMIT parameter restricts number of releases to be reset.\n\n" - ."php $argv[0] true ...:Sets all releases missing covers to be reset for post-processing.\n" - ."php $argv[0] check ...:Checks and displays all releases missing covers.\n" - ."php $argv[0] true 500 ...:Sets only 500 releases missing covers to be reset for post-processing.\n"); -} diff --git a/misc/testing/PostProc/check_previews.php b/misc/testing/PostProc/check_previews.php deleted file mode 100644 index 7755bf729..000000000 --- a/misc/testing/PostProc/check_previews.php +++ /dev/null @@ -1,57 +0,0 @@ -getPdo(); - - -$path2preview = storage_path('covers/preview'); - -if (isset($argv[1]) && ($argv[1] === 'true' || $argv[1] === 'check')) { - $releases = new Releases; - $nzb = app(NzbService::class); - $releaseImage = new ReleaseImageService; - - $couldbe = $argv[1] === 'true' ? $couldbe = 'were ' : 'could be '; - $limit = $counterfixed = 0; - if (isset($argv[2]) && is_numeric($argv[2])) { - $limit = $argv[2]; - } - cli()->header('Scanning for releases missing previews'); - $res = Release::query()->select('id', 'guid')->where(['haspreview' => 1])->get()->toArray(); - foreach ($res as $row) { - $nzbpath = $path2preview.$row['guid'].'_thumb.jpg'; - if (! file_exists($nzbpath)) { - $counterfixed++; - cli()->warning('Missing preview '.$nzbpath); - if ($argv[1] === 'true') { - $pdo->exec( - sprintf('UPDATE releases SET consoleinfo_id = NULL, gamesinfo_id = 0, imdbid = NULL, musicinfo_id = NULL, bookinfo_id = NULL, videos_id = 0, xxxinfo_id = 0, passwordstatus = -1, haspreview = -1, jpgstatus = 0, videostatus = 0, audiostatus = 0, nfostatus = -1 WHERE id = %s', $row['id']) - ); - } - } - - if (($limit > 0) && ($counterfixed >= $limit)) { - break; - } - } - cli()->header('Total releases missing previews that '.$couldbe.'reset for reprocessing= '.number_format($counterfixed)); -} else { - cli()->header("\nThis script checks if release previews actually exist on disk.\n\n" - ."Releases without previews may be reset for post-processing, thus regenerating them and related meta data.\n\n" - ."Useful for recovery after filesystem corruption, or as an alternative re-postprocessing tool.\n\n" - ."Optional LIMIT parameter restricts number of releases to be reset.\n\n" - ."php $argv[0] check [LIMIT] ...: Dry run, displays missing previews.\n" - ."php $argv[0] true [LIMIT] ...: Re-process releases missing previews.\n"); - exit(); -} diff --git a/misc/testing/PostProc/getConsole.php b/misc/testing/PostProc/getConsole.php deleted file mode 100644 index 5ab9af5ba..000000000 --- a/misc/testing/PostProc/getConsole.php +++ /dev/null @@ -1,44 +0,0 @@ -getPdo(); -$console = new ConsoleService; - - -$res = $pdo->query( - sprintf( - 'SELECT searchname, id FROM releases WHERE consoleinfo_id IS NULL AND categories_id - BETWEEN %s AND %s ORDER BY id DESC', - Category::GAME_ROOT, - Category::GAME_OTHER - ) -); -if ($res instanceof Traversable) { - cli()->header('Updating console info for '.number_format($res->rowCount()).' releases.'); - - foreach ($res as $arr) { - $starttime = now()->timestamp; - $gameInfo = $console->parseTitle($arr['searchname']); - if ($gameInfo !== false) { - $game = $console->updateConsoleInfo($gameInfo); - if ($game === false) { - cli()->primary($gameInfo['release'].' not found'); - } - } - - // amazon limits are 1 per 1 sec - $diff = floor((now()->timestamp - $starttime) * 1000000); - if (1000000 - $diff > 0) { - cli()->alternate('Sleeping'); - usleep(1000000 - $diff); - } - } -} diff --git a/misc/testing/PostProc/getGameCovers.php b/misc/testing/PostProc/getGameCovers.php deleted file mode 100644 index b4d7e82a5..000000000 --- a/misc/testing/PostProc/getGameCovers.php +++ /dev/null @@ -1,44 +0,0 @@ -getPdo(); -$game = new GamesService; - - -$res = $pdo->query( - sprintf('SELECT id, title FROM gamesinfo WHERE cover = 0 ORDER BY id DESC LIMIT 100') -); -$total = $res->rowCount(); -if ($total > 0) { - cli()->header('Updating game covers for '.number_format($total).' releases.'); - - foreach ($res as $arr) { - $starttime = now()->timestamp; - $gameInfo = $game->parseTitle($arr['title']); - if ($gameInfo !== false) { - cli()->primary('Looking up: '.$gameInfo['release']); - $gameData = $game->updateGamesInfo($gameInfo); - if ($gameData === false) { - cli()->primary($gameInfo['release'].' not found'); - } else { - if (file_exists(storage_path('covers/games/').$gameData.'.jpg')) { - $pdo->exec(sprintf('UPDATE gamesinfo SET cover = 1 WHERE id = %d', $arr['id'])); - } - } - } - - // Rate limiting - 1 per second - $diff = floor((now()->timestamp - $starttime) * 1000000); - if (1000000 - $diff > 0) { - cli()->alternate('Sleeping'); - usleep(1000000 - $diff); - } - } -} diff --git a/misc/testing/PostProc/getImdb.php b/misc/testing/PostProc/getImdb.php deleted file mode 100644 index 3a0623af6..000000000 --- a/misc/testing/PostProc/getImdb.php +++ /dev/null @@ -1,35 +0,0 @@ -getPdo(); -$movie = new MovieService(); -$movie->echooutput = true; - - -$movies = $pdo->query('SELECT imdbid FROM movieinfo WHERE tmdbid = 0 ORDER BY id ASC'); -if ($movies instanceof Traversable) { - $count = $movies->rowCount(); - if ($count > 0) { - cli()->header('Updating movie info for '.number_format($count).' movies.'); - - foreach ($movies as $mov) { - $startTime = now()->timestamp; - $mov = $movie->updateMovieInfo($mov['imdbid']); - - // tmdb limits are 30 per 10 sec, not certain for imdb - $diff = floor((now()->timestamp - $startTime) * 1000000); - if (333333 - $diff > 0) { - echo "sleeping\n"; - usleep(333333 - $diff); - } - } - } else { - cli()->header('No movies to update'); - } -} diff --git a/misc/testing/PostProc/getMovieCovers.php b/misc/testing/PostProc/getMovieCovers.php deleted file mode 100644 index 4862f990c..000000000 --- a/misc/testing/PostProc/getMovieCovers.php +++ /dev/null @@ -1,24 +0,0 @@ -echooutput = true; - - -$movies = MovieInfo::query()->where('cover', '=', 0)->orderBy('year')->orderByDesc('id')->get(['imdbid']); -$count = $movies->count(); -if ($count > 0) { - cli()->primary('Updating '.number_format($count).' movie covers.'); - foreach ($movies as $mov) { - $startTime = now()->timestamp; - $mov = $movie->updateMovieInfo($mov['imdbid']); - } -} else { - cli()->header('No movie covers to update'); -} diff --git a/misc/testing/PostProc/getTraktData.php b/misc/testing/PostProc/getTraktData.php deleted file mode 100644 index e041a19ec..000000000 --- a/misc/testing/PostProc/getTraktData.php +++ /dev/null @@ -1,34 +0,0 @@ -echooutput = true; - - -$movies = MovieInfo::query()->where('imdbid', '<>', 0)->where('traktid', '=', 0)->get(['imdbid']); -$count = $movies->count(); -if ($count > 0) { - cli()->primary('Updating '.number_format($count).' movies for TraktTV id.'); - foreach ($movies as $mov) { - $traktTv = new TraktProvider(); - $traktmovie = $traktTv->client->getMovieSummary('tt'.$mov['imdbid'], 'full'); - if ($traktmovie !== false) { - cli()->info('Updating IMDb id: tt'.$mov['imdbid']); - $trakt = $movie->parseTraktTv($traktmovie); - if ($trakt === true) { - cli()->info('Added traktid: '.$traktmovie['ids']['trakt']); - } else { - cli()->info('No traktid found.'); - } - } - } -} else { - cli()->header('No movies to update'); -} diff --git a/misc/testing/PostProc/getXXXCovers.php b/misc/testing/PostProc/getXXXCovers.php deleted file mode 100644 index 0d4306e87..000000000 --- a/misc/testing/PostProc/getXXXCovers.php +++ /dev/null @@ -1,33 +0,0 @@ -primary('Updating '.number_format(\count($movies)).' XXX movie covers.'); -foreach ($movies as $mov) { - $starttime = now()->timestamp; - $result = $pipeline->processMovie($mov->title); - - if ($result['status'] === 'matched') { - echo cli()->primary('Updated: '.$mov->title); - } else { - echo cli()->warning('No match found for: '.$mov->title); - } - - // sleep so that it's not ddos' the site - $diff = floor((now()->timestamp - $starttime) * 1000000); - if (333333 - $diff > 0) { - echo "\nsleeping\n"; - usleep(333333 - $diff); - } -} -echo "\n"; diff --git a/misc/testing/PostProc/getXXXSamples.php b/misc/testing/PostProc/getXXXSamples.php deleted file mode 100644 index fdbf54c53..000000000 --- a/misc/testing/PostProc/getXXXSamples.php +++ /dev/null @@ -1,59 +0,0 @@ -getPdo(); - - -$path2cover = storage_path('covers/sample/'); - -if (isset($argv[1]) && ($argv[1] === 'true' || $argv[1] === 'check')) { - $releaseImage = new ReleaseImageService; - $couldbe = $argv[1] === 'true' ? $couldbe = 'had ' : 'could have '; - $limit = $counterfixed = 0; - if (isset($argv[2]) && is_numeric($argv[2])) { - $limit = $argv[2]; - } - - cli()->header('Scanning for XXX UHD/HD/SD releases missing sample images'); - $res = $pdo->query(sprintf('SELECT r.id, r.guid AS guid, r.searchname AS searchname - FROM releases r - WHERE r.jpgstatus = 0 AND r.categories_id IN (%s, %s, %s) ORDER BY r.adddate DESC', Category::XXX_CLIPHD, Category::XXX_CLIPSD, Category::XXX_UHD)); - foreach ($res as $row) { - $nzbpath = $path2cover.$row['guid'].'_thumb.jpg'; - if (! file_exists($nzbpath)) { - $counterfixed++; - if ($argv[1] === 'true') { - $imgpath = 'http://pic4all.eu/images/'.$row['searchname'].'_1.jpg'; - // scan pic4all.eu for sample image - if (stripos($row['searchname'], 'SDCLiP') !== false) { - $row['searchname'] = strtolower(preg_replace('/.XXX(.720p|.1080p)?.MP4-SDCLiP/i', '', $row['searchname'])); - $imgpath = 'http://pic4all.eu/images/'.$row['searchname'].'.jpg'; - } - $sample = $releaseImage->saveImage($row['guid'].'_thumb', $imgpath, $releaseImage->jpgSavePath, 650, 650); - if ($sample !== 0) { - cli()->info('Downloaded sample for '.$row['searchname']); - $pdo->exec(sprintf('UPDATE releases SET jpgstatus = 1 WHERE id = %d', $row['id'])); - } else { - cli()->notice('Sample download failed!'); - $pdo->exec(sprintf('UPDATE releases SET jpgstatus = -2 WHERE id = %d', $row['id'])); - } - } - } - - if (($limit > 0) && ($counterfixed >= $limit)) { - break; - } - } - cli()->header('Total releases missing samples that '.$couldbe.'their samples updated = '.number_format($counterfixed)); -} else { - cli()->header("\nThis script checks if XXX release samples actually exist on disk.\n\n" - ."php $argv[0] check ...: Dry run, displays missing samples.\n" - ."php $argv[0] true ...: Update XXX releases missing samples.\n"); - exit(); -} diff --git a/misc/testing/PostProc/updateBookImages.php b/misc/testing/PostProc/updateBookImages.php deleted file mode 100644 index 914021b8b..000000000 --- a/misc/testing/PostProc/updateBookImages.php +++ /dev/null @@ -1,46 +0,0 @@ -error("\nThis script will check all images in covers/book and compare to db->bookinfo.\nTo run:\nphp $argv[0] true\n"); - exit(); -} - -$path2covers = storage_path('covers/book/'); - -$itr = File::allFiles($path2covers); -foreach ($itr as $filePath) { - if (is_file($filePath->getPathname()) && preg_match('/\d+\.jpg$/', $filePath->getPathname())) { - preg_match('/(\d+)\.jpg$/', $filePath->getPathname(), $hit); - if (isset($hit[1])) { - $run = BookInfo::query()->where('cover', '=', 0)->where('id', $hit[1])->update(['cover' => 1]); - if ($run >= 1) { - $covers++; - } else { - $run = BookInfo::query()->where('id', $hit[1])->select(['id'])->get(); - if ($run->count() === 0) { - cli()->info($filePath.' not found in db.'); - } - } - } - } -} - -$qry = BookInfo::query()->where('cover', '=', 1)->select(['id'])->get(); -foreach ($qry as $rows) { - if (! is_file($path2covers.$rows['id'].'.jpg')) { - BookInfo::query()->where(['cover' => 1, 'id' => $rows['id']])->update(['cover' => 0]); - cli()->info($path2covers.$rows['id'].'.jpg does not exist.'); - $deleted++; - } -} -cli()->header($covers.' covers set.'); -cli()->header($deleted.' books unset.'); diff --git a/misc/testing/PostProc/updateConsoleImages.php b/misc/testing/PostProc/updateConsoleImages.php deleted file mode 100644 index 22e589fd3..000000000 --- a/misc/testing/PostProc/updateConsoleImages.php +++ /dev/null @@ -1,56 +0,0 @@ -error("\nThis script will check all images in covers/console and compare to db->consoleinfo.\nTo run:\nphp $argv[0] true\n"); - exit(); -} - -$path2covers = storage_path('covers/console/'); - -$itr = File::allFiles($path2covers); -foreach ($itr as $filePath) { - if (is_file($filePath->getPathname()) && preg_match('/\d+\.jpg$/', $filePath->getPathname())) { - preg_match('/(\d+)\.jpg$/', $filePath->getPathname(), $hit); - if (isset($hit[1])) { - $run = ConsoleInfo::query()->where( - [ - 'cover' => 0, - 'id' => $hit[1], - ] - )->update(['cover' => 1]); - if ($run >= 1) { - $covers++; - } else { - $run = ConsoleInfo::query()->where('id', $hit[1])->value('id'); - if ($run === 0) { - cli()->info($filePath.' not found in db.'); - } - } - } - } -} - -$qry = ConsoleInfo::query()->where('cover', '=', 1)->value('id'); -foreach ($qry as $rows) { - if (! is_file($path2covers.$rows['id'].'.jpg')) { - ConsoleInfo::query()->where( - [ - ['cover' => 1], - ['id' => $rows['id']], - ] - )->update(['cover' => 0]); - cli()->info($path2covers.$rows['id'].'.jpg does not exist.'); - $deleted++; - } -} -cli()->header($covers.' covers set.'); -cli()->header($deleted.' consoles unset.'); diff --git a/misc/testing/PostProc/updateGamesImages.php b/misc/testing/PostProc/updateGamesImages.php deleted file mode 100644 index a65863455..000000000 --- a/misc/testing/PostProc/updateGamesImages.php +++ /dev/null @@ -1,48 +0,0 @@ -error("\nThis script will check all images in covers/games and compare to db->gamesinfo.\nTo run:\nphp $argv[0] true\n"); - exit(); -} - -$path2covers = storage_path('covers/games/'); - -$itr = File::allFiles($path2covers); -foreach ($itr as $filePath) { - if (is_file($filePath->getPathname()) && preg_match('/\d+\.jpg$/', $filePath->getPathname())) { - preg_match('/(\d+)\.jpg$/', basename($filePath->getPathname()), $hit); - if (isset($hit[1])) { - $run = GamesInfo::query()->where('cover', '=', 0)->where('id', $hit[1])->update(['cover' => 1]); - if ($run !== false) { - if ($run >= 1) { - $covers++; - } else { - $run = GamesInfo::query()->where('id', $hit[1])->select(['id'])->get(); - if ($run !== null && $run === 0) { - cli()->info($filePath->getPathname().' not found in db.'); - } - } - } - } - } -} - -$qry = GamesInfo::query()->where('cover', '=', 1)->select(['id'])->get(); -foreach ($qry as $rows) { - if (! is_file($path2covers.$rows['id'].'.jpg')) { - GamesInfo::query()->where(['cover' => 1, 'id' => $rows['id']])->update(['cover' => 0]); - cli()->info($path2covers.$rows['id'].'.jpg does not exist.'); - $deleted++; - } -} -cli()->header($covers.' covers set.'); -cli()->header($deleted.' games unset.'); diff --git a/misc/testing/PostProc/updateMovieImages.php b/misc/testing/PostProc/updateMovieImages.php deleted file mode 100644 index 2b7a5b0a8..000000000 --- a/misc/testing/PostProc/updateMovieImages.php +++ /dev/null @@ -1,69 +0,0 @@ -error("\nThis script will check all images in covers/movies and compare to db->movieinfo.\nTo run:\nphp $argv[0] true\n"); - exit(); -} - -$path2covers = storage_path('covers/movies'); - -$itr = File::allFiles($path2covers); -foreach ($itr as $filePath) { - if (is_file($filePath->getPathname()) && preg_match('/-cover\.jpg$/', $filePath->getPathname())) { - preg_match('/(\d+)-cover\.jpg$/', $filePath->getPathname(), $hit); - if (isset($hit[1])) { - $run = MovieInfo::query()->where('cover', '=', 0)->where('imdbid', $hit[1])->update(['cover' => 1]); - if ($run >= 1) { - $covers++; - } else { - $run = MovieInfo::query()->where('imdbid', '=', $hit[1])->select(['imdbid'])->get(); - if ($run->count() === 0) { - cli()->error($filePath.' not found in db.'); - } - } - } - } - if (is_file($filePath) && preg_match('/-backdrop\.jpg$/', $filePath->getPathname())) { - preg_match('/(\d+)-backdrop\.jpg$/', $filePath->getPathname(), $match1); - if (isset($match1[1])) { - $run = MovieInfo::query()->where(['backdrop' => 0, 'imdbid' => $match1[1]])->update(['backdrop' => 1]); - if ($run >= 1) { - $updated++; - } else { - $run = MovieInfo::query()->where('imdbid', $match1[1])->select(['imdbid'])->get(); - if ($run->count() === 0) { - cli()->error($filePath->getPathname().' not found in db.'); - } - } - } - } -} - -$qry = MovieInfo::query()->where('cover', '=', 1)->select(['imdbid'])->get(); -foreach ($qry as $rows) { - if (! is_file($path2covers.$rows['imdbid'].'-cover.jpg')) { - MovieInfo::query()->where('cover', '=', 1)->where('imdbid', $rows['imdbid'])->update(['cover' => 0]); - cli()->info($path2covers.$rows['imdbid'].'-cover.jpg does not exist.'); - $deleted++; - } -} -$qry1 = MovieInfo::query()->where('backdrop', '=', 1)->select(['imdbid'])->get(); -foreach ($qry1 as $rows) { - if (! is_file($path2covers.$rows['imdbid'].'-backdrop.jpg')) { - MovieInfo::query()->where('backdrop', '=', 1)->where('imdbid', $rows['imdbid'])->update(['backdrop' => 0]); - cli()->info($path2covers.$rows['imdbid'].'-backdrop.jpg does not exist.'); - $deleted++; - } -} -cli()->info($covers.' covers set.'); -cli()->info($updated.' backdrops set.'); -cli()->info($deleted.' movies unset.'); diff --git a/misc/testing/PostProc/updateMusicImages.php b/misc/testing/PostProc/updateMusicImages.php deleted file mode 100644 index 8dcae9f87..000000000 --- a/misc/testing/PostProc/updateMusicImages.php +++ /dev/null @@ -1,46 +0,0 @@ -error("\nThis script will check all images in covers/music and compare to db->musicinfo.\nTo run:\nphp $argv[0] true\n"); - exit(); -} - -$path2covers = storage_path('covers/music/'); - -$itr = File::allFiles($path2covers); -foreach ($itr as $filePath) { - if (is_file($filePath->getPathname()) && preg_match('/\d+\.jpg$/', $filePath->getPathname())) { - preg_match('/(\d+)\.jpg$/', $filePath->getPathname(), $hit); - if (isset($hit[1])) { - $run = MusicInfo::query()->where('cover', '=', 0)->where('id', $hit[1])->update(['cover' => 1]); - if ($run >= 1) { - $covers++; - } else { - $run = MusicInfo::query()->where('id', $hit[1])->select(['id'])->get(); - if ($run->count() === 0) { - cli()->info($filePath->getPathname().' not found in db.'); - } - } - } - } -} - -$qry = MusicInfo::query()->where('cover', '=', 1)->select(['id'])->get(); -foreach ($qry as $rows) { - if (! is_file($path2covers.$rows['id'].'.jpg')) { - MusicInfo::query()->where(['cover' => 1, 'id' => $rows['id']])->update(['cover' => 0]); - cli()->info($path2covers.$rows['id'].'.jpg does not exist.'); - $deleted++; - } -} -cli()->header($covers.' covers set.'); -cli()->header($deleted.' music unset.'); diff --git a/misc/testing/PostProc/updateXXXImages.php b/misc/testing/PostProc/updateXXXImages.php deleted file mode 100644 index 446eeeada..000000000 --- a/misc/testing/PostProc/updateXXXImages.php +++ /dev/null @@ -1,69 +0,0 @@ -error("\nThis script will check all images in covers/xxx and compare to db->xxxinfo.\nTo run:\nphp $argv[0] true\n"); - exit(); -} - -$path2covers = storage_path('covers/xxx/'); - -$itr = File::allFiles($path2covers); -foreach ($itr as $filePath) { - if (is_file($filePath->getPathname()) && preg_match('/-cover\.jpg$/', $filePath->getPathname())) { - preg_match('/(\d+)-cover\.jpg$/', $filePath->getPathname(), $hit); - if (isset($hit[1])) { - $run = XxxInfo::query()->where('cover', '=', 0)->where('id', $hit[1])->update(['cover' => 1]); - if ($run >= 1) { - $covers++; - } else { - $run = XxxInfo::query()->where('id', $hit[1])->select(['id'])->get(); - if ($run->count() === 0) { - cli()->info($filePath->getPathname().' not found in db.'); - } - } - } - } - if (is_file($filePath->getPathname()) && preg_match('/-backdrop\.jpg$/', $filePath->getPathname())) { - preg_match('/(\d+)-backdrop\.jpg$/', $filePath->getPathname(), $match1); - if (isset($match1[1])) { - $run = XxxInfo::query()->where(['backdrop' => 0, 'id' => $match1[1]])->update(['backdrop' => 1]); - if ($run >= 1) { - $updated++; - } else { - $run = XxxInfo::query()->where('id', $match1[1])->select(['id'])->get(); - if ($run->count() === 0) { - cli()->info($filePath->getPathname().' not found in db.'); - } - } - } - } -} - -$qry = XxxInfo::query()->where('cover', '=', 1)->select(['id'])->get(); -foreach ($qry as $rows) { - if (! is_file($path2covers.$rows['id'].'-cover.jpg')) { - XxxInfo::query()->where(['cover' => 1, 'id' => $rows['id']])->update(['cover' => 0]); - cli()->info($path2covers.$rows['id'].'-cover.jpg does not exist.'); - $deleted++; - } -} -$qry1 = XxxInfo::query()->where('backdrop', '=', 1)->select(['id'])->get(); -foreach ($qry1 as $rows) { - if (! is_file($path2covers.$rows['id'].'-backdrop.jpg')) { - XxxInfo::query()->where(['backdrop' => 1, 'id' => $rows['id']])->update(['backdrop' => 0]); - cli()->info($path2covers.$rows['id'].'-backdrop.jpg does not exist.'); - $deleted++; - } -} -cli()->header($covers.' covers set.'); -cli()->header($updated.' backdrops set.'); -cli()->header($deleted.' movies unset.'); diff --git a/misc/testing/Releases/delete_releases.php b/misc/testing/Releases/delete_releases.php deleted file mode 100644 index 21690a02d..000000000 --- a/misc/testing/Releases/delete_releases.php +++ /dev/null @@ -1,57 +0,0 @@ -info( - $n. - 'This deletes releases based on a list of criteria you pass.'.$n. - 'Usage:'.$n.$n. - 'List of supported criteria:'.$n. - 'fromname : Look for names of people who posted releases (the poster name). (modifiers: equals, like)'.$n. - 'groupname : Look in groups. (modifiers: equals, like)'.$n. - 'guid : Look for a specific guid. (modifiers: equals)'.$n. - 'name : Look for a name (the usenet name). (modifiers: equals, like)'.$n. - 'searchname : Look for a name (the search name). (modifiers: equals, like)'.$n. - 'size : Release must be (bigger than |smaller than |exactly) this size.(bytes) (modifiers: equals,bigger,smaller)'.$n. - 'adddate : Look for releases added to our DB (older than|newer than) x hours. (modifiers: bigger,smaller)'.$n. - 'postdate : Look for posted to usenet (older than|newer than) x hours. (modifiers: bigger,smaller)'.$n. - 'completion : Look for completion (less than) (modifiers: smaller)'.$n. - 'categories_id : Look for releases within specified category (modifiers: equals)'.$n. - 'imdbid : Look for releases with imdbid (modifiers: equals)'.$n. - 'rageid : Look for releases with rageid (modifiers: equals)'.$n. - 'totalpart : Look for releases with certain number of parts (modifiers: equals,bigger,smaller)'.$n. - 'nzbstatus : Look for releases with nzbstatus (modifiers: equals)'.$n.$n. - 'List of Modifiers:'.$n. - 'equals : Match must be exactly this. (fromname=equals="john" will only look for "john", not "johndoe")'.$n. - 'like : Match can be similar to this. Separate words using spaces(ie:"cars hdtv x264").'.$n. - ' (fromname=like="john" will look for any posters with john in it (ie:john@smith.com)'.$n. - 'bigger : Match must be bigger than this. (postdate=bigger="3" means older than 3 hours ago)'.$n. - 'smaller : Match must be smaller than this (postdate=smaller="3" means between now and 3 hours ago.'.$n.$n. - 'Extra:'.$n. - 'ignore : Ignore the user check. (before running we ask you if you want to run the query to delete)'.$n.$n. - 'Examples:'.$n. - $_SERVER['_'].' '.$argv[0].' groupname=equals="alt.binaries.teevee" searchname=like="olympics 2014" postdate=bigger="5"'.$n. - $_SERVER['_'].' '.$argv[0].' guid=equals="8fb5956bae3de4fb94edcc69da44d6883d586fd0"'.$n. - $_SERVER['_'].' '.$argv[0].' size=smaller="104857600" size=bigger="2048" groupname=like="movies"'.$n. - $_SERVER['_'].' '.$argv[0].' fromname=like="@XviD.net" groupname=equals="alt.binaries.movies.divx" ignore'.$n. - $_SERVER['_'].' '.$argv[0].' imdbid=equals=NULL categories_id=equals=2999 nzbstatus=equals=1 adddate=bigger=2880 # Remove other movie releases with non-cleaned names added > 120 days ago' - )); -} - -$RR = new ReleaseRemover; -// Remove argv[0] and send the array. -$RR->removeByCriteria(array_slice($argv, 1, $totalArgs - 1)); diff --git a/misc/testing/Releases/fixReleaseNames.php b/misc/testing/Releases/fixReleaseNames.php deleted file mode 100755 index 261e4edbd..000000000 --- a/misc/testing/Releases/fixReleaseNames.php +++ /dev/null @@ -1,131 +0,0 @@ -doConnect($compressedHeaders, true) : $nntp->doConnect()) !== true) { - $output->writeln('Unable to connect to usenet.'); - - return; - } - } - - switch ($argv[1]) { - case '3': - $nameFixingService->fixNamesWithNfo(1, $update, $other, $setStatus, $show); - break; - case '4': - $nameFixingService->fixNamesWithNfo(2, $update, $other, $setStatus, $show); - break; - case '5': - $nameFixingService->fixNamesWithFiles(1, $update, $other, $setStatus, $show); - break; - case '6': - $nameFixingService->fixNamesWithFiles(2, $update, $other, $setStatus, $show); - break; - case '7': - $nameFixingService->fixNamesWithPar2(1, $update, $other, $setStatus, $show, $nntp); - break; - case '8': - $nameFixingService->fixNamesWithPar2(2, $update, $other, $setStatus, $show, $nntp); - break; - case '9': - $nameFixingService->fixNamesWithMedia(1, $update, $other, $setStatus, $show); - break; - case '10': - $nameFixingService->fixNamesWithMedia(2, $update, $other, $setStatus, $show); - break; - case '11': - $nameFixingService->fixXXXNamesWithFiles(1, $update, $other, $setStatus, $show); - break; - case '12': - $nameFixingService->fixXXXNamesWithFiles(2, $update, $other, $setStatus, $show); - break; - case '13': - $nameFixingService->fixNamesWithSrr(1, $update, $other, $setStatus, $show); - break; - case '14': - $nameFixingService->fixNamesWithSrr(2, $update, $other, $setStatus, $show); - break; - case '15': - $nameFixingService->fixNamesWithParHash(1, $update, $other, $setStatus, $show); - break; - case '16': - $nameFixingService->fixNamesWithParHash(2, $update, $other, $setStatus, $show); - break; - case '17': - $nameFixingService->fixNamesWithMediaMovieName(1, $update, $other, $setStatus, $show); - break; - case '18': - $nameFixingService->fixNamesWithMediaMovieName(2, $update, $other, $setStatus, $show); - break; - case '19': - $nameFixingService->fixNamesWithCrc(1, $update, $other, $setStatus, $show); - break; - case '20': - $nameFixingService->fixNamesWithCrc(2, $update, $other, $setStatus, $show); - break; - default: - $output->writeln(''.PHP_EOL.'ERROR: Wrong argument, type php '.$argv[0].' to see a list of valid arguments.'); - exit(1); - } -} else { - $output->writeln([ - '', - 'You must supply 4 arguments.', - 'The 2nd argument, false, will display the results, but not change the name, type true to have the names changed.', - 'The 3rd argument, other, will only do against other categories, to do against all categories use all, or predb_id to process all not matched to predb.', - 'The 4th argument, yes, will set the release as checked, so the next time you run it will not be processed, to not set as checked type no.', - 'The 5th argument (optional), show, will display the release changes or only show a counter.', - '', - 'php '.$argv[0].' 3 false other no ...: Fix release names using NFO in the past 6 hours.', - 'php '.$argv[0].' 4 false other no ...: Fix release names using NFO.', - 'php '.$argv[0].' 5 false other no ...: Fix release names in misc categories using File Name in the past 6 hours.', - 'php '.$argv[0].' 6 false other no ...: Fix release names in misc categories using File Name.', - 'php '.$argv[0].' 7 false other no ...: Fix release names in misc categories using Par2 Files in the past 6 hours.', - 'php '.$argv[0].' 8 false other no ...: Fix release names in misc categories using Par2 Files.', - 'php '.$argv[0].' 9 false other no ...: Fix release names in misc categories using UID in the past 6 hours.', - 'php '.$argv[0].' 10 false other no ...: Fix release names in misc categories using UID.', - 'php '.$argv[0].' 11 false other no ...: Fix SDPORN XXX release names in misc categories using specific File Name in the past 6 hours.', - 'php '.$argv[0].' 12 false other no ...: Fix SDPORN XXX release names in misc categories using specific File Name.', - 'php '.$argv[0].' 13 false other no ...: Fix release names in misc categories using SRR files in the past 6 hours.', - 'php '.$argv[0].' 14 false other no ...: Fix release names in misc categories using SRR files.', - 'php '.$argv[0].' 15 false other no ...: Fix release names in misc categories using PAR2 hash_16K block in the past 6 hours.', - 'php '.$argv[0].' 16 false other no ...: Fix release names in misc categories using PAR2 hash_16K block.', - 'php '.$argv[0].' 17 false other no ...: Fix release names in misc categories using Mediainfo in the past 6 hours.', - 'php '.$argv[0].' 18 false other no ...: Fix release names in misc categories using Mediainfo.', - 'php '.$argv[0].' 19 false other no ...: Fix release names in misc categories using CRC32 in the past 6 hours.', - 'php '.$argv[0].' 20 false other no ...: Fix release names in misc categories using CRC32.', - '', - ]); - - exit(1); -} diff --git a/misc/testing/Releases/recategorize.php b/misc/testing/Releases/recategorize.php deleted file mode 100644 index 6143b3067..000000000 --- a/misc/testing/Releases/recategorize.php +++ /dev/null @@ -1,112 +0,0 @@ -error( - "\nThis script will attempt to re-categorize releases and is useful if changes have been made to Category.php.\n" - ."No updates will be done unless the category changes\n" - ."An optional last argument, false, will display the number of category changes that would be made\n" - ."but will not update the database.\n\n" - ."php $argv[0] all ...: To process all releases.\n" - ."php $argv[0] misc ...: To process all releases in misc categories.\n" - ."php $argv[0] 155 ...: To process all releases in groupid 155.\n" - ."php $argv[0] '(155, 140)' ...: To process all releases in groupids 155 and 140.\n" - ); - exit(); -} - -reCategorize($argv); - -function reCategorize($argv): void -{ - - - if (isset($argv[1]) && (is_numeric($argv[1]) || preg_match('/\([\d, ]+\)/', $argv[1]))) { - cli()->header('Categorizing all releases in '.$argv[1].' using searchname. This can take a while, be patient.'); - } elseif (isset($argv[1]) && $argv[1] === 'misc') { - cli()->header('Categorizing all releases in misc categories using searchname. This can take a while, be patient.'); - } else { - cli()->header('Categorizing all releases using searchname. This can take a while, be patient.'); - } - $timeStart = now(); - $chgCount = categorizeRelease($argv, true); - $time = now()->diffInSeconds($timeStart, true); - if (! isset($argv[2])) { - cli()->header('Finished re-categorizing '.number_format($chgCount).' releases in '.$time.' seconds, using the searchname.').PHP_EOL; - } else { - cli()->header('Finished re-categorizing in '.$time.' seconds , using the searchname.'.PHP_EOL - .'This would have changed '.number_format($chgCount).' releases but no updates were done.').PHP_EOL; - } -} - -function categorizeRelease($argv, $echoOutput = false): int -{ - $update = true; - $query = Release::query()->select(['id', 'searchname', 'fromname', 'groups_id', 'categories_id']); - if (isset($argv[1]) && is_numeric($argv[1])) { - $query->where('groups_id', $argv[1]); - } elseif (isset($argv[1]) && preg_match('/\([\d, ]+\)/', $argv[1])) { - $query->whereIn('groups_id', $argv[1]); - } elseif (isset($argv[1]) && $argv[1] === 'misc') { - $query->whereIn('categories_id', Category::OTHERS_GROUP); - } - if (isset($argv[2]) && $argv[2] === 'test') { - $update = false; - } - $total = $query->count(); - - cli()->header('Categorizing ['.$total.'] releases. This can take a while, be patient.'); - - $relCount = $chgCount = 0; - if ($total > 0) { - $query->chunk('100', function ($results) use ($update, $relCount, $chgCount) { - $cat = new CategorizationService(); - foreach ($results as $result) { - $catId = $cat->determineCategory($result->groups_id, $result->searchname, $result->fromname); - if ((int) $result->categories_id !== (int) $catId['categories_id']) { - if ($update === true) { - Release::query()->where('id', $result->id)->update([ - 'iscategorized' => 1, - 'videos_id' => 0, - 'tv_episodes_id' => 0, - 'imdbid' => null, - 'musicinfo_id' => null, - 'consoleinfo_id' => null, - 'gamesinfo_id' => 0, - 'bookinfo_id' => 0, - 'anidbid' => null, - 'xxxinfo_id' => 0, - 'categories_id' => $catId['categories_id'], - ]); - Blacklight\NameFixer::echoChangedReleaseName([ - 'new_name' => $result->searchname, - 'old_name' => $result->searchname, - 'new_category' => $catId['categories_id'], - 'old_category' => $result->categories_id, - 'group' => $result->group->name, - 'releases_id' => $result->id, - 'method' => 'Recategorize', - ]); - } - $chgCount++; - } - $relCount++; - echo '*'; - } - }); - - if ($echoOutput) { - cli()->overWritePrimary('Re-Categorized: ['.number_format($chgCount).'] '.cli()->percentString($relCount, $total).PHP_EOL); - } - } - - return $chgCount; -} diff --git a/misc/testing/Releases/removeCrapReleases.php b/misc/testing/Releases/removeCrapReleases.php deleted file mode 100755 index a77b8c273..000000000 --- a/misc/testing/Releases/removeCrapReleases.php +++ /dev/null @@ -1,69 +0,0 @@ -error( - $n. - 'Run fixReleaseNames.php first to attempt to fix release names.'.$n. - 'This will miss some releases if you have not set fixReleaseNames to set the release as checked.'.$n.$n. - "php $argv[0] false Display full usage of this script.".$n. - "php $argv[0] true full Run this script with all options." - ) - ); -} -if ($argCnt === 2) { - if ($argv[1] === 'false') { - exit( - "php $argv[0] arg1 arg2 arg3 arg4".$n.$n. - 'arg1 (Required) = true/false'.$n. - ' true = Run this script and delete releases.'.$n. - ' false = Run this script and show what could be deleted.'.$n.$n. - 'arg2 (Required) = full/number'.$n. - ' full = Run without a time limit.'.$n. - ' number = Run on releases up to this old.'.$n.$n. - 'arg3 (Optional) = blacklist | blfiles | codec | executable | gibberish | hashed | huge | nzb | installbin | passworded | passwordurl | sample | scr | short | size | wmv_all'.$n. - ' blfiles = Remove releases using the enabled blacklists in admin section of site against filenames.'.$n. - ' codec = Remove releases where the release contains AVI or WMV file and is in x264 category (the spammer).'.$n. - ' executable = Remove releases containing an exe file.'.$n. - ' gibberish = Remove releases where the name is letters/numbers only and 15 characters or longer.'.$n. - ' hashed = Remove releases where the name is letters/numbers only and 25 characters or longer.'.$n. - ' nzb = Remove releases having 1 file that is an nzb file.'.$n. - ' installbin = Remove releases which contain an install.bin file.'.$n. - ' passworded = Remove releases which contain the word password in the title.'.$n. - ' passwordurl = Remove releases which contain a password.url file.'.$n. - ' sample = Remove releases that are smaller than 40MB more than 1 file and have sample in the title'.$n. - ' scr = Remove releases where .scr extension is found in the files or subject.'.$n. - ' short = Remove releases where the name is only numbers or letters and is 5 characters or less.'.$n. - ' wmv_all = Remove releases where the release contains WMV file in any group!!.'.$n. - ' size = Remove releases smaller than minimum size to create a release set in site settings.'.$n.$n. - 'examples:'.$n. - "php $argv[0] true 12 blacklist = Remove releases up to 12 hours old using site blacklists.".$n. - "php $argv[0] false full = Show what releases could have been removed.".$n. - "php $argv[0] true full installbin = Remove releases which containing an install.bin file.".$n. - "php $argv[0] true full blacklist 1 = Remove releases matching blacklist id 1.".$n - ); - } else { - exit(cli()->error("Wrong usage! Type php $argv[0] false")); - } -} -if ($argCnt < 3) { - exit(cli()->error("Wrong usage! Type php $argv[0] false")); -} - -if (isset($argv[3]) && $argv[3] === 'blacklist' && isset($argv[4])) { - $blacklistID = $argv[4]; -} - -$RR = new ReleaseRemover; -$RR->removeCrap($argv[1] === 'true' ? true : false, $argv[2], $argv[3] ?? '', isset($blacklistID) ? $argv[4] : ''); diff --git a/misc/testing/Tests/test_fanarttv_API.php b/misc/testing/Tests/test_fanarttv_API.php deleted file mode 100644 index 8b89d4dc9..000000000 --- a/misc/testing/Tests/test_fanarttv_API.php +++ /dev/null @@ -1,25 +0,0 @@ -getMovieFanArt((string) $argv[1]); - if ($moviefanart) { - dump($moviefanart); - } else { - cli()->error('Error retrieving Fanart.TV data.'); - exit(); - } -} else { - cli()->error('Invalid arguments. This script requires a number or string (TMDB or IMDb ID.'); - exit(); -} diff --git a/misc/testing/Tests/test_omdb_API.php b/misc/testing/Tests/test_omdb_API.php deleted file mode 100644 index a6425fdba..000000000 --- a/misc/testing/Tests/test_omdb_API.php +++ /dev/null @@ -1,33 +0,0 @@ -search((string) $argv[1], (string) $argv[2]); - if (is_object($search) && $search->data->Response !== 'False') { - dump($search->data->Search[0]->Title.PHP_EOL); - } - - // Use the first show found (highest match) and get the requested season/episode from $argv - if (is_object($search) && $search->data->Response !== 'False') { - $search = $omdb->fetch('i', $search->data->Search[0]->imdbID); - - dump($search); - } else { - cli()->error('Error retrieving OMDb API data.'); - exit(); - } -} else { - cli()->error('Invalid arguments. This script requires a text string (show name), and a second argument, movie or series.'); - exit(); -} diff --git a/misc/testing/Tests/test_tmdb_API.php b/misc/testing/Tests/test_tmdb_API.php deleted file mode 100755 index baf283336..000000000 --- a/misc/testing/Tests/test_tmdb_API.php +++ /dev/null @@ -1,75 +0,0 @@ -isConfigured()) { - exit(cli()->error('TMDB API key is not configured. Please set your API key in the configuration.')); - } - - $season = (int) $argv[2]; - $episode = (int) $argv[3]; - - // Search for a show - $series = $tmdbClient->searchTv((string) $argv[1]); - - // Use the first show found (highest match) and get the requested season/episode from $argv - $totalResults = $series !== null ? TmdbClient::getInt($series, 'total_results') : 0; - $results = $series !== null ? TmdbClient::getArray($series, 'results') : []; - - if (! empty($results) && $totalResults > 0) { - $showId = TmdbClient::getInt($results[0], 'id'); - - if ($showId === 0) { - exit(cli()->error('Invalid show ID returned from TMDB API.')); - } - - // Get TV show details with networks - $tvShowDetails = $tmdbClient->getTvShow($showId); - $networks = $tvShowDetails !== null ? TmdbClient::getArray($tvShowDetails, 'networks') : []; - - // Get alternative titles - $alternativeTitlesResponse = $tmdbClient->getTvAlternativeTitles($showId); - $alternativeTitles = $alternativeTitlesResponse !== null ? TmdbClient::getArray($alternativeTitlesResponse, 'results') : []; - - // Get external IDs - $externalIds = $tmdbClient->getTvExternalIds($showId); - - // Merge additional data into results - $results[0]['networks'] = $networks; - $results[0]['alternative_titles'] = $alternativeTitles; - $results[0]['external_ids'] = $externalIds ?? []; - - if ($season > 0 && $episode > 0) { - $episodeObj = $tmdbClient->getTvEpisode($showId, $season, $episode); - if ($episodeObj !== null) { - echo "Show: ".TmdbClient::getString($results[0], 'name')."\n"; - echo "Season: $season, Episode: $episode\n"; - print_r($episodeObj); - } else { - exit(cli()->error('Episode not found on TMDB API.')); - } - } elseif ($season === 0 && $episode === 0) { - $tvShowFull = $tmdbClient->getTvShow($showId); - if ($tvShowFull !== null) { - print_r($tvShowFull); - } - } else { - exit(cli()->error('Invalid episode data returned from TMDB API.')); - } - } else { - exit(cli()->error('Invalid show data returned from TMDB API.')); - } -} else { - exit(cli()->error('Invalid arguments. This script requires a text string (show name) followed by a season and episode number.')); -} diff --git a/misc/testing/Tests/test_trakt_API.php b/misc/testing/Tests/test_trakt_API.php deleted file mode 100755 index b9086a987..000000000 --- a/misc/testing/Tests/test_trakt_API.php +++ /dev/null @@ -1,29 +0,0 @@ -searchShows((string) $argv[1], 'show'); - - // Use the first show found (highest match) and get the requested season/episode from $argv - if (is_array($series)) { - $series = $trakt->getShowSummary($series[0]['show']['ids']['trakt'], 'full'); - $episode = $trakt->getEpisodeSummary($series['ids']['trakt'], (int) $argv[2], (int) $argv[3], 'full'); - - print_r($series); - print_r($episode); - } else { - exit(cli()->error('Error retrieving Trakt data.')); - } -} else { - exit(cli()->error('Invalid arguments. This script requires a text string (show name) followed by a season and episode number.')); -} diff --git a/misc/testing/Tests/test_tvdb_API.php b/misc/testing/Tests/test_tvdb_API.php deleted file mode 100755 index 6dadc25ab..000000000 --- a/misc/testing/Tests/test_tvdb_API.php +++ /dev/null @@ -1,68 +0,0 @@ -client->search()->search((string) $argv[1], ['type' => 'series']); - - // Use the first show found (highest match) and get the requested season/episode from $argv - if ($series) { - print_r($series[0]); - $initialEpisodeObj = ''; - - if ($season > 0 && $episode > 0) { - try { - $initialEpisodeObj = $tvDB->client->series()->episodes($series[0]->tvdb_id); - } catch (InvalidArgumentException $error) { - echo 'Invalid argument(s) used'.PHP_EOL; - - return false; - } catch (CanIHaveSomeCoffee\TheTVDbAPI\Exception\ParseException $error) { - if (str_starts_with($error->getMessage(), 'Could not decode JSON data') || str_starts_with($error->getMessage(), 'Incorrect data structure')) { - return false; - } - } catch (CanIHaveSomeCoffee\TheTVDbAPI\Exception\ResourceNotFoundException $error) { - return false; - } catch (CanIHaveSomeCoffee\TheTVDbAPI\Exception\UnauthorizedException $error) { - if (str_starts_with($error->getMessage(), 'Unauthorized')) { - return false; - } - } - - if ($initialEpisodeObj) { - foreach ($initialEpisodeObj as $episodeBaseRecord) { - if ($episodeBaseRecord->number === $episode && $episodeBaseRecord->seasonNumber === $season) { - $episodeObj = $episodeBaseRecord; - } - } - print_r($episodeObj); - } - } elseif ($season === 0 && $episode === 0) { - $initialEpisodeObj = $tvDB->client->series()->allEpisodes($series[0]->tvdb_id); - if (is_object($initialEpisodeObj)) { - foreach ($initialEpisodeObj as $ep) { - print_r($ep); - } - } - } else { - exit(cli()->error('Invalid episode data returned from TVDB API.')); - } - } else { - exit(cli()->error('Invalid show data returned from TVDB API.')); - } -} else { - exit(cli()->error('Invalid arguments. This script requires a text string (show name) followed by a season and episode number.') - ); -} diff --git a/misc/testing/Tests/test_tvmaze_API.php b/misc/testing/Tests/test_tvmaze_API.php deleted file mode 100755 index d7355e6a2..000000000 --- a/misc/testing/Tests/test_tvmaze_API.php +++ /dev/null @@ -1,46 +0,0 @@ -client->search((string) $argv[1]); - - // Use the first show found (highest match) and get the requested season/episode from $argv - if ($series) { - echo PHP_EOL.cli()->info('Server Time: '.$serverTime).PHP_EOL; - print_r($series[0]); - - if ($season > 0 and $episode > 0) { - $episodeObj = $tvmaze->client->getEpisodeByNumber($series[0]->id, $season, $episode); - if ($episodeObj) { - print_r($episodeObj); - } - } elseif ($season == 0 && $episode == 0) { - $episodeObj = $tvmaze->client->getEpisodesByShowID($series[0]->id); - if (is_array($episodeObj)) { - echo '*'; - foreach ($episodeObj as $ep) { - print_r($ep); - } - } - } else { - exit(cli()->error('Invalid episode data returned from TVMaze API.')); - } - } else { - exit(cli()->error('Invalid show data returned from TVMaze API.')); - } -} else { - exit(cli()->error('Invalid arguments. This script requires a text string (show name) followed by a season and episode number.')); -} diff --git a/misc/testing/add_api_guard_permissions.php b/misc/testing/add_api_guard_permissions.php deleted file mode 100644 index deb484fa9..000000000 --- a/misc/testing/add_api_guard_permissions.php +++ /dev/null @@ -1,19 +0,0 @@ -forget('spatie.permission.cache'); -Permission::create(['name' => 'preview', 'guard_name' => 'api']); -Permission::create(['name' => 'hideads', 'guard_name' => 'api']); -Permission::create(['name' => 'edit release', 'guard_name' => 'api']); -Permission::create(['name' => 'view console', 'guard_name' => 'api']); -Permission::create(['name' => 'view movies', 'guard_name' => 'api']); -Permission::create(['name' => 'view audio', 'guard_name' => 'api']); -Permission::create(['name' => 'view pc', 'guard_name' => 'api']); -Permission::create(['name' => 'view tv', 'guard_name' => 'api']); -Permission::create(['name' => 'view adult', 'guard_name' => 'api']); -Permission::create(['name' => 'view books', 'guard_name' => 'api']); -Permission::create(['name' => 'view other', 'guard_name' => 'api']); diff --git a/misc/testing/add_rss_guard_permissions.php b/misc/testing/add_rss_guard_permissions.php deleted file mode 100644 index 9ae0e1585..000000000 --- a/misc/testing/add_rss_guard_permissions.php +++ /dev/null @@ -1,19 +0,0 @@ -forget('spatie.permission.cache'); -Permission::create(['name' => 'preview', 'guard_name' => 'rss']); -Permission::create(['name' => 'hideads', 'guard_name' => 'rss']); -Permission::create(['name' => 'edit release', 'guard_name' => 'rss']); -Permission::create(['name' => 'view console', 'guard_name' => 'rss']); -Permission::create(['name' => 'view movies', 'guard_name' => 'rss']); -Permission::create(['name' => 'view audio', 'guard_name' => 'rss']); -Permission::create(['name' => 'view pc', 'guard_name' => 'rss']); -Permission::create(['name' => 'view tv', 'guard_name' => 'rss']); -Permission::create(['name' => 'view adult', 'guard_name' => 'rss']); -Permission::create(['name' => 'view books', 'guard_name' => 'rss']); -Permission::create(['name' => 'view other', 'guard_name' => 'rss']); diff --git a/misc/testing/nzb-import.php b/misc/testing/nzb-import.php deleted file mode 100644 index 1e2de1639..000000000 --- a/misc/testing/nzb-import.php +++ /dev/null @@ -1,83 +0,0 @@ -= $argv[5]) { - break; - } -} - -if ($i > 1) { - unset($files); - - // Check these user argument values, convert them to bool. - $deleteNZB = ($argv[2] === 'true'); - $deleteFailedNZB = ($argv[3] === 'true'); - $useNzbName = ($argv[4] === 'true'); - - // Create a new instance of NzbImportService and send it the file locations. - $NZBImport = new NzbImportService; - - $NZBImport->beginImport($nzbFiles, $useNzbName, $deleteNZB, $deleteFailedNZB); -} else { - echo 'Nothing found to import!'.$n; -} diff --git a/misc/testing/resend_activation_email.php b/misc/testing/resend_activation_email.php deleted file mode 100644 index cf5503008..000000000 --- a/misc/testing/resend_activation_email.php +++ /dev/null @@ -1,17 +0,0 @@ -info('Email has been sent'); -} else { - cli()->error('You need to provide user id as argument'); -} diff --git a/phpunit.xml b/phpunit.xml index 67d9612e9..08bceb8d7 100644 --- a/phpunit.xml +++ b/phpunit.xml @@ -1,5 +1,5 @@ - + tests/Install diff --git a/phpunit.xml.bak b/phpunit.xml.bak index b2b7cb350..789e5b11d 100644 --- a/phpunit.xml.bak +++ b/phpunit.xml.bak @@ -1,5 +1,5 @@ - + Blacklight diff --git a/tests/Feature/FanarttvApiTest.php b/tests/Feature/FanarttvApiTest.php new file mode 100644 index 000000000..8bccd8060 --- /dev/null +++ b/tests/Feature/FanarttvApiTest.php @@ -0,0 +1,118 @@ +fanartService = new FanartTvService; + } + + public function test_fanarttv_service_is_configured(): void + { + if (! $this->fanartService->isConfigured()) { + $this->markTestSkipped('Fanart.tv API key is not configured.'); + } + + $this->assertTrue($this->fanartService->isConfigured()); + } + + public function test_can_get_movie_fanart_by_imdb_id(): void + { + if (! $this->fanartService->isConfigured()) { + $this->markTestSkipped('Fanart.tv API key is not configured.'); + } + + // The Shawshank Redemption IMDb ID + $movieData = $this->fanartService->getMovieFanArt('tt0111161'); + + $this->assertNotNull($movieData); + $this->assertIsArray($movieData); + } + + public function test_can_get_movie_fanart_by_tmdb_id(): void + { + if (! $this->fanartService->isConfigured()) { + $this->markTestSkipped('Fanart.tv API key is not configured.'); + } + + // The Shawshank Redemption TMDB ID + $movieData = $this->fanartService->getMovieFanArt('278'); + + $this->assertNotNull($movieData); + $this->assertIsArray($movieData); + } + + public function test_can_get_movie_properties(): void + { + if (! $this->fanartService->isConfigured()) { + $this->markTestSkipped('Fanart.tv API key is not configured.'); + } + + // The Shawshank Redemption IMDb ID + $props = $this->fanartService->getMovieProperties('tt0111161'); + + // May return null if no cover AND backdrop available + if ($props !== null) { + $this->assertIsArray($props); + $this->assertArrayHasKey('title', $props); + } else { + $this->assertNull($props); + } + } + + public function test_can_get_tv_fanart(): void + { + if (! $this->fanartService->isConfigured()) { + $this->markTestSkipped('Fanart.tv API key is not configured.'); + } + + // Breaking Bad TVDB ID + $tvData = $this->fanartService->getTvFanArt('81189'); + + $this->assertNotNull($tvData); + $this->assertIsArray($tvData); + } + + public function test_can_get_best_tv_poster(): void + { + if (! $this->fanartService->isConfigured()) { + $this->markTestSkipped('Fanart.tv API key is not configured.'); + } + + // Breaking Bad TVDB ID + $poster = $this->fanartService->getBestTvPoster('81189'); + + // May return null if no poster available + if ($poster !== null) { + $this->assertIsString($poster); + $this->assertStringStartsWith('http', $poster); + } else { + $this->assertNull($poster); + } + } + + public function test_returns_null_for_invalid_id(): void + { + if (! $this->fanartService->isConfigured()) { + $this->markTestSkipped('Fanart.tv API key is not configured.'); + } + + $movieData = $this->fanartService->getMovieFanArt('tt9999999999'); + + $this->assertNull($movieData); + } +} + diff --git a/tests/Feature/OmdbApiTest.php b/tests/Feature/OmdbApiTest.php new file mode 100644 index 000000000..5a367b690 --- /dev/null +++ b/tests/Feature/OmdbApiTest.php @@ -0,0 +1,107 @@ +omdb = new OMDbAPI($apiKey); + } + } + + public function test_omdb_api_key_is_configured(): void + { + if ($this->omdb === null) { + $this->markTestSkipped('OMDb API key is not configured.'); + } + + $this->assertNotNull($this->omdb); + } + + public function test_can_search_for_movies(): void + { + if ($this->omdb === null) { + $this->markTestSkipped('OMDb API key is not configured.'); + } + + $search = $this->omdb->search('The Matrix', 'movie'); + + $this->assertIsObject($search); + $this->assertNotEquals('False', $search->data->Response); + $this->assertNotEmpty($search->data->Search); + } + + public function test_can_search_for_series(): void + { + if ($this->omdb === null) { + $this->markTestSkipped('OMDb API key is not configured.'); + } + + $search = $this->omdb->search('Breaking Bad', 'series'); + + $this->assertIsObject($search); + $this->assertNotEquals('False', $search->data->Response); + $this->assertNotEmpty($search->data->Search); + } + + public function test_can_fetch_by_imdb_id(): void + { + if ($this->omdb === null) { + $this->markTestSkipped('OMDb API key is not configured.'); + } + + // The Matrix IMDb ID + $result = $this->omdb->fetch('i', 'tt0133093'); + + $this->assertIsObject($result); + $this->assertNotEquals('False', $result->data->Response); + $this->assertEquals('The Matrix', $result->data->Title); + } + + public function test_returns_false_response_for_invalid_search(): void + { + if ($this->omdb === null) { + $this->markTestSkipped('OMDb API key is not configured.'); + } + + $search = $this->omdb->search('xyznonexistentmovie99999', 'movie'); + + $this->assertIsObject($search); + $this->assertEquals('False', $search->data->Response); + } + + public function test_search_result_has_expected_properties(): void + { + if ($this->omdb === null) { + $this->markTestSkipped('OMDb API key is not configured.'); + } + + $search = $this->omdb->search('The Matrix', 'movie'); + + if ($search->data->Response === 'False') { + $this->markTestSkipped('OMDb search returned no results.'); + } + + $firstResult = $search->data->Search[0]; + + $this->assertObjectHasProperty('Title', $firstResult); + $this->assertObjectHasProperty('imdbID', $firstResult); + $this->assertObjectHasProperty('Year', $firstResult); + } +} + diff --git a/tests/Feature/TmdbApiTest.php b/tests/Feature/TmdbApiTest.php new file mode 100644 index 000000000..ae31f82f2 --- /dev/null +++ b/tests/Feature/TmdbApiTest.php @@ -0,0 +1,118 @@ +tmdbClient = app(TmdbClient::class); + } + + public function test_tmdb_client_is_configured(): void + { + // Skip if not configured + if (! $this->tmdbClient->isConfigured()) { + $this->markTestSkipped('TMDB API key is not configured.'); + } + + $this->assertTrue($this->tmdbClient->isConfigured()); + } + + public function test_can_search_tv_shows(): void + { + if (! $this->tmdbClient->isConfigured()) { + $this->markTestSkipped('TMDB API key is not configured.'); + } + + $results = $this->tmdbClient->searchTv('Breaking Bad'); + + $this->assertNotNull($results); + $totalResults = TmdbClient::getInt($results, 'total_results'); + $this->assertGreaterThan(0, $totalResults); + } + + public function test_can_get_tv_show_details(): void + { + if (! $this->tmdbClient->isConfigured()) { + $this->markTestSkipped('TMDB API key is not configured.'); + } + + // Breaking Bad TMDB ID + $showId = 1396; + $details = $this->tmdbClient->getTvShow($showId); + + $this->assertNotNull($details); + $this->assertEquals('Breaking Bad', TmdbClient::getString($details, 'name')); + } + + public function test_can_get_tv_episode(): void + { + if (! $this->tmdbClient->isConfigured()) { + $this->markTestSkipped('TMDB API key is not configured.'); + } + + // Breaking Bad TMDB ID, Season 1, Episode 1 + $showId = 1396; + $episode = $this->tmdbClient->getTvEpisode($showId, 1, 1); + + $this->assertNotNull($episode); + $this->assertEquals('Pilot', TmdbClient::getString($episode, 'name')); + } + + public function test_can_get_external_ids(): void + { + if (! $this->tmdbClient->isConfigured()) { + $this->markTestSkipped('TMDB API key is not configured.'); + } + + // Breaking Bad TMDB ID + $showId = 1396; + $externalIds = $this->tmdbClient->getTvExternalIds($showId); + + $this->assertNotNull($externalIds); + $this->assertArrayHasKey('imdb_id', $externalIds); + } + + public function test_can_get_alternative_titles(): void + { + if (! $this->tmdbClient->isConfigured()) { + $this->markTestSkipped('TMDB API key is not configured.'); + } + + // Breaking Bad TMDB ID + $showId = 1396; + $alternativeTitles = $this->tmdbClient->getTvAlternativeTitles($showId); + + $this->assertNotNull($alternativeTitles); + } + + public function test_search_returns_null_for_invalid_query(): void + { + if (! $this->tmdbClient->isConfigured()) { + $this->markTestSkipped('TMDB API key is not configured.'); + } + + $results = $this->tmdbClient->searchTv('xyznonexistentshow12345'); + + // Should return results array but with 0 total_results + if ($results !== null) { + $totalResults = TmdbClient::getInt($results, 'total_results'); + $this->assertEquals(0, $totalResults); + } else { + $this->assertNull($results); + } + } +} + diff --git a/tests/Feature/TraktApiTest.php b/tests/Feature/TraktApiTest.php new file mode 100644 index 000000000..58afa4ed9 --- /dev/null +++ b/tests/Feature/TraktApiTest.php @@ -0,0 +1,132 @@ +traktService = new TraktService; + } + + public function test_trakt_service_is_configured(): void + { + if (! $this->traktService->isConfigured()) { + $this->markTestSkipped('Trakt.tv API key is not configured.'); + } + + $this->assertTrue($this->traktService->isConfigured()); + } + + public function test_can_search_for_shows(): void + { + if (! $this->traktService->isConfigured()) { + $this->markTestSkipped('Trakt.tv API key is not configured.'); + } + + $results = $this->traktService->searchShows('Breaking Bad', 'show'); + + $this->assertNotNull($results); + $this->assertIsArray($results); + $this->assertNotEmpty($results); + } + + public function test_can_get_show_summary(): void + { + if (! $this->traktService->isConfigured()) { + $this->markTestSkipped('Trakt.tv API key is not configured.'); + } + + // First search for Breaking Bad + $results = $this->traktService->searchShows('Breaking Bad', 'show'); + + if (empty($results)) { + $this->markTestSkipped('Could not find Breaking Bad on Trakt.tv.'); + } + + $traktId = $results[0]['show']['ids']['trakt']; + $summary = $this->traktService->getShowSummary($traktId, 'full'); + + $this->assertNotNull($summary); + $this->assertIsArray($summary); + $this->assertEquals('Breaking Bad', $summary['title']); + } + + public function test_can_get_episode_summary(): void + { + if (! $this->traktService->isConfigured()) { + $this->markTestSkipped('Trakt.tv API key is not configured.'); + } + + // First search for Breaking Bad + $results = $this->traktService->searchShows('Breaking Bad', 'show'); + + if (empty($results)) { + $this->markTestSkipped('Could not find Breaking Bad on Trakt.tv.'); + } + + $traktId = $results[0]['show']['ids']['trakt']; + + // Get Season 1, Episode 1 + $episode = $this->traktService->getEpisodeSummary($traktId, 1, 1, 'full'); + + $this->assertNotNull($episode); + $this->assertIsArray($episode); + $this->assertEquals('Pilot', $episode['title']); + } + + public function test_can_get_trending_shows(): void + { + if (! $this->traktService->isConfigured()) { + $this->markTestSkipped('Trakt.tv API key is not configured.'); + } + + $trending = $this->traktService->getTrendingShows(5); + + $this->assertNotNull($trending); + $this->assertIsArray($trending); + $this->assertCount(5, $trending); + } + + public function test_search_result_has_expected_structure(): void + { + if (! $this->traktService->isConfigured()) { + $this->markTestSkipped('Trakt.tv API key is not configured.'); + } + + $results = $this->traktService->searchShows('Breaking Bad', 'show'); + + if (empty($results)) { + $this->markTestSkipped('Could not find Breaking Bad on Trakt.tv.'); + } + + $firstResult = $results[0]; + + $this->assertArrayHasKey('show', $firstResult); + $this->assertArrayHasKey('title', $firstResult['show']); + $this->assertArrayHasKey('ids', $firstResult['show']); + $this->assertArrayHasKey('trakt', $firstResult['show']['ids']); + } + + public function test_returns_empty_for_invalid_search(): void + { + if (! $this->traktService->isConfigured()) { + $this->markTestSkipped('Trakt.tv API key is not configured.'); + } + + $results = $this->traktService->searchShows('xyznonexistentshow99999', 'show'); + + $this->assertTrue(empty($results) || $results === null); + } +} diff --git a/tests/Feature/TvdbApiTest.php b/tests/Feature/TvdbApiTest.php new file mode 100644 index 000000000..0a2339d5d --- /dev/null +++ b/tests/Feature/TvdbApiTest.php @@ -0,0 +1,125 @@ +tvdbProvider = new TvdbProvider; + } catch (\Exception $e) { + $this->tvdbProvider = null; + } + } + + public function test_tvdb_provider_can_be_instantiated(): void + { + if ($this->tvdbProvider === null) { + $this->markTestSkipped('TVDB API is not configured or unavailable.'); + } + + $this->assertInstanceOf(TvdbProvider::class, $this->tvdbProvider); + } + + public function test_can_search_for_series(): void + { + if ($this->tvdbProvider === null) { + $this->markTestSkipped('TVDB API is not configured or unavailable.'); + } + + try { + $results = $this->tvdbProvider->client->search()->search('Breaking Bad', ['type' => 'series']); + + $this->assertNotEmpty($results); + $this->assertIsArray($results); + } catch (\Exception $e) { + $this->markTestSkipped('TVDB API search failed: '.$e->getMessage()); + } + } + + public function test_can_get_series_episodes(): void + { + if ($this->tvdbProvider === null) { + $this->markTestSkipped('TVDB API is not configured or unavailable.'); + } + + try { + // First search for Breaking Bad + $results = $this->tvdbProvider->client->search()->search('Breaking Bad', ['type' => 'series']); + + if (empty($results)) { + $this->markTestSkipped('Could not find Breaking Bad on TVDB.'); + } + + $tvdbId = $results[0]->tvdb_id; + $episodes = $this->tvdbProvider->client->series()->episodes($tvdbId); + + $this->assertNotEmpty($episodes); + } catch (\Exception $e) { + $this->markTestSkipped('TVDB API episode fetch failed: '.$e->getMessage()); + } + } + + public function test_can_find_specific_episode(): void + { + if ($this->tvdbProvider === null) { + $this->markTestSkipped('TVDB API is not configured or unavailable.'); + } + + try { + // Search for Breaking Bad + $results = $this->tvdbProvider->client->search()->search('Breaking Bad', ['type' => 'series']); + + if (empty($results)) { + $this->markTestSkipped('Could not find Breaking Bad on TVDB.'); + } + + $tvdbId = $results[0]->tvdb_id; + $episodes = $this->tvdbProvider->client->series()->episodes($tvdbId); + + // Find Season 1 Episode 1 + $foundEpisode = null; + foreach ($episodes as $episode) { + if ($episode->seasonNumber === 1 && $episode->number === 1) { + $foundEpisode = $episode; + break; + } + } + + $this->assertNotNull($foundEpisode, 'Should find S01E01 of Breaking Bad'); + } catch (\Exception $e) { + $this->markTestSkipped('TVDB API episode search failed: '.$e->getMessage()); + } + } + + public function test_handles_invalid_search_gracefully(): void + { + if ($this->tvdbProvider === null) { + $this->markTestSkipped('TVDB API is not configured or unavailable.'); + } + + try { + $results = $this->tvdbProvider->client->search()->search('xyznonexistentshow99999', ['type' => 'series']); + + // Should return empty or null for non-existent shows + $this->assertTrue(empty($results) || $results === null); + } catch (\Exception $e) { + // API might throw exception for no results, which is acceptable + $this->assertTrue(true); + } + } +} + diff --git a/tests/Feature/TvmazeApiTest.php b/tests/Feature/TvmazeApiTest.php new file mode 100644 index 000000000..3565e7332 --- /dev/null +++ b/tests/Feature/TvmazeApiTest.php @@ -0,0 +1,115 @@ +tvmazeProvider = new TvMazeProvider; + } + + public function test_tvmaze_provider_can_be_instantiated(): void + { + $this->assertInstanceOf(TvMazeProvider::class, $this->tvmazeProvider); + } + + public function test_can_search_for_shows(): void + { + try { + $results = $this->tvmazeProvider->client->search('Breaking Bad'); + + $this->assertNotEmpty($results); + $this->assertIsArray($results); + } catch (\Exception $e) { + $this->markTestSkipped('TVMaze API search failed: '.$e->getMessage()); + } + } + + public function test_can_get_episode_by_number(): void + { + try { + // First search for Breaking Bad + $results = $this->tvmazeProvider->client->search('Breaking Bad'); + + if (empty($results)) { + $this->markTestSkipped('Could not find Breaking Bad on TVMaze.'); + } + + $showId = $results[0]->id; + + // Get Season 1, Episode 1 + $episode = $this->tvmazeProvider->client->getEpisodeByNumber($showId, 1, 1); + + $this->assertNotNull($episode); + $this->assertEquals('Pilot', $episode->name); + } catch (\Exception $e) { + $this->markTestSkipped('TVMaze API episode fetch failed: '.$e->getMessage()); + } + } + + public function test_can_get_all_episodes_by_show_id(): void + { + try { + // First search for Breaking Bad + $results = $this->tvmazeProvider->client->search('Breaking Bad'); + + if (empty($results)) { + $this->markTestSkipped('Could not find Breaking Bad on TVMaze.'); + } + + $showId = $results[0]->id; + $episodes = $this->tvmazeProvider->client->getEpisodesByShowID($showId); + + $this->assertNotEmpty($episodes); + $this->assertIsArray($episodes); + // Breaking Bad has 62 episodes + $this->assertGreaterThan(50, count($episodes)); + } catch (\Exception $e) { + $this->markTestSkipped('TVMaze API episodes fetch failed: '.$e->getMessage()); + } + } + + public function test_search_returns_empty_for_nonexistent_show(): void + { + try { + $results = $this->tvmazeProvider->client->search('xyznonexistentshow99999'); + + $this->assertEmpty($results); + } catch (\Exception $e) { + // API might throw exception for no results + $this->assertTrue(true); + } + } + + public function test_first_search_result_has_expected_properties(): void + { + try { + $results = $this->tvmazeProvider->client->search('Breaking Bad'); + + if (empty($results)) { + $this->markTestSkipped('Could not find Breaking Bad on TVMaze.'); + } + + $show = $results[0]; + + $this->assertObjectHasProperty('id', $show); + $this->assertObjectHasProperty('name', $show); + } catch (\Exception $e) { + $this->markTestSkipped('TVMaze API search failed: '.$e->getMessage()); + } + } +} + diff --git a/tests/Install/InstallTest.php b/tests/Install/InstallTest.php index 40a64e013..7da87265a 100644 --- a/tests/Install/InstallTest.php +++ b/tests/Install/InstallTest.php @@ -1,5 +1,8 @@ artisan('migrate:fresh', ['--seed' => true]) + ->assertExitCode(0); - $message = 'NNTmux installation completed successfully'; - - $this->assertEquals('NNTmux installation completed successfully', $message, 'Test Failed'); + $this->assertTrue(true, 'NNTmux installation completed successfully'); } } diff --git a/tests/Unit/YencServiceTest.php b/tests/Unit/YencServiceTest.php new file mode 100644 index 000000000..bb12b251d --- /dev/null +++ b/tests/Unit/YencServiceTest.php @@ -0,0 +1,185 @@ +yencService = new YencService; + } + + public function test_enabled_returns_true(): void + { + $this->assertTrue($this->yencService->enabled()); + } + + public function test_encode_and_decode_round_trip(): void + { + $originalData = 'Hello, World! This is a test of yEnc encoding.'; + $filename = 'test.txt'; + + // Encode + $encoded = $this->yencService->encode($originalData, $filename); + + // Verify encoding contains headers + $this->assertStringContainsString('=ybegin', $encoded); + $this->assertStringContainsString('=yend', $encoded); + $this->assertStringContainsString('name=test.txt', $encoded); + $this->assertStringContainsString('crc32=', $encoded); + + // Decode + $decoded = $this->yencService->decode($encoded); + + $this->assertEquals($originalData, $decoded); + } + + public function test_encode_respects_line_length(): void + { + $data = str_repeat('A', 500); + $filename = 'test.txt'; + + $encoded = $this->yencService->encode($data, $filename, 100); + + // Check that no content line exceeds 100 characters + $lines = explode("\r\n", $encoded); + foreach ($lines as $line) { + // Skip header and trailer lines + if (str_starts_with($line, '=y')) { + continue; + } + $this->assertLessThanOrEqual(100, strlen($line)); + } + } + + public function test_encode_caps_line_length_at_254(): void + { + $data = 'Test data'; + $filename = 'test.txt'; + + $encoded = $this->yencService->encode($data, $filename, 300); + + // Should contain line=254 in header + $this->assertStringContainsString('line=254', $encoded); + } + + public function test_encode_throws_exception_for_invalid_line_length(): void + { + $this->expectException(RuntimeException::class); + + $this->yencService->encode('data', 'test.txt', 0); + } + + public function test_decode_returns_false_for_non_yenc_data(): void + { + $nonYencData = 'This is just plain text.'; + + $result = $this->yencService->decode($nonYencData); + + $this->assertFalse($result); + } + + public function test_decode_ignore_returns_original_for_non_yenc_data(): void + { + $nonYencData = 'This is just plain text.'; + + $result = $this->yencService->decodeIgnore($nonYencData); + + $this->assertEquals($nonYencData, $result); + } + + public function test_decode_ignore_decodes_yenc_data(): void + { + $originalData = 'Test content for yEnc'; + $encoded = $this->yencService->encode($originalData, 'test.txt'); + + $decoded = $this->yencService->decodeIgnore($encoded); + + $this->assertEquals($originalData, $decoded); + } + + public function test_is_yenc_encoded_returns_true_for_yenc(): void + { + $encoded = $this->yencService->encode('test', 'test.txt'); + + $this->assertTrue($this->yencService->isYencEncoded($encoded)); + } + + public function test_is_yenc_encoded_returns_false_for_plain_text(): void + { + $this->assertFalse($this->yencService->isYencEncoded('plain text')); + } + + public function test_extract_metadata_returns_metadata(): void + { + $data = 'Test content'; + $encoded = $this->yencService->encode($data, 'myfile.dat', 128, true); + + $metadata = $this->yencService->extractMetadata($encoded); + + $this->assertNotNull($metadata); + $this->assertEquals('myfile.dat', $metadata['name']); + $this->assertEquals(strlen($data), $metadata['size']); + $this->assertEquals(128, $metadata['line']); + $this->assertNotNull($metadata['crc32']); + } + + public function test_extract_metadata_returns_null_for_non_yenc(): void + { + $metadata = $this->yencService->extractMetadata('plain text'); + + $this->assertNull($metadata); + } + + public function test_encode_without_crc32(): void + { + $encoded = $this->yencService->encode('test', 'test.txt', 128, false); + + $this->assertStringNotContainsString('crc32=', $encoded); + } + + public function test_encode_with_special_characters(): void + { + // Test with characters that need escaping (NULL, TAB, LF, CR, space, ., =) + $data = "Hello\x00World\tTest\nNew\rLine . = End"; + + $encoded = $this->yencService->encode($data, 'special.bin'); + $decoded = $this->yencService->decode($encoded); + + $this->assertEquals($data, $decoded); + } + + public function test_encode_with_binary_data(): void + { + // Test with all possible byte values + $data = ''; + for ($i = 0; $i < 256; $i++) { + $data .= chr($i); + } + + $encoded = $this->yencService->encode($data, 'binary.bin'); + $decoded = $this->yencService->decode($encoded); + + $this->assertEquals($data, $decoded); + } + + public function test_service_can_be_resolved_from_container(): void + { + $service = app(YencService::class); + + $this->assertInstanceOf(YencService::class, $service); + } + + public function test_facade_works(): void + { + $this->assertTrue(\App\Facades\Yenc::enabled()); + } +} +