mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-28 17:01:16 +00:00
Update bootstrapping and create Yenc service and facade
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,232 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program (see LICENSE.txt in the base directory. If
|
||||
* not, see:.
|
||||
*
|
||||
* @link <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* @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<string, string>|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<string, string>|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<string, string> $decodeTable */
|
||||
$decodeTable = self::$decodeTable;
|
||||
/** @var array<string, string> $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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Facades;
|
||||
|
||||
use Illuminate\Support\Facades\Facade;
|
||||
|
||||
/**
|
||||
* Yenc Facade
|
||||
*
|
||||
* @method static string|false decode(string &$text, bool $ignore = false)
|
||||
* @method static string decodeIgnore(string &$text)
|
||||
* @method static bool enabled()
|
||||
* @method static bool isYencEncoded(string $text)
|
||||
* @method static string encode(string $data, string $filename, int $lineLength = 128, bool $includeCrc32 = true)
|
||||
* @method static array|null extractMetadata(string $text)
|
||||
*
|
||||
* @see \App\Services\YencService
|
||||
*/
|
||||
class Yenc extends Facade
|
||||
{
|
||||
/**
|
||||
* Get the registered name of the component.
|
||||
*/
|
||||
protected static function getFacadeAccessor(): string
|
||||
{
|
||||
return \App\Services\YencService::class;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
namespace App\Services\NNTP;
|
||||
|
||||
use App\Extensions\util\PhpYenc;
|
||||
use App\Models\Settings;
|
||||
use App\Services\Tmux\Tmux;
|
||||
use App\Services\YencService;
|
||||
|
||||
/*
|
||||
* Response codes not defined in Net_NNTP
|
||||
@@ -134,15 +134,21 @@ class NNTPService extends \Net_NNTP_Client
|
||||
*/
|
||||
protected string $_yEncTempOutput;
|
||||
|
||||
/**
|
||||
* YEnc encoding/decoding service.
|
||||
*/
|
||||
protected YencService $_yencService;
|
||||
|
||||
/**
|
||||
* Create a new NNTP service instance.
|
||||
*/
|
||||
public function __construct(?Tmux $tmux = null)
|
||||
public function __construct(?Tmux $tmux = null, ?YencService $yencService = null)
|
||||
{
|
||||
parent::__construct();
|
||||
|
||||
$this->_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.
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
@@ -10,10 +11,8 @@
|
||||
* New location: app/Services/Tmux/Scripts/groupfixrelnames.php
|
||||
*/
|
||||
|
||||
require_once __DIR__.'/../../../../bootstrap/autoload.php';
|
||||
|
||||
if (! isset($argv[1])) {
|
||||
cli()->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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
@@ -10,10 +11,8 @@
|
||||
* New location: app/Services/Tmux/Scripts/postprocess_pre.php
|
||||
*/
|
||||
|
||||
require_once __DIR__.'/../../../../bootstrap/autoload.php';
|
||||
|
||||
$limit = isset($argv[1]) && is_numeric($argv[1]) ? $argv[1] : '';
|
||||
$artisan = base_path('artisan');
|
||||
$artisan = dirname(__DIR__, 4).'/artisan';
|
||||
|
||||
$command = "php {$artisan} predb:check".($limit ? " {$limit}" : '');
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
|
||||
/**
|
||||
@@ -10,10 +11,7 @@
|
||||
* New location: app/Services/Tmux/Scripts/update_groups.php
|
||||
*/
|
||||
|
||||
require_once __DIR__.'/../../../../bootstrap/autoload.php';
|
||||
$artisan = dirname(__DIR__, 4).'/artisan';
|
||||
|
||||
$artisan = base_path('artisan');
|
||||
$command = "php {$artisan} groups:update";
|
||||
|
||||
passthru($command, $exitCode);
|
||||
passthru("php {$artisan} groups:update", $exitCode);
|
||||
exit($exitCode);
|
||||
|
||||
@@ -0,0 +1,293 @@
|
||||
<?php
|
||||
|
||||
namespace App\Services;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* YEnc encoding/decoding service.
|
||||
*
|
||||
* Provides optimized yEnc encoder/decoder implementation for Usenet article processing.
|
||||
*/
|
||||
class YencService
|
||||
{
|
||||
/**
|
||||
* Pre-computed decode translation table for non-escaped characters.
|
||||
* Maps yEnc encoded byte to decoded byte: (byte - 42) % 256
|
||||
*
|
||||
* @var array<string, string>|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<string, string>|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<string, string> $decodeTable */
|
||||
$decodeTable = $this->decodeTable;
|
||||
/** @var array<string, string> $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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Dotenv\Dotenv;
|
||||
use Dotenv\Repository\RepositoryBuilder;
|
||||
use Illuminate\Contracts\Console\Kernel;
|
||||
|
||||
require_once dirname(__DIR__).DIRECTORY_SEPARATOR.'vendor'.DIRECTORY_SEPARATOR.'autoload.php';
|
||||
require __DIR__.DIRECTORY_SEPARATOR.'app.php';
|
||||
require_once dirname(__DIR__).DIRECTORY_SEPARATOR.'app/Extensions/util/PhpYenc.php';
|
||||
|
||||
$repository = RepositoryBuilder::createWithDefaultAdapters()->make();
|
||||
|
||||
$dotenv = Dotenv::create($repository, dirname(__DIR__, 1), null)->load();
|
||||
|
||||
/** @var Kernel $kernel */
|
||||
$kernel = app(Kernel::class);
|
||||
$kernel->bootstrap();
|
||||
@@ -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(),
|
||||
|
||||
];
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This script will convert releases table imdbid column
|
||||
* from zerofilled int to varchar(15).
|
||||
*/
|
||||
use App\Models\MovieInfo;
|
||||
use App\Models\Release;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
$sql = Release::query()->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');
|
||||
}
|
||||
@@ -1,52 +0,0 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This script will convert releases table imdbid column
|
||||
* from zerofilled int to varchar(15).
|
||||
*/
|
||||
use App\Models\Release;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
$sql = Release::query()->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');
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\Release;
|
||||
use App\Models\ReleaseFile;
|
||||
|
||||
use Blacklight\Releases;
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
$passFiles = ReleaseFile::query()->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');
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
$tmux = Illuminate\Support\Facades\DB::table('tmux')->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,
|
||||
]
|
||||
);
|
||||
}
|
||||
@@ -1,323 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\Category;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
|
||||
|
||||
$ran = false;
|
||||
|
||||
if (isset($argv[1]) && $argv[1] === 'all' && isset($argv[2]) && $argv[2] === 'true') {
|
||||
$ran = true;
|
||||
$where = '';
|
||||
if (isset($argv[3]) && $argv[3] === 'truncate') {
|
||||
echo 'Truncating tables';
|
||||
DB::select('TRUNCATE TABLE consoleinfo');
|
||||
DB::select('TRUNCATE TABLE gamesinfo');
|
||||
DB::select('TRUNCATE TABLE movieinfo');
|
||||
DB::select('TRUNCATE TABLE video_data');
|
||||
DB::select('TRUNCATE TABLE musicinfo');
|
||||
DB::select('TRUNCATE TABLE bookinfo');
|
||||
DB::select('TRUNCATE TABLE release_nfos');
|
||||
DB::select('TRUNCATE TABLE xxxinfo');
|
||||
DB::select('TRUNCATE TABLE videos');
|
||||
DB::select('TRUNCATE TABLE videos_aliases');
|
||||
DB::select('TRUNCATE TABLE tv_info');
|
||||
DB::select('TRUNCATE TABLE tv_episodes');
|
||||
DB::select('TRUNCATE TABLE anidb_info');
|
||||
}
|
||||
cli()->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;
|
||||
@@ -1,78 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\Release;
|
||||
use App\Services\Nzb\NzbParserService;
|
||||
use App\Services\Nzb\NzbService;
|
||||
use App\Services\ReleaseImageService;
|
||||
|
||||
use Blacklight\Releases;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
$dir = resource_path().'/movednzbs/';
|
||||
|
||||
|
||||
if (! isset($argv[1]) || ! in_array($argv[1], ['true', 'move'])) {
|
||||
cli()->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().']');
|
||||
@@ -1,72 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\Release;
|
||||
use App\Models\UsenetGroup;
|
||||
use App\Services\Search\ManticoreSearchService;
|
||||
use App\Services\ReleaseCleaningService;
|
||||
|
||||
$message =
|
||||
'Shows old searchname vs new searchname for releases in a group using the releaseCleaning class. (Good for testing new regex)'.
|
||||
PHP_EOL.
|
||||
'Argument 1 is the group name.'.PHP_EOL.
|
||||
'Argument 2 is how many releases to limit this to, must be a number.'.PHP_EOL.
|
||||
'Argument 3 (true|false) true renames the releases, false only displays what could be changed.'.PHP_EOL.
|
||||
'Argument 4 is a categoryID, pass 0 to do all, 0010 to do misc, etc.'.PHP_EOL.
|
||||
'php '.$argv[0].' alt.binaries.comics.dcp 1000 false'.PHP_EOL;
|
||||
|
||||
if ($argc < 5) {
|
||||
exit($message);
|
||||
}
|
||||
if (! is_numeric($argv[2]) || ! is_numeric($argv[4])) {
|
||||
exit($message);
|
||||
}
|
||||
if (! in_array($argv[3], ['true', 'false'], false)) {
|
||||
exit($message);
|
||||
}
|
||||
|
||||
$category = '';
|
||||
|
||||
$rename = false;
|
||||
if ($argv[3] === 'true') {
|
||||
$rename = true;
|
||||
}
|
||||
|
||||
$group = UsenetGroup::query()->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,196 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
if (! isset($argv[1]) || ! isset($argv[2])) {
|
||||
exit(
|
||||
'Argument 1 is a input string. ie PRE name.'.PHP_EOL.
|
||||
'Argument 2 is a expected hash or encoding. ie MD5 string. Passing true on Argument 3 ignores this.'.PHP_EOL.
|
||||
'Argument 3 (optional) False, exit on first match. True, write all matches to text file in current path.'.PHP_EOL.
|
||||
'ie: php test_hash_algorithms.php Dog.with.a.Blog.S02E16.Love.Loss.and.a.Beanbag.Toss.HDTV.x264-QCF 11506192c6d92e0c9c795b9997d9396226dbdf62'.PHP_EOL.
|
||||
'ie: php test_hash_algorithms.php Anchorman.2.The.Legend.Continues.2013.UNRATED.WEBRip.x264-FLS false true'.PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test various hashing/encoding/etc on a string.
|
||||
* Class hash_algorithms.
|
||||
*/
|
||||
class HashAlgorithms
|
||||
{
|
||||
/**
|
||||
* The input string.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $_inputString;
|
||||
|
||||
/**
|
||||
* The string we are expecting to get.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $_expectedString;
|
||||
|
||||
/**
|
||||
* Write results to file?
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
protected $_writeToFile;
|
||||
|
||||
/**
|
||||
* @param string $inputString
|
||||
* @param string $expectedString
|
||||
* @param bool $writeToFile
|
||||
*/
|
||||
public function __construct($inputString, $expectedString, $writeToFile)
|
||||
{
|
||||
$this->_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));
|
||||
@@ -1,47 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\Settings;
|
||||
use App\Services\Nzb\NzbService;
|
||||
|
||||
|
||||
if (! isset($argv[1]) || ! isset($argv[2])) {
|
||||
exit("ERROR: You must supply the level you want to reorganize it to, and the source directory (You would use: 3 .../newznab/resources/nzb/ to move it to 3 levels deep)\n");
|
||||
}
|
||||
|
||||
$nzb = app(NzbService::class);
|
||||
|
||||
|
||||
$newLevel = $argv[1];
|
||||
$sourcePath = $argv[2];
|
||||
$objects = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($sourcePath));
|
||||
|
||||
$filestoprocess = [];
|
||||
$iFilesProcessed = $iFilesCounted = 0;
|
||||
$time = now()->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");
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// Scan for releases missing previews on disk
|
||||
// --------------------------------------------------------------
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\MovieService;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$movie = new MovieService();
|
||||
$movie->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");
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
// --------------------------------------------------------------
|
||||
// Scan for releases missing previews on disk
|
||||
// --------------------------------------------------------------
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\Release;
|
||||
use App\Services\Nzb\NzbService;
|
||||
use App\Services\ReleaseImageService;
|
||||
|
||||
use Blacklight\Releases;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$pdo = DB::connection()->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();
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This script will update all records in the consoleinfo table
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Services\ConsoleService;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$pdo = DB::connection()->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This script will update all records in the gamesinfo table
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\GamesService;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$pdo = DB::connection()->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This script will update all records in the movieinfo table
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\MovieService;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$pdo = DB::connection()->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');
|
||||
}
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This script will update all records in the movieinfo table where there is no cover
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\MovieInfo;
|
||||
use App\Services\MovieService;
|
||||
|
||||
|
||||
$movie = new MovieService();
|
||||
$movie->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');
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This script will update all records in the movieinfo table where there is no cover
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\MovieInfo;
|
||||
use App\Services\MovieService;
|
||||
use App\Services\TvProcessing\Providers\TraktProvider;
|
||||
|
||||
|
||||
$movie = new MovieService();
|
||||
$movie->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');
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
// This script will update all records in the xxxinfo table where there is no cover
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\AdultProcessing\AdultProcessingPipeline;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$pipeline = new AdultProcessingPipeline([], true);
|
||||
|
||||
|
||||
$movies = DB::select('SELECT title FROM xxxinfo WHERE cover = 0');
|
||||
|
||||
echo cli()->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";
|
||||
@@ -1,59 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Services\ReleaseImageService;
|
||||
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
$pdo = DB::connection()->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();
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\BookInfo;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
$covers = $updated = $deleted = 0;
|
||||
|
||||
|
||||
if ($argc === 1 || $argv[1] !== 'true') {
|
||||
cli()->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.');
|
||||
@@ -1,56 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\ConsoleInfo;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
$covers = $updated = $deleted = 0;
|
||||
|
||||
|
||||
if ($argc === 1 || $argv[1] !== 'true') {
|
||||
cli()->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.');
|
||||
@@ -1,48 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\GamesInfo;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
$covers = $updated = $deleted = 0;
|
||||
|
||||
|
||||
if ($argc === 1 || $argv[1] !== 'true') {
|
||||
cli()->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.');
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\MovieInfo;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
$covers = $updated = $deleted = 0;
|
||||
|
||||
|
||||
if ($argc === 1 || $argv[1] !== 'true') {
|
||||
cli()->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.');
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\MusicInfo;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
$covers = $updated = $deleted = 0;
|
||||
|
||||
|
||||
if ($argc === 1 || $argv[1] !== 'true') {
|
||||
cli()->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.');
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\XxxInfo;
|
||||
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
$covers = $updated = $deleted = 0;
|
||||
|
||||
|
||||
if ($argc === 1 || $argv[1] !== 'true') {
|
||||
cli()->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.');
|
||||
@@ -1,57 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
|
||||
use Blacklight\ReleaseRemover;
|
||||
|
||||
// New line for CLI.
|
||||
$n = PHP_EOL;
|
||||
|
||||
// Include config.php
|
||||
|
||||
// ColorCLI class.
|
||||
|
||||
|
||||
// Print arguments/usage.
|
||||
$totalArgs = count($argv);
|
||||
if ($totalArgs < 2) {
|
||||
exit(cli()->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));
|
||||
@@ -1,131 +0,0 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* This script attempts to clean release names using the NFO, file name and release name, Par2 file.
|
||||
* A good way to use this script is to use it in this order: php fixReleaseNames.php 3 true other yes
|
||||
* php fixReleaseNames.php 5 true other yes
|
||||
* If you used the 4th argument yes, but you want to reset the status,
|
||||
* there is another script called resetRelnameStatus.php
|
||||
*/
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\NameFixing\NameFixingService;
|
||||
use App\Services\NNTP\NNTPService;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
|
||||
$output = new ConsoleOutput;
|
||||
$nameFixingService = new NameFixingService;
|
||||
$nntp = new NNTPService;
|
||||
|
||||
if (isset($argv[1], $argv[2], $argv[3], $argv[4])) {
|
||||
$update = $argv[2] === 'true';
|
||||
$other = 1;
|
||||
if ($argv[3] === 'all') {
|
||||
$other = 2;
|
||||
} elseif ($argv[3] === 'predb_id') {
|
||||
$other = 3;
|
||||
}
|
||||
$setStatus = $argv[4] === 'yes';
|
||||
|
||||
$show = isset($argv[5]) && $argv[5] === 'show';
|
||||
if ($argv[1] === '7' || $argv[1] === '8') {
|
||||
$compressedHeaders = config('nntmux_nntp.compressed_headers');
|
||||
if ((config('nntmux_nntp.use_alternate_nntp_server') === true ? $nntp->doConnect($compressedHeaders, true) : $nntp->doConnect()) !== true) {
|
||||
$output->writeln('<error>Unable to connect to usenet.</error>');
|
||||
|
||||
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('<error>'.PHP_EOL.'ERROR: Wrong argument, type php '.$argv[0].' to see a list of valid arguments.</error>');
|
||||
exit(1);
|
||||
}
|
||||
} else {
|
||||
$output->writeln([
|
||||
'',
|
||||
'<error>You must supply 4 arguments.</error>',
|
||||
'<comment>The 2nd argument, false, will display the results, but not change the name, type true to have the names changed.</comment>',
|
||||
'<comment>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.</comment>',
|
||||
'<comment>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.</comment>',
|
||||
'<comment>The 5th argument (optional), show, will display the release changes or only show a counter.</comment>',
|
||||
'',
|
||||
'<info>php '.$argv[0].' 3 false other no ...: Fix release names using NFO in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 4 false other no ...: Fix release names using NFO.</info>',
|
||||
'<info>php '.$argv[0].' 5 false other no ...: Fix release names in misc categories using File Name in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 6 false other no ...: Fix release names in misc categories using File Name.</info>',
|
||||
'<info>php '.$argv[0].' 7 false other no ...: Fix release names in misc categories using Par2 Files in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 8 false other no ...: Fix release names in misc categories using Par2 Files.</info>',
|
||||
'<info>php '.$argv[0].' 9 false other no ...: Fix release names in misc categories using UID in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 10 false other no ...: Fix release names in misc categories using UID.</info>',
|
||||
'<info>php '.$argv[0].' 11 false other no ...: Fix SDPORN XXX release names in misc categories using specific File Name in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 12 false other no ...: Fix SDPORN XXX release names in misc categories using specific File Name.</info>',
|
||||
'<info>php '.$argv[0].' 13 false other no ...: Fix release names in misc categories using SRR files in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 14 false other no ...: Fix release names in misc categories using SRR files.</info>',
|
||||
'<info>php '.$argv[0].' 15 false other no ...: Fix release names in misc categories using PAR2 hash_16K block in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 16 false other no ...: Fix release names in misc categories using PAR2 hash_16K block.</info>',
|
||||
'<info>php '.$argv[0].' 17 false other no ...: Fix release names in misc categories using Mediainfo in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 18 false other no ...: Fix release names in misc categories using Mediainfo.</info>',
|
||||
'<info>php '.$argv[0].' 19 false other no ...: Fix release names in misc categories using CRC32 in the past 6 hours.</info>',
|
||||
'<info>php '.$argv[0].' 20 false other no ...: Fix release names in misc categories using CRC32.</info>',
|
||||
'',
|
||||
]);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
@@ -1,112 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Models\Category;
|
||||
use App\Models\Release;
|
||||
use App\Services\Categorization\CategorizationService;
|
||||
|
||||
|
||||
|
||||
|
||||
if (! (isset($argv[1]) && ($argv[1] === 'all' || $argv[1] === 'misc' || preg_match('/\([\d, ]+\)/', $argv[1]) || is_numeric($argv[1])))) {
|
||||
cli()->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;
|
||||
}
|
||||
@@ -1,69 +0,0 @@
|
||||
<?php
|
||||
|
||||
/* This script deletes releases that match certain criteria, type php removeCrapReleases.php false for details. */
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
|
||||
use Blacklight\ReleaseRemover;
|
||||
|
||||
|
||||
|
||||
$n = PHP_EOL;
|
||||
|
||||
$argCnt = count($argv);
|
||||
if ($argCnt === 1) {
|
||||
exit(
|
||||
cli()->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] : '');
|
||||
@@ -1,25 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\FanartTvService;
|
||||
|
||||
|
||||
$fanart = new FanartTvService();
|
||||
|
||||
|
||||
if (! empty($argv[1])) {
|
||||
// Test if you can fetch Fanart.TV images
|
||||
|
||||
// Search for a movie/tv
|
||||
$moviefanart = $fanart->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();
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use aharen\OMDbAPI;
|
||||
|
||||
|
||||
$omdb = new OMDbAPI(config('nntmux_api.omdb_api_key'));
|
||||
|
||||
|
||||
if (! empty($argv[1]) && ! empty($argv[2]) && ($argv[2] !== 'series' || $argv[2] !== 'movie')) {
|
||||
// Test if your OMDb API key and configuration are working
|
||||
// If it works you should get a printed array of the show entered
|
||||
|
||||
// Search for a show
|
||||
$search = $omdb->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();
|
||||
}
|
||||
@@ -1,75 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\TmdbClient;
|
||||
|
||||
|
||||
|
||||
|
||||
if (! empty($argv[1]) && is_numeric($argv[2]) && is_numeric($argv[3])) {
|
||||
// Test if your TMDB API configuration is working
|
||||
// If it works you should get a var dumped array of the show/season/episode entered
|
||||
|
||||
$tmdbClient = app(TmdbClient::class);
|
||||
|
||||
if (! $tmdbClient->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.'));
|
||||
}
|
||||
@@ -1,29 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\TraktService;
|
||||
|
||||
|
||||
$trakt = new TraktService;
|
||||
|
||||
if (! empty($argv[1]) && is_numeric($argv[2]) && is_numeric($argv[3])) {
|
||||
// Test if your Trakt API key and configuration are working
|
||||
// If it works you should get a printed array of the show/season/episode entered
|
||||
|
||||
// Search for a show
|
||||
$series = $trakt->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.'));
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\TvProcessing\Providers\TvdbProvider;
|
||||
|
||||
|
||||
$tvDB = new TvdbProvider;
|
||||
|
||||
if (! empty($argv[1]) && isset($argv[2], $argv[3]) && is_numeric($argv[2]) && is_numeric($argv[3])) {
|
||||
// Test if your TvDB API key and configuration are working
|
||||
// If it works you should get a var dumped array of the show/season/episode entered
|
||||
|
||||
$season = (int) $argv[2];
|
||||
$episode = (int) $argv[3];
|
||||
|
||||
// Search for a show
|
||||
$series = $tvDB->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.')
|
||||
);
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 3).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\TvProcessing\Providers\TvMazeProvider;
|
||||
|
||||
|
||||
$tvmaze = new TvMazeProvider;
|
||||
|
||||
if (! empty($argv[1]) && is_numeric($argv[2]) && is_numeric($argv[3])) {
|
||||
// Test if your TVMaze API configuration is working
|
||||
// If it works you should get a var dumped array of the show/season/episode entered
|
||||
|
||||
$season = (int) $argv[2];
|
||||
$episode = (int) $argv[3];
|
||||
|
||||
// Search for a show
|
||||
$series = $tvmaze->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.'));
|
||||
}
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
require_once dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
// Reset cached roles and permissions
|
||||
app('cache')->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']);
|
||||
@@ -1,19 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Spatie\Permission\Models\Permission;
|
||||
|
||||
require_once dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
// Reset cached roles and permissions
|
||||
app('cache')->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']);
|
||||
@@ -1,83 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
use App\Services\Nzb\NzbImportService;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
$n = PHP_EOL;
|
||||
|
||||
// Print usage.
|
||||
if (count($argv) !== 6) {
|
||||
exit(
|
||||
'This will import NZB files(.nzb or .nzb.gz), into your newznab site from a folder recursively(it will go down into sub-folders).'.$n.
|
||||
'Please use arg5, something sensible like 100k, if you have millions of NZB files the initial scan will be VERY slow otherwise.'.$n.$n.
|
||||
'Usage: '.$n.
|
||||
$_SERVER['_'].' '.__FILE__.' arg1 arg2 arg3 arg4 arg5'.$n.$n.
|
||||
'arg1 : Path to folder where NZB files are stored. | a folder path'.$n.
|
||||
'arg2 : Delete NZB when successfully imported.(recommended) | true/false'.$n.
|
||||
'arg3 : Delete NZB when unsuccessfully imported.(not recommended) | true/false'.$n.
|
||||
'arg4 : Use NZB file name as release name.(not recommended) | true/false'.$n.
|
||||
'arg5 : Import this many NZB files. (RECOMMENDED 100,000) | a number'.$n.$n.
|
||||
'ie: '.$_SERVER['_'].' '.__FILE__.' '.base_path('nzbToImport/ true false false 1000').$n
|
||||
);
|
||||
}
|
||||
|
||||
// Verify arguments.
|
||||
if (! is_dir($argv[1])) {
|
||||
exit('Error: arg1 must be a path (you might not have read access to this path)'.$n);
|
||||
}
|
||||
if (! in_array($argv[2], ['true', 'false'], false)) {
|
||||
exit('Error: arg2 must be true or false'.$n);
|
||||
}
|
||||
if (! in_array($argv[3], ['true', 'false'], false)) {
|
||||
exit('Error: arg3 must be true or false'.$n);
|
||||
}
|
||||
if (! in_array($argv[4], ['true', 'false'], false)) {
|
||||
exit('Error: arg4 must be true or false'.$n);
|
||||
}
|
||||
if (! is_numeric($argv[5])) {
|
||||
exit('Error: arg5 must be a number'.$n);
|
||||
}
|
||||
if ($argv[5] < 0) {
|
||||
exit('Error: arg5 must be 0 or higher'.$n);
|
||||
}
|
||||
|
||||
$path = $argv[1];
|
||||
// Check if path ends with dir separator.
|
||||
if (! Str::endsWith($path, '/')) {
|
||||
$path .= '/';
|
||||
}
|
||||
|
||||
$files = new RegexIterator(
|
||||
new RecursiveIteratorIterator(
|
||||
new RecursiveDirectoryIterator($argv[1])
|
||||
),
|
||||
'/^.+\.nzb(\.gz)?$/i',
|
||||
RecursiveRegexIterator::GET_MATCH
|
||||
);
|
||||
|
||||
$i = 1;
|
||||
$nzbFiles = [];
|
||||
foreach ($files as $file) {
|
||||
$nzbFiles[] = $file[0];
|
||||
if ($i++ >= $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;
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<?php
|
||||
|
||||
use App\Models\User;
|
||||
use Jrean\UserVerification\Facades\UserVerification;
|
||||
|
||||
require_once dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
|
||||
if (isset($argv[1]) && is_numeric($argv[1])) {
|
||||
$user = User::find($argv[1]);
|
||||
UserVerification::generate($user);
|
||||
|
||||
UserVerification::send($user, 'User email verification required');
|
||||
|
||||
cli()->info('Email has been sent');
|
||||
} else {
|
||||
cli()->error('You need to provide user id as argument');
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="./bootstrap/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.2/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||
<testsuites>
|
||||
<testsuite name="Install">
|
||||
<directory suffix="Test.php">tests/Install</directory>
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="./bootstrap/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" backupGlobals="false" bootstrap="vendor/autoload.php" colors="true" processIsolation="false" stopOnFailure="false" xsi:noNamespaceSchemaLocation="https://schema.phpunit.de/10.0/phpunit.xsd" cacheDirectory=".phpunit.cache" backupStaticProperties="false">
|
||||
<coverage>
|
||||
<include>
|
||||
<directory suffix=".php">Blacklight</directory>
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Services\FanartTvService;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Tests for Fanart.tv API integration.
|
||||
*
|
||||
* These tests verify that the Fanart.tv API is properly configured and responding.
|
||||
*/
|
||||
class FanarttvApiTest extends TestCase
|
||||
{
|
||||
private FanartTvService $fanartService;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use aharen\OMDbAPI;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Tests for OMDb API integration.
|
||||
*
|
||||
* These tests verify that the OMDb API is properly configured and responding.
|
||||
*/
|
||||
class OmdbApiTest extends TestCase
|
||||
{
|
||||
private ?OMDbAPI $omdb = null;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
$apiKey = config('nntmux_api.omdb_api_key');
|
||||
if (! empty($apiKey)) {
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Services\TmdbClient;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Tests for TMDB API integration.
|
||||
*
|
||||
* These tests verify that the TMDB API is properly configured and responding.
|
||||
*/
|
||||
class TmdbApiTest extends TestCase
|
||||
{
|
||||
private TmdbClient $tmdbClient;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Services\TraktService;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Tests for Trakt.tv API integration.
|
||||
*
|
||||
* These tests verify that the Trakt.tv API is properly configured and responding.
|
||||
*/
|
||||
class TraktApiTest extends TestCase
|
||||
{
|
||||
private TraktService $traktService;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Services\TvProcessing\Providers\TvdbProvider;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Tests for TVDB API integration.
|
||||
*
|
||||
* These tests verify that the TVDB API is properly configured and responding.
|
||||
*/
|
||||
class TvdbApiTest extends TestCase
|
||||
{
|
||||
private ?TvdbProvider $tvdbProvider = null;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
|
||||
try {
|
||||
$this->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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Feature;
|
||||
|
||||
use App\Services\TvProcessing\Providers\TvMazeProvider;
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Tests for TVMaze API integration.
|
||||
*
|
||||
* These tests verify that the TVMaze API is properly responding.
|
||||
* Note: TVMaze API does not require an API key.
|
||||
*/
|
||||
class TvmazeApiTest extends TestCase
|
||||
{
|
||||
private TvMazeProvider $tvmazeProvider;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This file is part of NNTmux.
|
||||
*
|
||||
@@ -12,21 +15,20 @@
|
||||
* @version 0.0.1
|
||||
*/
|
||||
|
||||
namespace tests;
|
||||
namespace Tests\Install;
|
||||
|
||||
require_once \dirname(__DIR__, 2).DIRECTORY_SEPARATOR.'bootstrap/autoload.php';
|
||||
use Tests\TestCase;
|
||||
|
||||
/**
|
||||
* Class InstallTest.
|
||||
*/
|
||||
final class InstallTest extends \PHPUnit\Framework\TestCase
|
||||
final class InstallTest extends TestCase
|
||||
{
|
||||
public function test_full_install(): void
|
||||
{
|
||||
passthru('php '.base_path().'/artisan migrate:fresh --seed');
|
||||
$this->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');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace Tests\Unit;
|
||||
|
||||
use App\Services\YencService;
|
||||
use RuntimeException;
|
||||
use Tests\TestCase;
|
||||
|
||||
class YencServiceTest extends TestCase
|
||||
{
|
||||
private YencService $yencService;
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
parent::setUp();
|
||||
$this->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());
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user