diff --git a/Blacklight/IRCClient.php b/Blacklight/IRCClient.php
index 25d30fd9b..c2fc4d9dc 100755
--- a/Blacklight/IRCClient.php
+++ b/Blacklight/IRCClient.php
@@ -2,7 +2,6 @@
namespace Blacklight;
-use Blacklight\utility\Utility;
/**
* Basic IRC client for fetching IRCScraper.
@@ -556,7 +555,7 @@ class IRCClient
// Create SSL/TLS context if using secure connection
$context = $this->_remote_tls
- ? stream_context_create(Utility::streamSslContextOptions(true))
+ ? stream_context_create(streamSslContextOptions(true))
: null;
$socket = stream_socket_client(
diff --git a/Blacklight/Movie.php b/Blacklight/Movie.php
index ac2da55d9..32f550ea2 100755
--- a/Blacklight/Movie.php
+++ b/Blacklight/Movie.php
@@ -11,7 +11,6 @@ use App\Services\FanartTvService;
use App\Services\ImdbScraper;
use App\Services\TmdbClient;
use App\Services\TvProcessing\Providers\TraktProvider;
-use Blacklight\utility\Utility;
use GuzzleHttp\Client;
use GuzzleHttp\Exception\GuzzleException;
use Illuminate\Database\Eloquent\Builder;
@@ -296,7 +295,7 @@ class Movie
}
}
- $trailer = Utility::imdb_trailers($imdbId);
+ $trailer = imdb_trailers($imdbId);
if ($trailer) {
MovieInfo::query()->where('imdbid', $imdbId)->update(['trailer' => $trailer]);
diff --git a/Blacklight/NNTP.php b/Blacklight/NNTP.php
index 062ebd61b..b25e2a8e8 100755
--- a/Blacklight/NNTP.php
+++ b/Blacklight/NNTP.php
@@ -4,7 +4,6 @@ namespace Blacklight;
use App\Extensions\util\PhpYenc;
use App\Models\Settings;
-use Blacklight\utility\Utility;
/*
* Class for connecting to the usenet, retrieving articles and article headers,
@@ -1274,7 +1273,7 @@ class NNTP extends \Net_NNTP_Client
// Attempt to connect to usenet.
// Only create SSL context if using TLS/SSL transport
$context = preg_match('/tls|ssl/', $transport)
- ? stream_context_create(Utility::streamSslContextOptions())
+ ? stream_context_create(streamSslContextOptions())
: null;
$socket = stream_socket_client(
diff --git a/Blacklight/NZBContents.php b/Blacklight/NZBContents.php
index 4787c50c5..e08533161 100755
--- a/Blacklight/NZBContents.php
+++ b/Blacklight/NZBContents.php
@@ -7,7 +7,6 @@ namespace Blacklight;
use App\Models\Release;
use App\Models\Settings;
use App\Services\PostProcessService;
-use Blacklight\utility\Utility;
/**
* Gets information contained within the NZB.
@@ -293,7 +292,7 @@ class NZBContents
}
// Attempt to decompress the NZB file
- $nzbContents = Utility::unzipGzipFile($nzbPath);
+ $nzbContents = unzipGzipFile($nzbPath);
if (empty($nzbContents)) {
if ($this->echooutput) {
$perms = fileperms($nzbPath);
diff --git a/Blacklight/NZBExport.php b/Blacklight/NZBExport.php
index 1cddd088f..b80ec02fd 100755
--- a/Blacklight/NZBExport.php
+++ b/Blacklight/NZBExport.php
@@ -3,7 +3,6 @@
namespace Blacklight;
use App\Models\UsenetGroup;
-use Blacklight\utility\Utility;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
@@ -149,7 +148,7 @@ class NZBExport
}
// If not, decompress it and create a file to store it in.
} else {
- $nzbContents = Utility::unzipGzipFile($nzbFile);
+ $nzbContents = unzipGzipFile($nzbFile);
if (! $nzbContents) {
if ($this->echoCLI) {
echo 'Unable to export NZB with GUID: '.$release['guid'];
diff --git a/Blacklight/NZBImport.php b/Blacklight/NZBImport.php
index d2303ca0f..70d05013d 100755
--- a/Blacklight/NZBImport.php
+++ b/Blacklight/NZBImport.php
@@ -7,7 +7,6 @@ use App\Models\Settings;
use App\Models\UsenetGroup;
use App\Services\BlacklistService;
use App\Services\Categorization\CategorizationService;
-use Blacklight\utility\Utility;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
@@ -123,7 +122,7 @@ class NZBImport
if (File::isFile($nzbFile)) {
// Get the contents of the NZB file as a string.
if (Str::endsWith($nzbFile, '.nzb.gz')) {
- $nzbString = Utility::unzipGzipFile($nzbFile);
+ $nzbString = unzipGzipFile($nzbFile);
} else {
$nzbString = File::get($nzbFile);
}
diff --git a/Blacklight/Nfo.php b/Blacklight/Nfo.php
index 0c295c0ab..7b8670438 100755
--- a/Blacklight/Nfo.php
+++ b/Blacklight/Nfo.php
@@ -9,7 +9,6 @@ use App\Models\ReleaseNfo;
use App\Models\Settings;
use App\Models\UsenetGroup;
use App\Services\PostProcessService;
-use Blacklight\utility\Utility;
use dariusiii\rarinfo\Par2Info;
use dariusiii\rarinfo\SfvInfo;
use Illuminate\Support\Facades\Cache;
@@ -275,8 +274,8 @@ class Nfo
// File/GetId3 work with files, so save to disk.
File::put($tmpPath, $possibleNFO);
- // Use 'file' command via Utility::fileInfo if available
- $result = Utility::fileInfo($tmpPath);
+ // Use 'file' command via fileInfo if available
+ $result = fileInfo($tmpPath);
if (! empty($result)) {
if (preg_match($this->_textFileRegex, $result)) {
$isNfo = true;
@@ -1214,7 +1213,7 @@ class Nfo
public function cleanNfoContent(string $nfoContent): string
{
// Convert to UTF-8 if needed (CP437 is common for NFOs)
- $content = Utility::cp437toUTF($nfoContent);
+ $content = cp437toUTF($nfoContent);
// Normalize line endings
$content = str_replace(["\r\n", "\r"], "\n", $content);
diff --git a/Blacklight/utility/Country.php b/Blacklight/utility/Country.php
deleted file mode 100755
index 629eb772a..000000000
--- a/Blacklight/utility/Country.php
+++ /dev/null
@@ -1,49 +0,0 @@
-.
- *
- * @author ruhllatio
- * @copyright 2015 nZEDb
- */
-
-namespace Blacklight\utility;
-
-use App\Models\Country as CountryModel;
-
-/**
- * Class Country.
- */
-class Country
-{
- /**
- * Get a country code for a country name.
- *
- * @return mixed
- */
- public static function countryCode(string $country)
- {
- if (\strlen($country) > 2) {
- $code = CountryModel::whereFullName($country)->orWhere('name', $country)->first(['iso_3166_2']);
- if ($code !== null && isset($code['iso_3166_2'])) {
- return $code['iso_3166_2'];
- }
- }
-
- return '';
- }
-}
diff --git a/Blacklight/utility/Utility.php b/Blacklight/utility/Utility.php
deleted file mode 100755
index 036a01af8..000000000
--- a/Blacklight/utility/Utility.php
+++ /dev/null
@@ -1,250 +0,0 @@
- ! $forceIgnore && $hasCustomCerts && config('nntmux_ssl.ssl_verify_peer', false),
- 'verify_peer_name' => ! $forceIgnore && $hasCustomCerts && config('nntmux_ssl.ssl_verify_host', false),
- 'allow_self_signed' => $forceIgnore ? true : config('nntmux_ssl.ssl_allow_self_signed', true),
- ];
-
- // Add certificate paths if configured
- if ($hasCustomCerts && ! $forceIgnore) {
- if ($cafile !== '') {
- $options['cafile'] = $cafile;
- }
- if ($capath !== '') {
- $options['capath'] = $capath;
- }
- }
-
- // Additional security options for modern TLS
- $options['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT;
- $options['disable_compression'] = true; // Prevent CRIME attacks
- $options['SNI_enabled'] = true; // Enable Server Name Indication
-
- // If we set the transport to tls and the server falls back to ssl,
- // the context options would be for tls and would not apply to ssl,
- // so set both tls and ssl context in case the server does not support tls.
- return ['tls' => $options, 'ssl' => $options];
- }
-
- public static function getCoverURL(array $options = []): string
- {
- $defaults = [
- 'id' => null,
- 'suffix' => '-cover.jpg',
- 'type' => '',
- ];
- $options += $defaults;
- $fileSpecTemplate = '%s/%s%s';
- $fileSpec = '';
-
- if (! empty($options['id']) && \in_array(
- $options['type'],
- ['anime', 'audio', 'audiosample', 'book', 'console', 'games', 'movies', 'music', 'preview', 'sample', 'tvrage', 'video', 'xxx'],
- false
- )
- ) {
- $fileSpec = sprintf($fileSpecTemplate, $options['type'], $options['id'], $options['suffix']);
- $fileSpec = file_exists(storage_path('covers/').$fileSpec) ? $fileSpec :
- sprintf($fileSpecTemplate, $options['type'], 'no', $options['suffix']);
- }
-
- return $fileSpec;
- }
-
- /**
- * Return file type/info using magic numbers.
- * Try using `file` program where available, fallback to using PHP's finfo class.
- *
- * @param string $path Path to the file / folder to check.
- * @return string File info. Empty string on failure.
- *
- * @throws \Exception
- */
- public static function fileInfo(string $path): string
- {
- $magicPath = config('nntmux_settings.magic_file_path');
- if ($magicPath !== null && Process::run('which file')->successful()) {
- $magicSwitch = " -m $magicPath";
- $output = runCmd('file'.$magicSwitch.' -b "'.$path.'"');
- } else {
- $fileInfo = $magicPath === null ? finfo_open(FILEINFO_RAW) : finfo_open(FILEINFO_RAW, $magicPath);
-
- $output = finfo_file($fileInfo, $path);
- if (empty($output)) {
- $output = '';
- }
- finfo_close($fileInfo);
- }
-
- return $output;
- }
-
- /**
- * Convert Code page 437 chars to UTF.
- */
- public static function cp437toUTF(string $string): string
- {
- return iconv('CP437', 'UTF-8//IGNORE//TRANSLIT', $string);
- }
-
- /**
- * Fetches an embeddable video to a IMDB trailer from http://www.traileraddict.com.
- */
- public static function imdb_trailers($imdbID): string
- {
- $xml = getRawHtml('https://api.traileraddict.com/?imdb='.$imdbID);
- if ($xml !== false && preg_match('#(v\.traileraddict\.com/\d+)#i', $xml, $html)) {
- return 'https://'.$html[1];
- }
-
- return '';
- }
-
- public static function showApiError(int $errorCode = 900, string $errorText = '')
- {
- $errorHeader = 'HTTP 1.1 400 Bad Request';
- if ($errorText === '') {
- switch ($errorCode) {
- case 100:
- $errorText = 'Incorrect user credentials';
- $errorHeader = 'HTTP 1.1 401 Unauthorized';
- break;
- case 101:
- $errorText = 'Account suspended';
- $errorHeader = 'HTTP 1.1 403 Forbidden';
- break;
- case 102:
- $errorText = 'Insufficient privileges/not authorized';
- $errorHeader = 'HTTP 1.1 401 Unauthorized';
- break;
- case 103:
- $errorText = 'Registration denied';
- $errorHeader = 'HTTP 1.1 403 Forbidden';
- break;
- case 104:
- $errorText = 'Registrations are closed';
- $errorHeader = 'HTTP 1.1 403 Forbidden';
- break;
- case 105:
- $errorText = 'Invalid registration (Email Address Taken)';
- $errorHeader = 'HTTP 1.1 403 Forbidden';
- break;
- case 106:
- $errorText = 'Invalid registration (Email Address Bad Format)';
- $errorHeader = 'HTTP 1.1 403 Forbidden';
- break;
- case 107:
- $errorText = 'Registration Failed (Data error)';
- $errorHeader = 'HTTP 1.1 400 Bad Request';
- break;
- case 200:
- $errorText = 'Missing parameter';
- $errorHeader = 'HTTP 1.1 400 Bad Request';
- break;
- case 201:
- $errorText = 'Incorrect parameter';
- $errorHeader = 'HTTP 1.1 400 Bad Request';
- break;
- case 202:
- $errorText = 'No such function';
- $errorHeader = 'HTTP 1.1 404 Not Found';
- break;
- case 203:
- $errorText = 'Function not available';
- $errorHeader = 'HTTP 1.1 400 Bad Request';
- break;
- case 300:
- $errorText = 'No such item';
- $errorHeader = 'HTTP 1.1 404 Not Found';
- break;
- case 500:
- $errorText = 'Request limit reached';
- $errorHeader = 'HTTP 1.1 429 Too Many Requests';
- break;
- case 501:
- $errorText = 'Download limit reached';
- $errorHeader = 'HTTP 1.1 429 Too Many Requests';
- break;
- case 910:
- $errorText = 'API disabled';
- $errorHeader = 'HTTP 1.1 401 Unauthorized';
- break;
- default:
- $errorText = 'Unknown error';
- $errorHeader = 'HTTP 1.1 400 Bad Request';
- break;
- }
- }
-
- $response =
- "\n".
- '\n";
-
- return response($response)->header('Content-type', 'text/xml')->header('Content-Length', strlen($response))->header('X-NNTmux', 'API ERROR ['.$errorCode.'] '.$errorText)->header('HTTP/1.1', $errorHeader);
- }
-
- public static function getRange($tableName): LengthAwarePaginator
- {
- $range = DB::table($tableName);
- if ($tableName === 'xxxinfo') {
- $range->selectRaw('UNCOMPRESS(plot) AS plot');
- }
-
- return $range->orderByDesc('created_at')->paginate(config('nntmux.items_per_page'));
- }
-}
diff --git a/app/Extensions/helper/helpers.php b/app/Extensions/helper/helpers.php
index f78f75c90..8ee60f996 100644
--- a/app/Extensions/helper/helpers.php
+++ b/app/Extensions/helper/helpers.php
@@ -1,8 +1,8 @@
NZBPath($guid);
if ($nzbPath) {
- $nzbContents = Utility::unzipGzipFile($nzbPath);
+ $nzbContents = unzipGzipFile($nzbPath);
if ($nzbContents) {
$filename = $guid;
$r = Release::query()->where('guid', $guid)->first();
@@ -682,3 +682,306 @@ if (! function_exists('getAvailableTimezones')) {
return $timezones;
}
}
+
+if (! function_exists('countryCode')) {
+ /**
+ * Get a country code for a country name.
+ *
+ * @return mixed
+ */
+ function countryCode(string $country)
+ {
+ if (\strlen($country) > 2) {
+ $code = CountryModel::whereFullName($country)->orWhere('name', $country)->first(['iso_3166_2']);
+ if ($code !== null && isset($code['iso_3166_2'])) {
+ return $code['iso_3166_2'];
+ }
+ }
+
+ return '';
+ }
+}
+
+if (! function_exists('unzipGzipFile')) {
+ /**
+ * Unzip a gzip file, return the output. Return false on error / empty.
+ *
+ * @return bool|string
+ */
+ function unzipGzipFile(string $filePath)
+ {
+ $string = '';
+ $gzFile = @gzopen($filePath, 'rb', 0);
+ if ($gzFile) {
+ while (! gzeof($gzFile)) {
+ $temp = gzread($gzFile, 1024);
+ // Check for empty string.
+ // Without this the loop would be endless and consume 100% CPU.
+ // Do not set $string empty here, as the data might still be good.
+ if (! $temp) {
+ break;
+ }
+ $string .= $temp;
+ }
+ gzclose($gzFile);
+ }
+
+ return $string === '' ? false : $string;
+ }
+}
+
+if (! function_exists('streamSslContextOptions')) {
+ /**
+ * Creates an array to be used with stream_context_create() to verify openssl certificates
+ * when connecting to a tls or ssl connection when using stream functions (fopen/file_get_contents/etc).
+ *
+ * @param bool $forceIgnore Force ignoring of verification (useful for self-signed certs in development).
+ * @return array Stream context options for SSL/TLS connections
+ */
+ function streamSslContextOptions(bool $forceIgnore = false): array
+ {
+ $cafile = config('nntmux_ssl.ssl_cafile', '');
+ $capath = config('nntmux_ssl.ssl_capath', '');
+ $hasCustomCerts = $cafile !== '' || $capath !== '';
+
+ // Base options - either insecure (no certs configured) or configured
+ $options = [
+ 'verify_peer' => ! $forceIgnore && $hasCustomCerts && config('nntmux_ssl.ssl_verify_peer', false),
+ 'verify_peer_name' => ! $forceIgnore && $hasCustomCerts && config('nntmux_ssl.ssl_verify_host', false),
+ 'allow_self_signed' => $forceIgnore ? true : config('nntmux_ssl.ssl_allow_self_signed', true),
+ ];
+
+ // Add certificate paths if configured
+ if ($hasCustomCerts && ! $forceIgnore) {
+ if ($cafile !== '') {
+ $options['cafile'] = $cafile;
+ }
+ if ($capath !== '') {
+ $options['capath'] = $capath;
+ }
+ }
+
+ // Additional security options for modern TLS
+ $options['crypto_method'] = STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT | STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT;
+ $options['disable_compression'] = true; // Prevent CRIME attacks
+ $options['SNI_enabled'] = true; // Enable Server Name Indication
+
+ // If we set the transport to tls and the server falls back to ssl,
+ // the context options would be for tls and would not apply to ssl,
+ // so set both tls and ssl context in case the server does not support tls.
+ return ['tls' => $options, 'ssl' => $options];
+ }
+}
+
+if (! function_exists('getCoverURL')) {
+ function getCoverURL(array $options = []): string
+ {
+ $defaults = [
+ 'id' => null,
+ 'suffix' => '-cover.jpg',
+ 'type' => '',
+ ];
+ $options += $defaults;
+ $fileSpecTemplate = '%s/%s%s';
+ $fileSpec = '';
+
+ if (! empty($options['id']) && \in_array(
+ $options['type'],
+ ['anime', 'audio', 'audiosample', 'book', 'console', 'games', 'movies', 'music', 'preview', 'sample', 'tvrage', 'video', 'xxx'],
+ false
+ )
+ ) {
+ $fileSpec = sprintf($fileSpecTemplate, $options['type'], $options['id'], $options['suffix']);
+ $fileSpec = file_exists(storage_path('covers/').$fileSpec) ? $fileSpec :
+ sprintf($fileSpecTemplate, $options['type'], 'no', $options['suffix']);
+ }
+
+ return $fileSpec;
+ }
+}
+
+if (! function_exists('fileInfo')) {
+ /**
+ * Return file type/info using magic numbers.
+ * Try using `file` program where available, fallback to using PHP's finfo class.
+ *
+ * @param string $path Path to the file / folder to check.
+ * @return string File info. Empty string on failure.
+ *
+ * @throws \Exception
+ */
+ function fileInfo(string $path): string
+ {
+ $magicPath = config('nntmux_settings.magic_file_path');
+ if ($magicPath !== null && \Illuminate\Support\Facades\Process::run('which file')->successful()) {
+ $magicSwitch = " -m $magicPath";
+ $output = runCmd('file'.$magicSwitch.' -b "'.$path.'"');
+ } else {
+ $fileInfo = $magicPath === null ? finfo_open(FILEINFO_RAW) : finfo_open(FILEINFO_RAW, $magicPath);
+
+ $output = finfo_file($fileInfo, $path);
+ if (empty($output)) {
+ $output = '';
+ }
+ finfo_close($fileInfo);
+ }
+
+ return $output;
+ }
+}
+
+if (! function_exists('cp437toUTF')) {
+ /**
+ * Convert Code page 437 chars to UTF.
+ */
+ function cp437toUTF(string $string): string
+ {
+ return iconv('CP437', 'UTF-8//IGNORE//TRANSLIT', $string);
+ }
+}
+
+if (! function_exists('imdb_trailers')) {
+ /**
+ * Fetches an embeddable video to a IMDB trailer from http://www.traileraddict.com.
+ */
+ function imdb_trailers($imdbID): string
+ {
+ $xml = getRawHtml('https://api.traileraddict.com/?imdb='.$imdbID);
+ if ($xml !== false && preg_match('#(v\.traileraddict\.com/\d+)#i', $xml, $html)) {
+ return 'https://'.$html[1];
+ }
+
+ return '';
+ }
+}
+
+if (! function_exists('showApiError')) {
+ function showApiError(int $errorCode = 900, string $errorText = '')
+ {
+ $errorHeader = 'HTTP 1.1 400 Bad Request';
+ if ($errorText === '') {
+ switch ($errorCode) {
+ case 100:
+ $errorText = 'Incorrect user credentials';
+ $errorHeader = 'HTTP 1.1 401 Unauthorized';
+ break;
+ case 101:
+ $errorText = 'Account suspended';
+ $errorHeader = 'HTTP 1.1 403 Forbidden';
+ break;
+ case 102:
+ $errorText = 'Insufficient privileges/not authorized';
+ $errorHeader = 'HTTP 1.1 401 Unauthorized';
+ break;
+ case 103:
+ $errorText = 'Registration denied';
+ $errorHeader = 'HTTP 1.1 403 Forbidden';
+ break;
+ case 104:
+ $errorText = 'Registrations are closed';
+ $errorHeader = 'HTTP 1.1 403 Forbidden';
+ break;
+ case 105:
+ $errorText = 'Invalid registration (Email Address Taken)';
+ $errorHeader = 'HTTP 1.1 403 Forbidden';
+ break;
+ case 106:
+ $errorText = 'Invalid registration (Email Address Bad Format)';
+ $errorHeader = 'HTTP 1.1 403 Forbidden';
+ break;
+ case 107:
+ $errorText = 'Registration Failed (Data error)';
+ $errorHeader = 'HTTP 1.1 400 Bad Request';
+ break;
+ case 200:
+ $errorText = 'Missing parameter';
+ $errorHeader = 'HTTP 1.1 400 Bad Request';
+ break;
+ case 201:
+ $errorText = 'Incorrect parameter';
+ $errorHeader = 'HTTP 1.1 400 Bad Request';
+ break;
+ case 202:
+ $errorText = 'No such function';
+ $errorHeader = 'HTTP 1.1 404 Not Found';
+ break;
+ case 203:
+ $errorText = 'Function not available';
+ $errorHeader = 'HTTP 1.1 400 Bad Request';
+ break;
+ case 300:
+ $errorText = 'No such item';
+ $errorHeader = 'HTTP 1.1 404 Not Found';
+ break;
+ case 500:
+ $errorText = 'Request limit reached';
+ $errorHeader = 'HTTP 1.1 429 Too Many Requests';
+ break;
+ case 501:
+ $errorText = 'Download limit reached';
+ $errorHeader = 'HTTP 1.1 429 Too Many Requests';
+ break;
+ case 910:
+ $errorText = 'API disabled';
+ $errorHeader = 'HTTP 1.1 401 Unauthorized';
+ break;
+ default:
+ $errorText = 'Unknown error';
+ $errorHeader = 'HTTP 1.1 400 Bad Request';
+ break;
+ }
+ }
+
+ $response =
+ "\n".
+ '\n";
+
+ return response($response)->header('Content-type', 'text/xml')->header('Content-Length', strlen($response))->header('X-NNTmux', 'API ERROR ['.$errorCode.'] '.$errorText)->header('HTTP/1.1', $errorHeader);
+ }
+}
+
+if (! function_exists('getRange')) {
+ function getRange($tableName): \Illuminate\Contracts\Pagination\LengthAwarePaginator
+ {
+ $range = \Illuminate\Support\Facades\DB::table($tableName);
+ if ($tableName === 'xxxinfo') {
+ $range->selectRaw('UNCOMPRESS(plot) AS plot');
+ }
+
+ return $range->orderByDesc('created_at')->paginate(config('nntmux.items_per_page'));
+ }
+}
+
+if (! function_exists('isValidNewznabNzb')) {
+ /**
+ * Validate if the content is a valid Newznab NZB file.
+ *
+ * @param string $content The NZB file content
+ * @return bool True if valid NZB, false otherwise
+ */
+ function isValidNewznabNzb(string $content): bool
+ {
+ // Check if content starts with valid XML declaration and contains NZB namespace
+ if (empty($content)) {
+ return false;
+ }
+
+ // Try to load as XML
+ libxml_use_internal_errors(true);
+ $xml = @simplexml_load_string($content);
+
+ if ($xml === false) {
+ libxml_clear_errors();
+ return false;
+ }
+
+ // Check for NZB namespace or nzb root element
+ $namespaces = $xml->getNamespaces(true);
+ $hasNzbNamespace = isset($namespaces['']) && str_contains($namespaces[''], 'nzb');
+ $isNzbRoot = strtolower($xml->getName()) === 'nzb';
+
+ libxml_clear_errors();
+
+ return $hasNzbNamespace || $isNzbRoot;
+ }
+}
diff --git a/app/Http/Controllers/Admin/AdminConsoleController.php b/app/Http/Controllers/Admin/AdminConsoleController.php
index f837ac9b1..be10cfb13 100644
--- a/app/Http/Controllers/Admin/AdminConsoleController.php
+++ b/app/Http/Controllers/Admin/AdminConsoleController.php
@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BasePageController;
use Blacklight\Console;
use Blacklight\Genres;
-use Blacklight\utility\Utility;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
@@ -22,7 +21,7 @@ class AdminConsoleController extends BasePageController
$meta_title = $title = 'Console List';
- $consoleList = Utility::getRange('consoleinfo');
+ $consoleList = getRange('consoleinfo');
return view('admin.console.index', compact('consoleList', 'title', 'meta_title'));
}
diff --git a/app/Http/Controllers/Admin/AdminMusicController.php b/app/Http/Controllers/Admin/AdminMusicController.php
index ecf5adffa..96085909e 100644
--- a/app/Http/Controllers/Admin/AdminMusicController.php
+++ b/app/Http/Controllers/Admin/AdminMusicController.php
@@ -5,7 +5,6 @@ namespace App\Http\Controllers\Admin;
use App\Http\Controllers\BasePageController;
use Blacklight\Genres;
use Blacklight\Music;
-use Blacklight\utility\Utility;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
@@ -22,10 +21,10 @@ class AdminMusicController extends BasePageController
$search = $request->input('musicsearch', '');
if (! empty($search)) {
- $musicList = Utility::getRange('musicinfo', $search);
+ $musicList = getRange('musicinfo', $search);
$lastSearch = $search;
} else {
- $musicList = Utility::getRange('musicinfo');
+ $musicList = getRange('musicinfo');
$lastSearch = '';
}
diff --git a/app/Http/Controllers/Api/ApiController.php b/app/Http/Controllers/Api/ApiController.php
index 0f5f6d63f..854e5cb14 100644
--- a/app/Http/Controllers/Api/ApiController.php
+++ b/app/Http/Controllers/Api/ApiController.php
@@ -14,7 +14,6 @@ use App\Models\UserDownload;
use App\Models\UserRequest;
use Blacklight\NZB;
use Blacklight\Releases;
-use Blacklight\utility\Utility;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
@@ -73,10 +72,10 @@ class ApiController extends BasePageController
$function = 'nzbAdd';
break;
default:
- return Utility::showApiError(202, 'No such function ('.$request->input('t').')');
+ return showApiError(202, 'No such function ('.$request->input('t').')');
}
} else {
- return Utility::showApiError(200, 'Missing parameter (t)');
+ return showApiError(200, 'Missing parameter (t)');
}
$uid = $apiKey = $oldestGrabTime = $thisOldestTime = '';
@@ -87,17 +86,17 @@ class ApiController extends BasePageController
if ($function !== 'c' && $function !== 'r') {
if ($request->missing('apikey') || ($request->has('apikey') && empty($request->input('apikey')))) {
- return Utility::showApiError(200, 'Missing parameter (apikey)');
+ return showApiError(200, 'Missing parameter (apikey)');
}
$apiKey = $request->input('apikey');
$res = User::getByRssToken($apiKey);
if ($res === null) {
- return Utility::showApiError(100, 'Incorrect user credentials (wrong API key)');
+ return showApiError(100, 'Incorrect user credentials (wrong API key)');
}
if ($res->hasRole('Disabled')) {
- return Utility::showApiError(101);
+ return showApiError(101);
}
$uid = $res->id;
@@ -116,7 +115,7 @@ class ApiController extends BasePageController
$thisRequests = UserRequest::getApiRequests($uid);
$grabs = UserDownload::getDownloadRequests($uid);
if ($thisRequests > $maxRequests) {
- return Utility::showApiError(500, 'Request limit reached ('.$thisRequests.'/'.$maxRequests.')');
+ return showApiError(500, 'Request limit reached ('.$thisRequests.'/'.$maxRequests.')');
}
}
@@ -265,7 +264,7 @@ class ApiController extends BasePageController
$this->addCoverURL(
$relData,
function ($release) {
- return Utility::getCoverURL(['type' => 'movies', 'id' => $release->imdbid]);
+ return getCoverURL(['type' => 'movies', 'id' => $release->imdbid]);
}
);
@@ -281,12 +280,12 @@ class ApiController extends BasePageController
return redirect(url('/getnzb?r='.$apiKey.'&id='.$request->input('id').(($request->has('del') && $request->input('del') === '1') ? '&del=1' : '')));
}
- return Utility::showApiError(300, 'No such item (the guid you provided has no release in our database)');
+ return showApiError(300, 'No such item (the guid you provided has no release in our database)');
// Get individual NZB details.
case 'd':
if ($request->missing('id')) {
- return Utility::showApiError(200, 'Missing parameter (guid is required for single release details)');
+ return showApiError(200, 'Missing parameter (guid is required for single release details)');
}
UserRequest::addApiRequest($apiKey, $request->getRequestUri());
@@ -298,7 +297,7 @@ class ApiController extends BasePageController
// Get an NFO file for an individual release.
case 'n':
if ($request->missing('id')) {
- return Utility::showApiError(200, 'Missing parameter (id is required for retrieving an NFO)');
+ return showApiError(200, 'Missing parameter (id is required for retrieving an NFO)');
}
UserRequest::addApiRequest($apiKey, $request->getRequestUri());
@@ -313,12 +312,12 @@ class ApiController extends BasePageController
}, $rel['searchname'].'.nfo', ['Content-type:' => 'application/octet-stream']);
}
- echo nl2br(Utility::cp437toUTF($data['nfo']));
+ echo nl2br(cp437toUTF($data['nfo']));
} else {
- return Utility::showApiError(300, 'Release does not have an NFO file associated.');
+ return showApiError(300, 'Release does not have an NFO file associated.');
}
} else {
- return Utility::showApiError(300, 'Release does not exist.');
+ return showApiError(300, 'Release does not exist.');
}
break;
//
@@ -352,7 +351,7 @@ class ApiController extends BasePageController
return response('File is not an NZB file', 400);
}
// Check if the file is proper xml nzb file.
- if (! Utility::isValidNewznabNzb($nzbFile->getContent())) {
+ if (! isValidNewznabNzb($nzbFile->getContent())) {
return response('File is not a valid Newznab NZB file', 400);
}
if (! File::isDirectory(config('nntmux.nzb_upload_folder'))) {
@@ -406,7 +405,7 @@ class ApiController extends BasePageController
header('Content-type: application/json');
}
if ($response === false) {
- return Utility::showApiError(201);
+ return showApiError(201);
} else {
header('Content-Length: '.\strlen($response));
echo $response;
@@ -461,9 +460,9 @@ class ApiController extends BasePageController
$maxAge = -1;
if ($request->has('maxage')) {
if (! $request->filled('maxage')) {
- return Utility::showApiError(201, 'Incorrect parameter (maxage must not be empty)');
+ return showApiError(201, 'Incorrect parameter (maxage must not be empty)');
} elseif (! is_numeric($request->input('maxage'))) {
- return Utility::showApiError(201, 'Incorrect parameter (maxage must be numeric)');
+ return showApiError(201, 'Incorrect parameter (maxage must be numeric)');
} else {
$maxAge = (int) $request->input('maxage');
}
@@ -541,7 +540,7 @@ class ApiController extends BasePageController
public function verifyEmptyParameter(Request $request, string $parameter)
{
if ($request->has($parameter) && $request->isNotFilled($parameter)) {
- return Utility::showApiError(201, 'Incorrect parameter ('.$parameter.' must not be empty)');
+ return showApiError(201, 'Incorrect parameter ('.$parameter.' must not be empty)');
}
}
diff --git a/app/Http/Controllers/GetNzbController.php b/app/Http/Controllers/GetNzbController.php
index f73a09fa7..e0617e223 100644
--- a/app/Http/Controllers/GetNzbController.php
+++ b/app/Http/Controllers/GetNzbController.php
@@ -7,7 +7,6 @@ use App\Models\User;
use App\Models\UserDownload;
use App\Models\UsersRelease;
use Blacklight\NZB;
-use Blacklight\utility\Utility;
use Exception;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Contracts\Routing\ResponseFactory;
@@ -100,7 +99,7 @@ class GetNzbController extends BasePageController
private function getUserDataFromSession()
{
if ($this->userdata->hasRole('Disabled')) {
- return Utility::showApiError(101);
+ return showApiError(101);
}
return [
@@ -119,16 +118,16 @@ class GetNzbController extends BasePageController
private function getUserDataFromRssToken(Request $request)
{
if ($request->missing('r')) {
- return Utility::showApiError(200);
+ return showApiError(200);
}
$user = User::getByRssToken($request->input('r'));
if (! $user) {
- return Utility::showApiError(100);
+ return showApiError(100);
}
if ($user->hasRole('Disabled')) {
- return Utility::showApiError(101);
+ return showApiError(101);
}
return [
@@ -150,7 +149,7 @@ class GetNzbController extends BasePageController
{
$requests = UserDownload::getDownloadRequests($uid);
if ($requests > $maxDownloads) {
- return Utility::showApiError(501);
+ return showApiError(501);
}
return null;
@@ -166,7 +165,7 @@ class GetNzbController extends BasePageController
$id = $request->input('id');
if (empty($id)) {
- return Utility::showApiError(200, 'Parameter id is required');
+ return showApiError(200, 'Parameter id is required');
}
// Remove .nzb suffix if present
@@ -204,7 +203,7 @@ class GetNzbController extends BasePageController
// Check if zip download would exceed limits
$requests = UserDownload::getDownloadRequests($uid);
if ($requests + $guidCount > $maxDownloads) {
- return Utility::showApiError(501);
+ return showApiError(501);
}
$zip = getStreamingZip($guids);
@@ -254,13 +253,13 @@ class GetNzbController extends BasePageController
// Get NZB file path and validate
$nzbPath = (new NZB)->getNZBPath($releaseId);
if (! File::exists($nzbPath)) {
- return Utility::showApiError(300, 'NZB file not found!');
+ return showApiError(300, 'NZB file not found!');
}
// Get release data
$releaseData = Release::getByGuid($releaseId);
if ($releaseData === null) {
- return Utility::showApiError(300, 'Release not found!');
+ return showApiError(300, 'Release not found!');
}
// Update statistics
diff --git a/app/Http/Controllers/NfoController.php b/app/Http/Controllers/NfoController.php
index b510a737c..df26c9feb 100644
--- a/app/Http/Controllers/NfoController.php
+++ b/app/Http/Controllers/NfoController.php
@@ -4,7 +4,6 @@ namespace App\Http\Controllers;
use App\Models\Release;
use App\Models\ReleaseNfo;
-use Blacklight\utility\Utility;
use Illuminate\Http\Request;
class NfoController extends BasePageController
@@ -24,7 +23,7 @@ class NfoController extends BasePageController
$nfo = ReleaseNfo::getReleaseNfo($rel['id']);
if ($nfo !== null) {
- $nfo['nfoUTF'] = Utility::cp437toUTF($nfo['nfo']);
+ $nfo['nfoUTF'] = cp437toUTF($nfo['nfo']);
$modal = $request->has('modal');
diff --git a/app/Services/AdditionalProcessing/AdditionalProcessingOrchestrator.php b/app/Services/AdditionalProcessing/AdditionalProcessingOrchestrator.php
index 08c7c70ed..708051ddf 100644
--- a/app/Services/AdditionalProcessing/AdditionalProcessingOrchestrator.php
+++ b/app/Services/AdditionalProcessing/AdditionalProcessingOrchestrator.php
@@ -8,7 +8,6 @@ use App\Services\AdditionalProcessing\Config\ProcessingConfiguration;
use App\Services\AdditionalProcessing\DTO\ReleaseProcessingContext;
use App\Services\TempWorkspaceService;
use Blacklight\Releases;
-use Blacklight\utility\Utility;
use Exception;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
@@ -685,7 +684,7 @@ class AdditionalProcessingOrchestrator
}
// Check file magic
- $output = Utility::fileInfo($filePath);
+ $output = fileInfo($filePath);
if (empty($output)) {
continue;
}
diff --git a/app/Services/AdditionalProcessing/NzbContentParser.php b/app/Services/AdditionalProcessing/NzbContentParser.php
index 74d9d5246..e8a84f5cf 100644
--- a/app/Services/AdditionalProcessing/NzbContentParser.php
+++ b/app/Services/AdditionalProcessing/NzbContentParser.php
@@ -3,7 +3,6 @@
namespace App\Services\AdditionalProcessing;
use Blacklight\NZB;
-use Blacklight\utility\Utility;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Log;
@@ -32,7 +31,7 @@ class NzbContentParser
return ['contents' => [], 'error' => 'NZB not found for GUID: '.$guid];
}
- $nzbContents = Utility::unzipGzipFile($nzbPath);
+ $nzbContents = unzipGzipFile($nzbPath);
if (! $nzbContents) {
// Try repair on raw file contents
$nzbContents = $this->attemptRawRepair($nzbPath);
diff --git a/app/Services/AdditionalProcessing/ReleaseFileManager.php b/app/Services/AdditionalProcessing/ReleaseFileManager.php
index 18f165618..8aeebe8a7 100644
--- a/app/Services/AdditionalProcessing/ReleaseFileManager.php
+++ b/app/Services/AdditionalProcessing/ReleaseFileManager.php
@@ -440,9 +440,9 @@ class ReleaseFileManager
}
// Try CP437 (DOS encoding - common for scene NFOs with ASCII art)
- // Use the utility function if available
- if (class_exists('\Blacklight\utility\Utility') && method_exists('\Blacklight\utility\Utility', 'cp437toUTF')) {
- return \Blacklight\utility\Utility::cp437toUTF($data);
+ // Use the cp437toUTF helper function
+ if (function_exists('cp437toUTF')) {
+ return cp437toUTF($data);
}
// Fallback: try ISO-8859-1 (Latin-1)
diff --git a/app/Services/TvProcessing/Providers/AbstractTvProvider.php b/app/Services/TvProcessing/Providers/AbstractTvProvider.php
index 7fad5bee2..77b562614 100644
--- a/app/Services/TvProcessing/Providers/AbstractTvProvider.php
+++ b/app/Services/TvProcessing/Providers/AbstractTvProvider.php
@@ -10,7 +10,6 @@ use App\Models\TvInfo;
use App\Models\Video;
use Blacklight\ColorCLI;
use Blacklight\Releases;
-use Blacklight\utility\Country;
use Illuminate\Support\Facades\DB;
/**
@@ -182,7 +181,7 @@ abstract class AbstractTvProvider extends BaseVideoProvider
// Check if the country is not a proper code and retrieve if not
if ($show['country'] !== '' && \strlen($show['country']) > 2) {
- $show['country'] = Country::countryCode($show['country']);
+ $show['country'] = countryCode($show['country']);
}
// Check if video already exists based on site ID info
@@ -257,7 +256,7 @@ abstract class AbstractTvProvider extends BaseVideoProvider
public function update(int $videoId, array $show = []): void
{
if ($show['country'] !== '') {
- $show['country'] = Country::countryCode($show['country']);
+ $show['country'] = countryCode($show['country']);
}
$ifStringID = 'IF(%s = 0, %s, %s)';
diff --git a/misc/testing/Dev/clean_nzbs.php b/misc/testing/Dev/clean_nzbs.php
index e6f36f67a..c32290d4d 100644
--- a/misc/testing/Dev/clean_nzbs.php
+++ b/misc/testing/Dev/clean_nzbs.php
@@ -7,7 +7,6 @@ use Blacklight\ColorCLI;
use Blacklight\NZB;
use Blacklight\ReleaseImage;
use Blacklight\Releases;
-use Blacklight\utility\Utility;
use Illuminate\Support\Facades\File;
$dir = resource_path().'/movednzbs/';
@@ -41,7 +40,7 @@ $itr = new RecursiveIteratorIterator($dirItr, RecursiveIteratorIterator::LEAVES_
foreach ($itr as $filePath) {
$guid = stristr($filePath->getFilename(), '.nzb.gz', true);
if (File::isFile($filePath) && $guid) {
- $nzbfile = Utility::unzipGzipFile($filePath);
+ $nzbfile = unzipGzipFile($filePath);
$nzbContents = $nzb->nzbFileList($nzbfile, ['no-file-key' => false, 'strip-count' => true]);
if (! $nzbfile || ! @simplexml_load_string($nzbfile) || count($nzbContents) === 0) {
if ($argv[1] === 'move') {