diff --git a/Blacklight/NZBContents.php b/Blacklight/NZBContents.php index cbb598ce0..63f39000a 100755 --- a/Blacklight/NZBContents.php +++ b/Blacklight/NZBContents.php @@ -47,11 +47,10 @@ class NZBContents /** * Look for an .nfo file in the NZB, download it, verify it, and return the content. * - * @param string $guid The release GUID. - * @param int $relID The release ID. - * @param int $groupID The group ID. - * @param string $groupName The group name. - * + * @param string $guid The release GUID. + * @param int $relID The release ID. + * @param int $groupID The group ID. + * @param string $groupName The group name. * @return string|false The verified NFO content as a string, or false if not found, download failed, or verification failed. * * @throws \Exception If NNTP operations fail. @@ -62,12 +61,13 @@ class NZBContents $messageID = $this->parseNZB($guid, $relID, $groupID, true); // If no NFO message ID found - if ($messageID === false || !isset($messageID['id'])) { + if ($messageID === false || ! isset($messageID['id'])) { if ($this->echooutput) { echo '-'; } // Make sure we set status to NFO_NONFO Release::query()->where('id', $relID)->update(['nfostatus' => Nfo::NFO_NONFO]); + return false; } @@ -81,6 +81,7 @@ class NZBContents if ($this->echooutput) { echo 'f'; } + return false; } @@ -91,6 +92,7 @@ class NZBContents // Show if it was found via explicit name (+) or potentially hidden (*) echo $messageID['hidden'] === false ? '+' : '*'; } + return $fetchedBinary; } @@ -99,6 +101,7 @@ class NZBContents echo '-'; } Release::query()->where('id', $relID)->update(['nfostatus' => Nfo::NFO_NONFO]); + return false; } @@ -107,11 +110,10 @@ class NZBContents * * This version includes improved regex for PAR2 file detection. * - * @param string $guid The release GUID. - * @param int $relID The release ID. - * @param int $groupID The group ID. - * @param bool $nfoCheck Whether to specifically look for an NFO file. - * + * @param string $guid The release GUID. + * @param int $relID The release ID. + * @param int $groupID The group ID. + * @param bool $nfoCheck Whether to specifically look for an NFO file. * @return array|false An array containing NFO message ID and hidden status, or false if not found/error. * * @throws \Exception If NNTP operations fail. @@ -139,42 +141,41 @@ class NZBContents $segmentCountInFile++; // Store the first segment ID of the current file, potentially useful for NFO/PAR2 if ($segmentCountInFile === 1) { - $firstSegmentId = (string) $segment; + $firstSegmentId = (string) $segment; } } $subject = (string) $nzbContents->attributes()->subject; if (preg_match('/(?:[(\[])?(\d+)[\/)\\]](\d+)[)\]]?$/', $subject, $parts)) { // Improve artificial parts calculation robustness (e.g., "[15/20]", "(15/20)") - if (isset($parts[2]) && (int)$parts[2] > 0) { - // Use the total count from the subject if available and seems valid - $artificialParts += (int)$parts[2]; - } - } else if (preg_match('/(\d+)\)$/', $subject, $parts)) { - // Fallback to original simple check if the more robust one fails - $artificialParts += (int)$parts[1]; + if (isset($parts[2]) && (int) $parts[2] > 0) { + // Use the total count from the subject if available and seems valid + $artificialParts += (int) $parts[2]; + } + } elseif (preg_match('/(\d+)\)$/', $subject, $parts)) { + // Fallback to original simple check if the more robust one fails + $artificialParts += (int) $parts[1]; } - // --- NFO Detection --- // Check for explicit NFO files first - if ($nfoCheck && !$foundNFO && isset($firstSegmentId) && preg_match('/\.\b(nfo|diz|info?)\b(?![.-])/i', $subject)) { + if ($nfoCheck && ! $foundNFO && isset($firstSegmentId) && preg_match('/\.\b(nfo|diz|info?)\b(?![.-])/i', $subject)) { $nfoMessageId = ['hidden' => false, 'id' => $firstSegmentId]; $foundNFO = true; // Found an explicit NFO, prioritize this } // Check for potential "hidden" NFOs (single segment, common name, not other known types) // Only consider this if an explicit NFO wasn't found yet - else if ($nfoCheck && !$foundNFO && !$hiddenNFO && isset($firstSegmentId) && $segmentCountInFile === 1 && preg_match('/\(1\/1\)$/i', $subject)) { - // Simplified exclusion: check if it's NOT likely another common file type based on extension pattern - if (!preg_match('/\.(?:exe|com|bat|cmd|scr|dll|zip|rar|[rst]\d{2}|[a-z0-9]{3}|7z|ace|tar|gz|bz2|iso|bin|cue|img|mdf|nrg|dmg|vhd|mp3|flac|ogg|aac|wav|wma|avi|mkv|mp4|mov|wmv|mpg|mpeg|ts|vob|jpg|jpeg|png|gif|bmp|tif|tiff|psd|pdf|doc|docx|xls|xlsx|ppt|pptx|txt|log|xml|html|css|js|php|py|java|c|cpp|h|cs|sql|db|dbf|mdb|accdb|par2?|sfv|md5|sha1|sha256|url|lnk|cfg|ini|inf|sys|tmp|bak|msi|pkg|deb|rpm|apk|ipa)\b/i', $subject)) { - $nfoMessageId = ['hidden' => true, 'id' => $firstSegmentId]; - $hiddenNFO = true; // Found a potential hidden NFO - } + elseif ($nfoCheck && ! $foundNFO && ! $hiddenNFO && isset($firstSegmentId) && $segmentCountInFile === 1 && preg_match('/\(1\/1\)$/i', $subject)) { + // Simplified exclusion: check if it's NOT likely another common file type based on extension pattern + if (! preg_match('/\.(?:exe|com|bat|cmd|scr|dll|zip|rar|[rst]\d{2}|[a-z0-9]{3}|7z|ace|tar|gz|bz2|iso|bin|cue|img|mdf|nrg|dmg|vhd|mp3|flac|ogg|aac|wav|wma|avi|mkv|mp4|mov|wmv|mpg|mpeg|ts|vob|jpg|jpeg|png|gif|bmp|tif|tiff|psd|pdf|doc|docx|xls|xlsx|ppt|pptx|txt|log|xml|html|css|js|php|py|java|c|cpp|h|cs|sql|db|dbf|mdb|accdb|par2?|sfv|md5|sha1|sha256|url|lnk|cfg|ini|inf|sys|tmp|bak|msi|pkg|deb|rpm|apk|ipa)\b/i', $subject)) { + $nfoMessageId = ['hidden' => true, 'id' => $firstSegmentId]; + $hiddenNFO = true; // Found a potential hidden NFO + } } // --- PAR2 Detection --- // Look specifically for the .par2 index file (often small, but not always 1/1) - if ($this->lookuppar2 && !$foundPAR2 && isset($firstSegmentId) && preg_match('/\.par2$/i', $subject)) { + if ($this->lookuppar2 && ! $foundPAR2 && isset($firstSegmentId) && preg_match('/\.par2$/i', $subject)) { // Attempt to parse the PAR2 file using its first segment ID // Ensure $this->pp is initialized and parsePAR2 exists and accepts these parameters if (method_exists($this->pp, 'parsePAR2') && $this->pp->parsePAR2($firstSegmentId, $relID, $groupID, $this->nntp, 1) === true) { @@ -188,15 +189,14 @@ class NZBContents // Avoid division by zero and handle cases where parts info might be missing/incorrect if ($artificialParts > 0) { $completion = min(100, ($actualParts / $artificialParts) * 100); - } else if ($actualParts > 0) { + } elseif ($actualParts > 0) { // If artificial parts couldn't be determined, but we have actual parts, // we can't calculate completion accurately based on subject. // Consider if $actualParts alone means 100% or if it's unknown. // Setting to 100 if actual parts > 0 and artificial is 0 might be misleading. // Let's default to 0 or another state indicating unknown completion from subject. $completion = 0; // Or potentially set a specific status? - } - else { + } else { // If both are zero (e.g., empty NZB or parsing issue), completion is 0. $completion = 0; } @@ -210,9 +210,10 @@ class NZBContents // If NFO check was requested but nothing suitable was found if ($nfoCheck && $nfoMessageId === null) { - // Update status to indicate no NFO was found in the NZB structure - Release::query()->where('id', $relID)->update(['nfostatus' => Nfo::NFO_NONFO]); - return false; + // Update status to indicate no NFO was found in the NZB structure + Release::query()->where('id', $relID)->update(['nfostatus' => Nfo::NFO_NONFO]); + + return false; } // If NFO check was not requested, the function's primary goal might be just completion/PAR2 update. @@ -224,8 +225,7 @@ class NZBContents /** * Loads and parses an NZB file based on a GUID. * - * @param string $guid The release GUID to locate the NZB file - * + * @param string $guid The release GUID to locate the NZB file * @return \SimpleXMLElement|bool The parsed NZB file as SimpleXMLElement or false on failure */ public function loadNzb(string $guid): \SimpleXMLElement|bool @@ -242,8 +242,9 @@ class NZBContents if ($this->echooutput) { $perms = fileperms($nzbPath); $formattedPerms = $perms !== false ? decoct($perms & 0777) : 'unknown'; - echo PHP_EOL . "Unable to decompress: {$nzbPath} - {$formattedPerms} - may have bad file permissions, skipping." . PHP_EOL; + echo PHP_EOL."Unable to decompress: {$nzbPath} - {$formattedPerms} - may have bad file permissions, skipping.".PHP_EOL; } + return false; } @@ -254,10 +255,11 @@ class NZBContents if ($nzbFile === false) { if ($this->echooutput) { $errors = libxml_get_errors(); - $errorMsg = !empty($errors) ? " - XML error: " . $errors[0]->message : ""; - echo PHP_EOL . "Unable to load NZB: {$guid} appears to be an invalid NZB{$errorMsg}, skipping." . PHP_EOL; + $errorMsg = ! empty($errors) ? ' - XML error: '.$errors[0]->message : ''; + echo PHP_EOL."Unable to load NZB: {$guid} appears to be an invalid NZB{$errorMsg}, skipping.".PHP_EOL; libxml_clear_errors(); } + return false; } diff --git a/Blacklight/Nfo.php b/Blacklight/Nfo.php index 82dbaad29..ecf144fdb 100755 --- a/Blacklight/Nfo.php +++ b/Blacklight/Nfo.php @@ -21,29 +21,25 @@ use Throwable; */ class Nfo { - /** - * Regex to detect common non-NFO file headers/signatures. - * @var string - */ - protected string $_nonNfoHeaderRegex = '/\A(\s*<\?xml|=newz\[NZB\]=|RIFF|\s*[RP]AR|.{0,10}(JFIF|matroska|ftyp|ID3))|;\s*Generated\s*by.*SF\w/i'; + /** + * Regex to detect common non-NFO file headers/signatures. + */ + protected string $_nonNfoHeaderRegex = '/\A(\s*<\?xml|=newz\[NZB\]=|RIFF|\s*[RP]AR|.{0,10}(JFIF|matroska|ftyp|ID3))|;\s*Generated\s*by.*SF\w/i'; - /** - * Regex to identify text encoding from the 'file' command output. - * @var string - */ - protected string $_textFileRegex = '/(ASCII|ISO-8859|UTF-(8|16|32).*?)\s*text/'; + /** + * Regex to identify text encoding from the 'file' command output. + */ + protected string $_textFileRegex = '/(ASCII|ISO-8859|UTF-(8|16|32).*?)\s*text/'; - /** - * Regex to identify common binary file types from the 'file' command output. - * @var string - */ - protected string $_binaryFileRegex = '/^(JPE?G|Parity|PNG|RAR|XML|(7-)?[Zz]ip)/'; + /** + * Regex to identify common binary file types from the 'file' command output. + */ + protected string $_binaryFileRegex = '/^(JPE?G|Parity|PNG|RAR|XML|(7-)?[Zz]ip)/'; - /** - * Regex to detect binary characters within the content. - * @var string - */ - protected string $_binaryCharsRegex = '/[\x00-\x08\x12-\x1F\x0B\x0E\x0F]/'; + /** + * Regex to detect binary characters within the content. + */ + protected string $_binaryCharsRegex = '/[\x00-\x08\x12-\x1F\x0B\x0E\x0F]/'; /** * @var int @@ -146,7 +142,7 @@ class Nfo /** * Confirm this is an NFO file. * - * @param bool|string $possibleNFO The nfo content. + * @param bool|string $possibleNFO The nfo content. * @param string $guid The guid of the release. * @return bool True if it's likely an NFO, False otherwise. */ @@ -163,7 +159,7 @@ class Nfo return false; } - $tmpPath = $this->tmpPath . $guid . '.nfo'; + $tmpPath = $this->tmpPath.$guid.'.nfo'; $isNfo = false; // Default assumption try { @@ -172,29 +168,30 @@ class Nfo // Use 'file' command via Utility::fileInfo if available $result = Utility::fileInfo($tmpPath); - if (!empty($result)) { + if (! empty($result)) { if (preg_match($this->_textFileRegex, $result)) { $isNfo = true; // It's text, likely NFO } elseif (preg_match($this->_binaryFileRegex, $result) || preg_match($this->_binaryCharsRegex, $possibleNFO)) { $isNfo = false; // Detected binary format or characters } + // If fileInfo gave a result, trust it and return return $isNfo; } // Fallback checks if 'file' command is unavailable or inconclusive // Check if it's a par2. - $par2info = new Par2Info(); + $par2info = new Par2Info; $par2info->setData($possibleNFO); - if (!$par2info->error) { - // It's a PAR2 file - return false; + if (! $par2info->error) { + // It's a PAR2 file + return false; } // Check if it's an SFV. - $sfv = new SfvInfo(); + $sfv = new SfvInfo; $sfv->setData($possibleNFO); - if (!$sfv->error) { + if (! $sfv->error) { // It's an SFV file return false; } @@ -202,11 +199,11 @@ class Nfo // If it wasn't identified as a known non-NFO binary type by fileInfo, // and isn't PAR2 or SFV, assume it might be NFO (especially if fileInfo failed). // Further checks (like binary char check) could be added here if needed. - $isNfo = !preg_match($this->_binaryCharsRegex, $possibleNFO); + $isNfo = ! preg_match($this->_binaryCharsRegex, $possibleNFO); } catch (Throwable $e) { // Log errors during file operations - Log::error("Error processing potential NFO for GUID {$guid}: " . $e->getMessage()); + Log::error("Error processing potential NFO for GUID {$guid}: ".$e->getMessage()); $isNfo = false; // Treat errors as non-NFO } finally { // Ensure temporary file is always deleted @@ -214,7 +211,7 @@ class Nfo try { File::delete($tmpPath); } catch (Throwable $e) { - Log::error("Error deleting temporary NFO file {$tmpPath}: " . $e->getMessage()); + Log::error("Error deleting temporary NFO file {$tmpPath}: ".$e->getMessage()); } } } @@ -265,15 +262,14 @@ class Nfo return false; } - /** + /** * Attempt to find NFO files inside the NZB's of releases. * - * @param NNTP $nntp The NNTP connection object - * @param string $groupID (optional) Group ID to filter releases by - * @param string $guidChar (optional) First character of the GUID for parallel processing - * @param bool $processImdb (optional) Process IMDB IDs (currently unused) - * @param bool $processTv (optional) Process TV IDs (currently unused) - * + * @param NNTP $nntp The NNTP connection object + * @param string $groupID (optional) Group ID to filter releases by + * @param string $guidChar (optional) First character of the GUID for parallel processing + * @param bool $processImdb (optional) Process IMDB IDs (currently unused) + * @param bool $processTv (optional) Process TV IDs (currently unused) * @return int Count of successfully processed NFO files * * @throws \Exception If NNTP operations fail @@ -316,10 +312,10 @@ class Nfo try { // Only insert if not already present $exists = ReleaseNfo::whereReleasesId($release['id'])->exists(); - if (!$exists) { + if (! $exists) { ReleaseNfo::query()->insert([ 'releases_id' => $release['id'], - 'nfo' => "\x1f\x8b\x08\x00".gzcompress($fetchedBinary) + 'nfo' => "\x1f\x8b\x08\x00".gzcompress($fetchedBinary), ]); }