mirror of
https://github.com/OPSnet/Gazelle.git
synced 2026-01-16 18:04:34 -05:00
file storage classes are object based
This commit is contained in:
@@ -133,9 +133,9 @@ RUN useradd -ms /bin/bash gazelle \
|
||||
| sed -r 's/pcntl_(fork|signal|signal_dispatch|waitpid),//g' \
|
||||
> /etc/php/${PHP_VER}/cli/conf.d/99-boris.ini \
|
||||
&& echo "Generate file storage directories..." \
|
||||
&& perl /var/www/bin/generate-storage-dirs /var/lib/gazelle/torrent 2 100 \
|
||||
&& perl /var/www/bin/generate-storage-dirs /var/lib/gazelle/riplog 2 100 \
|
||||
&& perl /var/www/bin/generate-storage-dirs /var/lib/gazelle/riploghtml 2 100 \
|
||||
&& perl /var/www/bin/generate-storage-dirs /var/lib/gazelle/torrent 2 100 \
|
||||
&& chown -R gazelle:gazelle /var/lib/gazelle /var/www
|
||||
|
||||
EXPOSE 80/tcp
|
||||
|
||||
41
app/File.php
41
app/File.php
@@ -2,46 +2,47 @@
|
||||
|
||||
namespace Gazelle;
|
||||
|
||||
abstract class File extends Base {
|
||||
/**
|
||||
* Note that currently, PHP does not allow an abstract class to define a method
|
||||
* signature as array|int and then be specialized in the child class as either
|
||||
* one or the other. So everything is defined as mixed and we will see if this
|
||||
* may be revisited in a future version of PHP.
|
||||
* It might also not be the best example of inheritance, but is simplifies much
|
||||
* of the implementation as it is.
|
||||
*/
|
||||
|
||||
abstract class File extends BaseObject {
|
||||
/**
|
||||
* Path to stored file
|
||||
*/
|
||||
abstract public function path(mixed $id): string;
|
||||
abstract public function path(): string;
|
||||
|
||||
/**
|
||||
* Does the file exist?
|
||||
*/
|
||||
public function exists(mixed $id): bool {
|
||||
return file_exists($this->path($id));
|
||||
public function exists(): bool {
|
||||
return file_exists($this->path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Store a file on disk at the specified path.
|
||||
* Store some data as a file on disk at the specified path.
|
||||
*/
|
||||
public function put(string $source, mixed $id): bool {
|
||||
return file_put_contents($this->path($id), $source) !== false;
|
||||
public function put(string $contents): bool {
|
||||
return file_put_contents($this->path(), $contents) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the contents of the stored file.
|
||||
*/
|
||||
public function get(mixed $id): string|false {
|
||||
return file_get_contents($this->path($id));
|
||||
public function get(): string|false {
|
||||
return file_get_contents($this->path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the size of the stored file. Note that the size
|
||||
* of a file that does not exist will be 0 (which may occur
|
||||
* if something bad happened). Use the exists() method to
|
||||
* distinguish between a true 0-byte file and missing file.
|
||||
*/
|
||||
public function size(): int {
|
||||
return (int)filesize($this->path());
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the stored file.
|
||||
*/
|
||||
public function remove(mixed $id): bool {
|
||||
return unlink($this->path($id));
|
||||
public function remove(): int {
|
||||
return (int)unlink($this->path());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,55 +2,74 @@
|
||||
|
||||
namespace Gazelle\File;
|
||||
|
||||
/* Note that there can be multiple rip logs per torrent, so there is one
|
||||
* torrent id and one or more log ids. In the usual course of operations,
|
||||
* an object is created with new File(<torrent-int>, <log-int>) which
|
||||
* points to one log (among possibly multiple) belonging to a torrent.
|
||||
*
|
||||
* A variant construction is allowed: new File(<int>, '*') which means
|
||||
* "all the log files". In this case, calling the remove() method removes
|
||||
* *all* the logs. You can of course remove just one log file if the log
|
||||
* id is specified in the constructor with new File(<int>, <int>).
|
||||
*/
|
||||
|
||||
class RipLog extends \Gazelle\File {
|
||||
/**
|
||||
* Move an existing rip log to the file storage location.
|
||||
* NOTE: This is a change in behaviour from the parent class,
|
||||
* which is expecting the file contents.
|
||||
*
|
||||
* $source Path to the file, usually the result of a POST operation.
|
||||
* $id The unique identifier [torrentId, logId] of the object
|
||||
*/
|
||||
public function put(string $source, mixed $id): bool {
|
||||
return false !== move_uploaded_file($source, $this->path($id));
|
||||
public function __construct(
|
||||
public readonly int $id,
|
||||
public readonly int|string $logId,
|
||||
) {}
|
||||
|
||||
public function flush(): static {
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove one or more rip logs of a torrent
|
||||
*
|
||||
* $id The unique identifier [torrentId, logId] of the object
|
||||
* If logId is null, all logs are taken into consideration
|
||||
*/
|
||||
public function remove(mixed $id): bool {
|
||||
[$torrentId, $logId] = $id;
|
||||
if (is_null($logId)) {
|
||||
$logfiles = glob($this->path([$torrentId, '*']));
|
||||
if ($logfiles === false) {
|
||||
return false;
|
||||
}
|
||||
foreach ($logfiles as $path) {
|
||||
if (preg_match('/(\d+)\.log/', $path, $match)) {
|
||||
$logId = $match[1];
|
||||
$this->remove([$torrentId, $logId]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
if ($this->exists($id)) {
|
||||
return unlink($this->path($id));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public function location(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
public function link(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Path of a rip log.
|
||||
*/
|
||||
public function path(mixed $id): string {
|
||||
[$torrentId, $logId] = $id;
|
||||
$key = strrev(sprintf('%04d', $torrentId));
|
||||
return sprintf("%s/%02d/%02d/{$torrentId}_{$logId}.log",
|
||||
public function path(): string {
|
||||
$key = strrev(sprintf('%04d', $this->id));
|
||||
return sprintf("%s/%02d/%02d/{$this->id}_{$this->logId}.log",
|
||||
STORAGE_PATH_RIPLOG, substr($key, 0, 2), substr($key, 2, 2)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Move an existing rip log to the file storage location.
|
||||
* NOTE: This is a change in behaviour from the parent class,
|
||||
* which is expecting the file contents.
|
||||
*/
|
||||
public function put(string $source): bool {
|
||||
return move_uploaded_file($source, $this->path()) !== false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove one or more rip logs of a torrent
|
||||
*/
|
||||
public function remove(): int {
|
||||
if ($this->exists()) {
|
||||
return (int)unlink($this->path());
|
||||
} elseif ($this->logId === '*') {
|
||||
$fileList = glob($this->path());
|
||||
if ($fileList === false) {
|
||||
return 0;
|
||||
}
|
||||
foreach ($fileList as $path) {
|
||||
if (preg_match('/(\d+)\.log/', $path, $match)) {
|
||||
if (!new self($this->id, (int)$match[1])->remove()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,44 +2,56 @@
|
||||
|
||||
namespace Gazelle\File;
|
||||
|
||||
// see the comment in File\RipLog
|
||||
|
||||
class RipLogHTML extends \Gazelle\File {
|
||||
/**
|
||||
* Remove one or more HTML-ized rip logs of a torrent
|
||||
*
|
||||
* @param mixed $id The unique identifier [torrentId, logId] of the object
|
||||
* If logId is null, all logs are taken into consideration
|
||||
*/
|
||||
public function remove(mixed $id): bool {
|
||||
[$torrentId, $logId] = $id;
|
||||
if (is_null($logId)) {
|
||||
$htmlfiles = glob($this->path([$torrentId, '*']));
|
||||
if ($htmlfiles === false) {
|
||||
return false;
|
||||
}
|
||||
foreach ($htmlfiles as $path) {
|
||||
if (preg_match('/(\d+)\.log/', $path, $match)) {
|
||||
$logId = $match[1];
|
||||
$this->remove([$torrentId, $logId]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
} else {
|
||||
$path = $this->path($id);
|
||||
if (file_exists($path)) {
|
||||
return unlink($path);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
public function __construct(
|
||||
public readonly int $id,
|
||||
public readonly int|string $logId,
|
||||
) {}
|
||||
|
||||
public function flush(): static {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function location(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
public function link(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Path of a HTML-ized rip log.
|
||||
*/
|
||||
public function path(mixed $id): string {
|
||||
[$torrentId, $logId] = $id;
|
||||
$key = strrev(sprintf('%04d', $torrentId));
|
||||
return sprintf("%s/%02d/%02d/{$torrentId}_{$logId}.html",
|
||||
public function path(): string {
|
||||
$key = strrev(sprintf('%04d', $this->id));
|
||||
return sprintf("%s/%02d/%02d/{$this->id}_{$this->logId}.html",
|
||||
STORAGE_PATH_RIPLOGHTML, substr($key, 0, 2), substr($key, 2, 2)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove one or more HTML-ized rip logs of a torrent
|
||||
*/
|
||||
public function remove(): int {
|
||||
if ($this->exists()) {
|
||||
return (int)unlink($this->path());
|
||||
} elseif ($this->logId === '*') {
|
||||
$fileList = glob($this->path());
|
||||
if ($fileList === false) {
|
||||
return 0;
|
||||
}
|
||||
foreach ($fileList as $path) {
|
||||
if (preg_match('/(\d+)\.html/', $path, $match)) {
|
||||
if (!new self($this->id, (int)$match[1])->remove()) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,13 +3,29 @@
|
||||
namespace Gazelle\File;
|
||||
|
||||
class Torrent extends \Gazelle\File {
|
||||
public function __construct(
|
||||
public readonly int $id,
|
||||
) {}
|
||||
|
||||
public function flush(): static {
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function location(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
public function link(): string {
|
||||
return "";
|
||||
}
|
||||
|
||||
/**
|
||||
* Path of a torrent file
|
||||
*/
|
||||
public function path(mixed $id): string {
|
||||
$key = strrev(sprintf('%04d', $id));
|
||||
public function path(): string {
|
||||
$key = strrev(sprintf('%04d', $this->id));
|
||||
return sprintf('%s/%02d/%02d/%d.torrent',
|
||||
STORAGE_PATH_TORRENT, substr($key, 0, 2), substr($key, 2, 2), $id
|
||||
STORAGE_PATH_TORRENT, substr($key, 0, 2), substr($key, 2, 2), $this->id
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,8 +9,8 @@ class RipLog extends \Gazelle\Json {
|
||||
) {}
|
||||
|
||||
public function payload(): array {
|
||||
$filer = new \Gazelle\File\RipLog();
|
||||
if (!$filer->exists([$this->torrentId, $this->logId])) {
|
||||
$ripLog = new \Gazelle\File\RipLog($this->torrentId, $this->logId);
|
||||
if (!$ripLog->exists()) {
|
||||
return [
|
||||
'id' => $this->torrentId,
|
||||
'logid' => $this->logId,
|
||||
@@ -32,7 +32,7 @@ class RipLog extends \Gazelle\Json {
|
||||
];
|
||||
}
|
||||
|
||||
$logFile = $filer->get([$this->torrentId, $this->logId]);
|
||||
$logFile = $ripLog->get();
|
||||
$ripLog = new \Gazelle\RipLog($this->torrentId, $this->logId);
|
||||
return [
|
||||
'id' => $this->torrentId,
|
||||
|
||||
@@ -2,28 +2,29 @@
|
||||
|
||||
namespace Gazelle\Manager;
|
||||
|
||||
class TorrentLog extends \Gazelle\Base {
|
||||
public function __construct(
|
||||
protected \Gazelle\File\RipLog $ripFiler,
|
||||
protected \Gazelle\File\RipLogHTML $htmlFiler,
|
||||
) {}
|
||||
use Gazelle\Logfile as Logfile;
|
||||
use Gazelle\File\RipLog as RipLog;
|
||||
use Gazelle\File\RipLogHTML as RipLogHTML;
|
||||
use Gazelle\Torrent as Torrent;
|
||||
|
||||
public function create(\Gazelle\Torrent $torrent, \Gazelle\Logfile $logfile, string $checkerVersion): \Gazelle\TorrentLog {
|
||||
class TorrentLog extends \Gazelle\Base {
|
||||
public function create(Torrent $torrent, Logfile $logfile, string $checkerVersion): \Gazelle\TorrentLog {
|
||||
self::$db->prepared_query('
|
||||
INSERT INTO torrents_logs
|
||||
(TorrentID, Score, `Checksum`, FileName, Ripper, RipperVersion, `Language`, ChecksumState, Details, LogcheckerVersion)
|
||||
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
|
||||
', $torrent->id, $logfile->score(), $logfile->checksumStatus(), $logfile->filename(),
|
||||
$logfile->ripper(), $logfile->ripperVersion(), $logfile->language(), $logfile->checksumState(), $logfile->detailsAsString(),
|
||||
$checkerVersion
|
||||
', $torrent->id, $logfile->score(), $logfile->checksumStatus(),
|
||||
$logfile->filename(), $logfile->ripper(), $logfile->ripperVersion(),
|
||||
$logfile->language(), $logfile->checksumState(),
|
||||
$logfile->detailsAsString(), $checkerVersion
|
||||
);
|
||||
$logId = self::$db->inserted_id();
|
||||
$this->ripFiler->put($logfile->filepath(), [$torrent->id, $logId]);
|
||||
$this->htmlFiler->put($logfile->text(), [$torrent->id, $logId]);
|
||||
new RipLog($torrent->id, $logId)->put($logfile->filepath());
|
||||
new RipLogHTML($torrent->id, $logId)->put($logfile->text());
|
||||
return $this->findById($torrent, $logId);
|
||||
}
|
||||
|
||||
public function findById(\Gazelle\Torrent $torrent, int $id): ?\Gazelle\TorrentLog {
|
||||
public function findById(Torrent $torrent, int $id): ?\Gazelle\TorrentLog {
|
||||
$logId = (int)self::$db->scalar("
|
||||
SELECT LogID FROM torrents_logs WHERE TorrentID = ? AND LogID = ?
|
||||
", $torrent->id, $id
|
||||
|
||||
@@ -97,8 +97,7 @@ class Torrent extends TorrentAbstract {
|
||||
* Convert a stored torrent into a binary file that can be loaded in a torrent client
|
||||
*/
|
||||
public function torrentBody(string $announceUrl): string {
|
||||
$filer = new File\Torrent();
|
||||
$contents = $filer->get($this->id);
|
||||
$contents = new File\Torrent($this->id)->get();
|
||||
if ($contents == false) {
|
||||
return '';
|
||||
}
|
||||
@@ -209,11 +208,7 @@ class Torrent extends TorrentAbstract {
|
||||
*
|
||||
* @return int number of logfiles removed
|
||||
*/
|
||||
public function removeAllLogs(
|
||||
User $user,
|
||||
File\RipLog $ripLog,
|
||||
File\RipLogHTML $ripLogHtml,
|
||||
): int {
|
||||
public function removeAllLogs(User $user): int {
|
||||
self::$db->begin_transaction();
|
||||
self::$db->prepared_query("
|
||||
DELETE FROM torrents_logs WHERE TorrentID = ?
|
||||
@@ -232,9 +227,8 @@ class Torrent extends TorrentAbstract {
|
||||
$this->logger()->torrent($this, $user, "All logs removed from torrent");
|
||||
self::$db->commit();
|
||||
$this->flush();
|
||||
|
||||
$ripLog->remove([$this->id, null]);
|
||||
$ripLogHtml->remove([$this->id, null]);
|
||||
new File\RipLog($this->id, '*')->remove();
|
||||
new File\RipLogHTML($this->id, '*')->remove();
|
||||
|
||||
return $affected;
|
||||
}
|
||||
@@ -457,8 +451,8 @@ class Torrent extends TorrentAbstract {
|
||||
*
|
||||
* @return int number of files regenned
|
||||
*/
|
||||
public function regenerateFilelist(File\Torrent $filer, \OrpheusNET\BencodeTorrent\BencodeTorrent $encoder): int {
|
||||
$torrentFile = $filer->get($this->id);
|
||||
public function regenerateFilelist(\OrpheusNET\BencodeTorrent\BencodeTorrent $encoder): int {
|
||||
$torrentFile = new File\Torrent($this->id)->get();
|
||||
if ($torrentFile === false) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Gazelle\Torrent;
|
||||
|
||||
use Gazelle\File\RipLogHTML as RipLogHTML;
|
||||
|
||||
class Log extends \Gazelle\Base {
|
||||
public function __construct(
|
||||
public readonly int $id,
|
||||
@@ -37,7 +39,6 @@ class Log extends \Gazelle\Base {
|
||||
);
|
||||
$logs = self::$db->to_array('LogID', MYSQLI_ASSOC);
|
||||
$details = [];
|
||||
$htmlFiler = new \Gazelle\File\RipLogHTML();
|
||||
foreach ($logs as $log) {
|
||||
$details[$log['LogID']] = [
|
||||
'adjustment' => !$log['is_adjusted']
|
||||
@@ -48,7 +49,7 @@ class Log extends \Gazelle\Base {
|
||||
'adjusted' => $log['AdjustedScore'],
|
||||
'reason' => empty($log['AdjustmentReason']) ? 'none supplied' : $log['AdjustmentReason'],
|
||||
],
|
||||
'log' => $htmlFiler->get([$this->id, $log['LogID']]),
|
||||
'log' => new RipLogHTML($this->id, $log['LogID'])->get(),
|
||||
'status' => array_merge(explode("\n", $log['Details']), unserialize($log['AdjustmentDetails'])),
|
||||
];
|
||||
if (($log['Adjusted'] === '0' && $log['Checksum'] === '0') || ($log['Adjusted'] === '1' && $log['AdjustedChecksum'] === '0')) {
|
||||
|
||||
@@ -5,6 +5,8 @@ namespace Gazelle;
|
||||
use Gazelle\Enum\LeechReason;
|
||||
use Gazelle\Enum\LeechType;
|
||||
use Gazelle\Enum\TorrentFlag;
|
||||
use Gazelle\File\RipLog as RipLog;
|
||||
use Gazelle\File\RipLogHTML as RipLogHTML;
|
||||
|
||||
abstract class TorrentAbstract extends BaseAttrObject {
|
||||
final public const CACHE_LOCK = 'torrent_lock_%d';
|
||||
@@ -481,7 +483,7 @@ abstract class TorrentAbstract extends BaseAttrObject {
|
||||
return $this->info()['LogScore'];
|
||||
}
|
||||
|
||||
public function logfileList(File\RipLog $ripFiler, File\RipLogHTML $htmlFiler): array {
|
||||
public function logfileList(): array {
|
||||
self::$db->prepared_query("
|
||||
SELECT LogID AS id,
|
||||
Score,
|
||||
@@ -499,13 +501,13 @@ abstract class TorrentAbstract extends BaseAttrObject {
|
||||
);
|
||||
$list = self::$db->to_array(false, MYSQLI_ASSOC);
|
||||
foreach ($list as &$log) {
|
||||
$log['has_riplog'] = $ripFiler->exists([$this->id, $log['id']]);
|
||||
$log['html_log'] = $htmlFiler->get([$this->id, $log['id']]);
|
||||
$log['has_riplog'] = new RipLog($this->id, $log['id'])->exists();
|
||||
$log['html_log'] = new RipLogHTML($this->id, $log['id'])->get();
|
||||
$log['adjustment_details'] = unserialize($log['AdjustmentDetails']);
|
||||
$log['adjusted'] = ($log['Adjusted'] === '1');
|
||||
$log['adjusted_checksum'] = ($log['AdjustedChecksum'] === '1');
|
||||
$log['checksum'] = ($log['Checksum'] === '1');
|
||||
$log['details'] = empty($log['Details']) ? [] : explode("\r\n", trim($log['Details']));
|
||||
$log['adjusted'] = ($log['Adjusted'] === '1');
|
||||
$log['adjusted_checksum'] = ($log['AdjustedChecksum'] === '1');
|
||||
$log['checksum'] = ($log['Checksum'] === '1');
|
||||
$log['details'] = explode("\r\n", trim($log['Details'] ?? ''));
|
||||
if ($log['adjusted'] && $log['checksum'] !== $log['adjusted_checksum']) {
|
||||
$log['details'][] = 'Bad/No Checksum(s)';
|
||||
}
|
||||
|
||||
@@ -22,9 +22,7 @@ $errLog = 0;
|
||||
$newHtml = 0;
|
||||
$errHtml = 0;
|
||||
|
||||
$db = Gazelle\DB::DB();
|
||||
$logFiler = new Gazelle\File\RipLog();
|
||||
$htmlFiler = new Gazelle\File\RipLogHTML();
|
||||
$db = Gazelle\DB::DB();
|
||||
|
||||
while (true) {
|
||||
$db->prepared_query('
|
||||
@@ -49,10 +47,10 @@ while (true) {
|
||||
++$newLog;
|
||||
}
|
||||
if (!file_exists($htmlFiler->path([$torrentId, $logId]))) {
|
||||
if (!$htmlFiler->put($log, [$torrentId, $logId])) {
|
||||
if (!new RipLog($torrentId, $logId)->put($log)) {
|
||||
++$errHtml;
|
||||
}
|
||||
$htmlFiler->put($log . "\n", [$torrentId, $logId]);
|
||||
new RipLogHTML($torrentId, $logId)->put("$log\n");
|
||||
++$newHtml;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,6 @@ require_once __DIR__ . '/../lib/bootstrap.php';
|
||||
$allConfig = [
|
||||
'-html' => [
|
||||
'CHECK' => 'SELECT Log FROM torrents_logs WHERE TorrentID = ? AND LogID = ?',
|
||||
'FILER' => new Gazelle\File\RipLogHTML(),
|
||||
'HASH' => 'SELECT Log AS digest FROM torrents_logs WHERE TorrentID = ? AND LogID = ?',
|
||||
'PIPE' => '/usr/bin/find ' . STORAGE_PATH_RIPLOGHTML . ' -type f',
|
||||
'MATCH' => '~/(\d+)_(\d+)\.html$~',
|
||||
@@ -29,7 +28,6 @@ $allConfig = [
|
||||
],
|
||||
'-log' => [
|
||||
'CHECK' => 'SELECT 1 FROM torrents_logs WHERE TorrentID = ? AND LogID = ?',
|
||||
'FILER' => new Gazelle\File\RipLog(),
|
||||
'HASH' => null,
|
||||
'PIPE' => '/usr/bin/find ' . STORAGE_PATH_RIPLOG . ' -type f',
|
||||
'MATCH' => '~/(\d+)_(\d+)\.log$~',
|
||||
@@ -37,7 +35,6 @@ $allConfig = [
|
||||
],
|
||||
'-torrent' => [
|
||||
'CHECK' => 'SELECT 1 FROM torrents WHERE ID = ?',
|
||||
'FILER' => new Gazelle\File\Torrent(),
|
||||
'HASH' => 'SELECT File AS digest FROM torrents_files WHERE TorrentID = ?',
|
||||
'PIPE' => '/usr/bin/find ' . STORAGE_PATH_TORRENT . ' -type f',
|
||||
'MATCH' => '~/(\d+)\.torrent$~',
|
||||
|
||||
@@ -4,7 +4,6 @@ require_once __DIR__ . '/../lib/bootstrap.php';
|
||||
$Cache->disableLocalCache();
|
||||
|
||||
$torMan = new Gazelle\Manager\Torrent();
|
||||
$filer = new Gazelle\File\Torrent();
|
||||
$encoder = new OrpheusNET\BencodeTorrent\BencodeTorrent();
|
||||
$db = Gazelle\DB::DB();
|
||||
$max = $db->scalar("SELECT max(ID) FROM torrents");
|
||||
@@ -22,7 +21,7 @@ while ($id < $max) {
|
||||
$list = $db->collect(0);
|
||||
foreach ($list as $id) {
|
||||
try {
|
||||
$torMan->findById($id)->regenerateFilelist($filer, $encoder);
|
||||
$torMan->findById($id)->regenerateFilelist($encoder);
|
||||
} catch (RuntimeException $e) {
|
||||
echo "$id: fail: " . $e->getMessage() . "\n";
|
||||
}
|
||||
|
||||
@@ -65,9 +65,10 @@ defined('TMPDIR') or define('TMPDIR', '/tmp');
|
||||
|
||||
// Paths for storing uploaded assets outside the database. See bin/generate-storage-dirs
|
||||
// Should also be moved out of the root partition.
|
||||
defined('STORAGE_PATH_TORRENT') or define('STORAGE_PATH_TORRENT', '/var/lib/gazelle/torrent');
|
||||
defined('STORAGE_PATH_GENERAL') or define('STORAGE_PATH_GENERAL', '/var/lib/gazelle/general');
|
||||
defined('STORAGE_PATH_RIPLOG') or define('STORAGE_PATH_RIPLOG', '/var/lib/gazelle/riplog');
|
||||
defined('STORAGE_PATH_RIPLOGHTML') or define('STORAGE_PATH_RIPLOGHTML', '/var/lib/gazelle/riploghtml');
|
||||
defined('STORAGE_PATH_TORRENT') or define('STORAGE_PATH_TORRENT', '/var/lib/gazelle/torrent');
|
||||
|
||||
// Host static assets (images, css, js) on another server.
|
||||
// In development it is just a folder
|
||||
@@ -134,16 +135,20 @@ defined('AUTHKEY') or define('AUTHKEY', 'changeme');
|
||||
// Extra salt added into RSS authentication
|
||||
defined('RSS_HASH') or define('RSS_HASH', 'changeme');
|
||||
|
||||
// Seedbox ids are hashified with this salt.
|
||||
defined('SEEDBOX_SALT') or define('SEEDBOX_SALT', 'changeme');
|
||||
|
||||
// User avatars are hashed with this salt.
|
||||
defined('AVATAR_SALT') or define('AVATAR_SALT', 'changeme');
|
||||
|
||||
// General storage files are hashed with this salt
|
||||
// Changing this after site launch will expire all short-term links
|
||||
defined('FILE_SALT') or define('FILE_SALT', 'changeme');
|
||||
|
||||
// Salt for folder clashes. Changing this after site launch will
|
||||
// invalidate cache keys that will be regenerated on next call.
|
||||
defined('FOLDER_CLASH_SALT') or define('FOLDER_CLASH_SALT', 'changeme');
|
||||
|
||||
// Seedbox ids are hashified with this salt.
|
||||
defined('SEEDBOX_SALT') or define('SEEDBOX_SALT', 'changeme');
|
||||
|
||||
// Salt for custom Top 10 lists. Changing this after site launch will
|
||||
// invalidate cache keys that will be regenerated on next call.
|
||||
defined('TOP10_SALT') or define('TOP10_SALT', 'changeme');
|
||||
|
||||
@@ -103,9 +103,10 @@ fi
|
||||
|
||||
if [ ! -d /var/lib/gazelle/torrent ]; then
|
||||
echo "Generate file storage directories..."
|
||||
perl "${CI_PROJECT_DIR}/bin/generate-storage-dirs" /var/lib/gazelle/torrent 2 100
|
||||
perl "${CI_PROJECT_DIR}/bin/generate-storage-dirs" /var/lib/gazelle/general 1 100
|
||||
perl "${CI_PROJECT_DIR}/bin/generate-storage-dirs" /var/lib/gazelle/riplog 2 100
|
||||
perl "${CI_PROJECT_DIR}/bin/generate-storage-dirs" /var/lib/gazelle/riploghtml 2 100
|
||||
perl "${CI_PROJECT_DIR}/bin/generate-storage-dirs" /var/lib/gazelle/torrent 2 100
|
||||
chown -R gazelle /var/lib/gazelle
|
||||
fi
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ $torrent = new Manager\Torrent()->findById((int)($_GET['id'] ?? 0));
|
||||
if (is_null($torrent)) {
|
||||
json_error('bad parameters');
|
||||
}
|
||||
if ($torrent->uploaderId() != $Viewer->id() && !$Viewer->permitted('admin_add_log')) {
|
||||
if ($torrent->uploaderId() != $Viewer->id && !$Viewer->permitted('admin_add_log')) {
|
||||
json_error('Not your upload.');
|
||||
}
|
||||
if (empty($_FILES) || empty($_FILES['logfiles'])) {
|
||||
@@ -19,7 +19,7 @@ if (empty($_FILES) || empty($_FILES['logfiles'])) {
|
||||
echo new Json\AddLog(
|
||||
$torrent,
|
||||
$Viewer,
|
||||
new Manager\TorrentLog(new File\RipLog(), new File\RipLogHTML()),
|
||||
new Manager\TorrentLog(),
|
||||
new LogfileSummary($_FILES['logfiles']),
|
||||
)
|
||||
->setVersion(1)
|
||||
|
||||
@@ -17,7 +17,7 @@ if (is_null($torrent)) {
|
||||
if ($torrent->media() !== 'CD') {
|
||||
Error400::error('Media of torrent precludes adding a log.');
|
||||
}
|
||||
if ($torrent->uploaderId() != $Viewer->id() && !$Viewer->permitted('admin_add_log')) {
|
||||
if ($torrent->uploaderId() != $Viewer->id && !$Viewer->permitted('admin_add_log')) {
|
||||
Error403::error('Not your upload.');
|
||||
}
|
||||
|
||||
@@ -27,13 +27,10 @@ $logfileSummary = new LogfileSummary($_FILES['logfiles']);
|
||||
if (!$logfileSummary->total()) {
|
||||
Error400::error("No logfiles uploaded.");
|
||||
} else {
|
||||
$ripFiler = new File\RipLog();
|
||||
$htmlFiler = new File\RipLogHTML();
|
||||
|
||||
$torrent->removeLogDb();
|
||||
$ripFiler->remove([$torrent->id(), null]);
|
||||
$htmlFiler->remove([$torrent->id(), null]);
|
||||
$torrentLogManager = new Manager\TorrentLog($ripFiler, $htmlFiler);
|
||||
new File\RipLog($torrent->id, '*')->remove();
|
||||
new File\RipLogHTML($torrent->id, '*')->remove();
|
||||
$torrentLogManager = new Manager\TorrentLog();
|
||||
|
||||
$checkerVersion = Logchecker::getLogcheckerVersion();
|
||||
foreach ($logfileSummary->all() as $logfile) {
|
||||
|
||||
@@ -29,8 +29,6 @@ $requestMan = new Manager\Request();
|
||||
$userMan = new Manager\User();
|
||||
$search = new Search\Torrent\Report($_GET['view'] ?? '', $_GET['id'] ?? '', $reportTypeMan, $userMan);
|
||||
$imgProxy = new Util\ImageProxy($Viewer);
|
||||
$ripFiler = new File\RipLog();
|
||||
$htmlFiler = new File\RipLogHTML();
|
||||
|
||||
$paginator = new Util\Paginator(REPORTS_PER_PAGE, (int)($_GET['page'] ?? 1));
|
||||
$paginator->setTotal($search->total());
|
||||
@@ -173,34 +171,36 @@ if ($search->canUnclaim($Viewer)) {
|
||||
<?php
|
||||
} else {
|
||||
foreach ($details as $logId => $info) {
|
||||
if ($info['adjustment']) {
|
||||
$adj = $info['adjustment'];
|
||||
$adjUser = $userMan->findById($adj['userId']);
|
||||
?>
|
||||
if ($info['adjustment']) {
|
||||
$adj = $info['adjustment'];
|
||||
$adjUser = $userMan->findById($adj['userId']);
|
||||
?>
|
||||
<li>Log adjusted <?= $adjUser ? "by {$adjUser->link()}" : '' ?> from score <?= $adj['score']
|
||||
?> to <?= $adj['adjusted'] . ($adj['reason'] ? ', reason: ' . $adj['reason'] : '') ?></li>
|
||||
<?php
|
||||
}
|
||||
if (isset($info['status']['tracks'])) {
|
||||
$info['status']['tracks'] = implode(', ', array_keys($info['status']['tracks']));
|
||||
}
|
||||
foreach ($info['status'] as $s) {
|
||||
if ($s) {
|
||||
?>
|
||||
?> to <?= $adj['adjusted'] . ($adj['reason'] ? ', reason: ' . $adj['reason'] : '') ?></li>
|
||||
<?php
|
||||
}
|
||||
if (isset($info['status']['tracks'])) {
|
||||
$info['status']['tracks'] = implode(', ', array_keys($info['status']['tracks']));
|
||||
}
|
||||
foreach ($info['status'] as $s) {
|
||||
if ($s) {
|
||||
?>
|
||||
<li><?= $s ?></li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
<li>
|
||||
<span class="nobr"><strong>Logfile #<?= $logId ?></strong>: </span>
|
||||
<a href="javascript:void(0);" onclick="BBCode.spoiler(this);" class="brackets">Show</a><pre class="hidden"><?= $ripFiler->get([ $torrentId , $logId]) ?></pre>
|
||||
<a href="javascript:void(0);" onclick="BBCode.spoiler(this);" class="brackets">Show</a><pre class="hidden"><?=
|
||||
new File\RipLog($torrentId, $logId)->get() ?></pre>
|
||||
</li>
|
||||
<li>
|
||||
<span class="nobr"><strong>HTML logfile #<?= $logId ?></strong>: </span>
|
||||
<a href="javascript:void(0);" onclick="BBCode.spoiler(this);" class="brackets">Show</a><pre class="hidden"><?= $info['log'] ?></pre>
|
||||
<a href="javascript:void(0);" onclick="BBCode.spoiler(this);" class="brackets">Show</a><pre class="hidden"><?=
|
||||
$info['log'] ?></pre>
|
||||
</li>
|
||||
<?php
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
@@ -210,37 +210,39 @@ if ($search->canUnclaim($Viewer)) {
|
||||
<?php
|
||||
$log = new Torrent\Log($extra->id);
|
||||
$details = $log->logDetails();
|
||||
?>
|
||||
?>
|
||||
<ul class="nobullet logdetails">
|
||||
<?php if (!count($details)) { ?>
|
||||
<?php if (!count($details)) { ?>
|
||||
<li class="nobr">No logs</li>
|
||||
<?php
|
||||
<?php
|
||||
} else {
|
||||
foreach ($details as $logId => $info) {
|
||||
if ($info['adjustment']) {
|
||||
$adj = $info['adjustment'];
|
||||
$adjUser = $userMan->findById($adj['userId']);
|
||||
?>
|
||||
if ($info['adjustment']) {
|
||||
$adj = $info['adjustment'];
|
||||
$adjUser = $userMan->findById($adj['userId']);
|
||||
?>
|
||||
<li>Log adjusted <?= $adjUser ? "by {$adjUser->link()}" : '' ?> from score <?= $adj['score']
|
||||
?> to <?= $adj['adjusted'] . ($adj['reason'] ? ', reason: ' . $adj['reason'] : '') ?></li>
|
||||
<?php
|
||||
}
|
||||
if (isset($info['status']['tracks'])) {
|
||||
$info['status']['tracks'] = implode(', ', array_keys($info['status']['tracks']));
|
||||
}
|
||||
foreach ($info['status'] as $s) {
|
||||
?>
|
||||
?> to <?= $adj['adjusted'] . ($adj['reason'] ? ', reason: ' . $adj['reason'] : '') ?></li>
|
||||
<?php
|
||||
}
|
||||
if (isset($info['status']['tracks'])) {
|
||||
$info['status']['tracks'] = implode(', ', array_keys($info['status']['tracks']));
|
||||
}
|
||||
foreach ($info['status'] as $s) {
|
||||
?>
|
||||
<li><?= $s ?></li>
|
||||
<?php } ?>
|
||||
<?php } ?>
|
||||
<li>
|
||||
<span class="nobr"><strong>Raw logfile #<?= $logId ?></strong>: </span>
|
||||
<a href="javascript:void(0);" onclick="BBCode.spoiler(this);" class="brackets">Show</a><pre class="hidden"><?= $ripFiler->get([$extra->id, $logId]) ?></pre>
|
||||
<a href="javascript:void(0);" onclick="BBCode.spoiler(this);" class="brackets">Show</a><pre class="hidden"><?=
|
||||
new File\RipLog($extra->id, $logId)->get() ?></pre>
|
||||
</li>
|
||||
<li>
|
||||
<span class="nobr"><strong>HTML logfile #<?= $logId ?></strong>: </span>
|
||||
<a href="javascript:void(0);" onclick="BBCode.spoiler(this);" class="brackets">Show</a><pre class="hidden"><?= $info['log'] ?></pre>
|
||||
<a href="javascript:void(0);" onclick="BBCode.spoiler(this);" class="brackets">Show</a><pre class="hidden"><?=
|
||||
$info['log'] ?></pre>
|
||||
</li>
|
||||
<?php
|
||||
<?php
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
||||
@@ -209,7 +209,7 @@ $db->begin_transaction(); // It's all or nothing
|
||||
if (isset($_FILES['logfiles'])) {
|
||||
$logfileSummary = new LogfileSummary($_FILES['logfiles']);
|
||||
if ($logfileSummary->total()) {
|
||||
$torrentLogManager = new Manager\TorrentLog(new File\RipLog(), new File\RipLogHTML());
|
||||
$torrentLogManager = new Manager\TorrentLog();
|
||||
$checkerVersion = Logchecker::getLogcheckerVersion();
|
||||
foreach ($logfileSummary->all() as $logfile) {
|
||||
$torrentLogManager->create($torrent, $logfile, $checkerVersion);
|
||||
|
||||
@@ -14,13 +14,14 @@ $torrent = new Manager\Torrent()->findById((int)($_GET['torrentid'] ?? 0));
|
||||
if (is_null($torrent)) {
|
||||
Error404::error();
|
||||
}
|
||||
$tlog = new Manager\TorrentLog(new File\RipLog(), new File\RipLogHTML())->findById($torrent, (int)($_GET['logid'] ?? 0));
|
||||
$tlog = new Manager\TorrentLog()->findById($torrent, (int)($_GET['logid'] ?? 0));
|
||||
if (is_null($tlog)) {
|
||||
Error404::error();
|
||||
}
|
||||
|
||||
echo $Twig->render('torrent/edit-log.twig', [
|
||||
'adjuster' => new Manager\User()->findById($tlog->adjustedByUserId())?->link() ?? 'System',
|
||||
'adjuster' => new Manager\User()
|
||||
->findById($tlog->adjustedByUserId())?->link() ?? 'System',
|
||||
'tlog' => $tlog,
|
||||
'torrent' => $torrent,
|
||||
|
||||
|
||||
@@ -16,8 +16,8 @@ if (is_null($torrent)) {
|
||||
}
|
||||
|
||||
echo $Twig->render('torrent/riplog.twig', [
|
||||
'id' => $torrent->id(),
|
||||
'list' => $torrent->logfileList(new File\RipLog(), new File\RipLogHTML()),
|
||||
'id' => $torrent->id,
|
||||
'list' => $torrent->logfileList(),
|
||||
'log_score' => $torrent->logScore(),
|
||||
'viewer' => $Viewer,
|
||||
]);
|
||||
|
||||
@@ -14,8 +14,7 @@ if (is_null($torrent)) {
|
||||
Error404::error();
|
||||
}
|
||||
$torrent->regenerateFilelist(
|
||||
new File\Torrent(),
|
||||
new \OrpheusNET\BencodeTorrent\BencodeTorrent()
|
||||
new \OrpheusNET\BencodeTorrent\BencodeTorrent(),
|
||||
);
|
||||
|
||||
header("Location: " . $torrent->location());
|
||||
|
||||
@@ -16,11 +16,11 @@ if (is_null($torrent) || !$logId) {
|
||||
Error404::error();
|
||||
}
|
||||
|
||||
new File\RipLog()->remove([$torrent->id(), $logId]);
|
||||
new File\RipLog($torrent->id, $logId)->remove();
|
||||
$torrent->logger()->torrent(
|
||||
$torrent,
|
||||
$Viewer,
|
||||
"Riplog ID $logId removed from torrent {$torrent->id()}",
|
||||
"Riplog ID $logId removed from torrent {$torrent->id}",
|
||||
);
|
||||
$torrent->clearLog($logId);
|
||||
|
||||
|
||||
@@ -7,7 +7,9 @@ namespace Gazelle;
|
||||
|
||||
authorize();
|
||||
if (!$Viewer->permitted('torrents_delete')) {
|
||||
Error403::error();
|
||||
Error403::error(
|
||||
'You are not allowed to delete torrents. Please report the torrent instead.'
|
||||
);
|
||||
}
|
||||
|
||||
$torrent = new Manager\Torrent()->findById((int)($_GET['torrentid'] ?? 0));
|
||||
@@ -15,9 +17,5 @@ if (is_null($torrent)) {
|
||||
Error404::error();
|
||||
}
|
||||
|
||||
$torrent->removeAllLogs(
|
||||
$Viewer,
|
||||
new File\RipLog(),
|
||||
new File\RipLogHTML(),
|
||||
);
|
||||
$torrent->removeAllLogs($Viewer);
|
||||
header('Location: ' . $torrent->location());
|
||||
|
||||
@@ -17,9 +17,9 @@ if (is_null($torrent) || !$logId) {
|
||||
Error404::error();
|
||||
}
|
||||
|
||||
$logpath = new File\RipLog()->path([$torrent->id(), $logId]);
|
||||
$logpath = new File\RipLog($torrent->id, $logId)->path();
|
||||
$logfile = new Logfile($logpath, basename($logpath));
|
||||
new File\RipLogHTML()->put($logfile->text(), [$torrent->id(), $logId]);
|
||||
new File\RipLogHTML($torrent->id, $logId)->put($logfile->text());
|
||||
|
||||
$torrent->rescoreLog($logId, $logfile, Logchecker::getLogcheckerVersion());
|
||||
|
||||
|
||||
@@ -309,14 +309,14 @@ $upload = [
|
||||
'new' => [], // list of newly created Torrent objects
|
||||
];
|
||||
|
||||
$torrentFiler = new File\Torrent();
|
||||
$torrent = $torMan->findByInfohash(bin2hex($bencoder->getHexInfoHash()));
|
||||
$torrent = $torMan->findByInfohash(bin2hex($bencoder->getHexInfoHash()));
|
||||
if ($torrent) {
|
||||
if ($torrentFiler->exists($torrent->id)) {
|
||||
$torrentFile = new File\Torrent($torrent->id);
|
||||
if ($torrentFile->exists()) {
|
||||
reportError("The exact same torrent file already exists on the site! {$torrent->link()}");
|
||||
} else {
|
||||
// A lost torrent
|
||||
$torrentFiler->put($bencoder->getEncode(), $torrent->id);
|
||||
$torrentFile->put($bencoder->getEncode());
|
||||
reportError("Thank you for fixing this torrent {$torrent->link()}");
|
||||
}
|
||||
}
|
||||
@@ -364,11 +364,12 @@ if ($isMusicUpload) {
|
||||
|
||||
$torrent = $torMan->findByInfohash(bin2hex($xbencoder->getHexInfoHash()));
|
||||
if ($torrent) {
|
||||
if ($torrentFiler->exists($torrent->id)) {
|
||||
$torrentFile = new File\Torrent($torrent->id);
|
||||
if ($torrentFile->exists()) {
|
||||
reportError("The exact same torrent file already exists on the site! {$torrent->link()}");
|
||||
} else {
|
||||
// A lost torrent
|
||||
$torrentFiler->put($bencoder->getEncode(), $torrent->id);
|
||||
$torrentFile->put($bencoder->getEncode());
|
||||
reportError("Thank you for fixing this torrent {$torrent->link()}");
|
||||
}
|
||||
}
|
||||
@@ -588,7 +589,7 @@ foreach ($upload['extra'] as $info) {
|
||||
|
||||
$size = number_format($extra->size() / (1024 * 1024), 2);
|
||||
$upload['new'][] = $extra;
|
||||
$torrentFiler->put($info['TorEnc'], $extra->id);
|
||||
new File\Torrent($extra->id)->put($info['TorEnc']);
|
||||
$extra->logger()->torrent($extra, $Viewer, "uploaded ($size MiB)")
|
||||
->general("Torrent {$extra->id} ($logName) ($size MiB) was uploaded by " . $Viewer->username());
|
||||
}
|
||||
@@ -597,7 +598,7 @@ foreach ($upload['extra'] as $info) {
|
||||
//--------------- Write Files To Disk ------------------------------------------//
|
||||
|
||||
if ($logfileSummary?->total()) {
|
||||
$torrentLogManager = new Manager\TorrentLog(new File\RipLog(), new File\RipLogHTML());
|
||||
$torrentLogManager = new Manager\TorrentLog();
|
||||
$checkerVersion = Logchecker::getLogcheckerVersion();
|
||||
foreach ($logfileSummary->all() as $logfile) {
|
||||
$torrentLogManager->create($torrent, $logfile, $checkerVersion);
|
||||
@@ -608,7 +609,7 @@ $size = number_format($TotalSize / (1024 * 1024), 2);
|
||||
$torrent->logger()->torrent($torrent, $Viewer, "uploaded ($size MiB)")
|
||||
->general("Torrent $TorrentID ($logName) ($size MiB) was uploaded by " . $Viewer->username());
|
||||
|
||||
if (!$torrentFiler->put($bencoder->getEncode(), $TorrentID)) {
|
||||
if (!new File\Torrent($TorrentID)->put($bencoder->getEncode())) {
|
||||
reportError("Internal error saving torrent file. Please report this in the bugs forum.");
|
||||
}
|
||||
$db->commit(); // We have a usable upload, any subsequent failures can be repaired ex post facto
|
||||
|
||||
@@ -23,7 +23,7 @@ switch ($_GET['type']) {
|
||||
}
|
||||
header('Content-type: text/plain');
|
||||
header("Content-Disposition: inline; filename=\"{$match[1]}_{$match[2]}.txt\"");
|
||||
echo new File\RipLog()->get([$match[1], $match[2]]);
|
||||
echo new File\RipLog((int)$match[1], (int)$match[2])->get();
|
||||
break;
|
||||
default:
|
||||
Error404::error();
|
||||
|
||||
@@ -5,75 +5,143 @@ namespace Gazelle;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class FileStorageTest extends TestCase {
|
||||
public function testTorrentPath(): void {
|
||||
$filer = new File\Torrent();
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/10/00/1.torrent', $filer->path(1), 'file-torrent-00001');
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/01/00/10.torrent', $filer->path(10), 'file-torrent-00010');
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/00/10/100.torrent', $filer->path(100), 'file-torrent-00100');
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/00/01/1000.torrent', $filer->path(1000), 'file-torrent-01000');
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/00/00/10000.torrent', $filer->path(10000), 'file-torrent-10000');
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/10/00/10001.torrent', $filer->path(10001), 'file-torrent-10001');
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/20/00/10002.torrent', $filer->path(10002), 'file-torrent-10002');
|
||||
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/43/21/1234.torrent', $filer->path(1234), 'file-torrent-1234');
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/53/21/1235.torrent', $filer->path(1235), 'file-torrent-1235');
|
||||
$this->assertEquals(STORAGE_PATH_TORRENT . '/43/21/81234.torrent', $filer->path(81234), 'file-torrent-81234');
|
||||
}
|
||||
|
||||
public function testRipLogPath(): void {
|
||||
$filer = new File\RipLog();
|
||||
$this->assertEquals(STORAGE_PATH_RIPLOG . '/71/00/17_34.log', $filer->path([17, 34]), 'file-riplog-17-14');
|
||||
$this->assertEquals(STORAGE_PATH_RIPLOG . '/73/16/16137_707.log', $filer->path([16137, 707]), 'file-riplog-16137-707');
|
||||
$this->assertEquals(STORAGE_PATH_RIPLOG . '/73/16/16137_708.log', $filer->path([16137, 708]), 'file-riplog-16137-708');
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_RIPLOG . '/71/00/17_34.log',
|
||||
new File\RipLog(17, 34)->path(),
|
||||
'file-riplog-17-14',
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_RIPLOG . '/73/16/16137_707.log',
|
||||
new File\RipLog(16137, 707)->path(),
|
||||
'file-riplog-16137-707'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_RIPLOG . '/73/16/16137_708.log',
|
||||
new File\RipLog(16137, 708)->path(),
|
||||
'file-riplog-16137-708'
|
||||
);
|
||||
}
|
||||
|
||||
public function testRipLogHTMLPath(): void {
|
||||
$filer = new File\RipLogHTML();
|
||||
$this->assertEquals(STORAGE_PATH_RIPLOGHTML . '/72/00/27_44.html', $filer->path([27, 44]), 'file-html-27-44');
|
||||
$this->assertEquals(STORAGE_PATH_RIPLOGHTML . '/73/16/26137_807.html', $filer->path([26137, 807]), 'file-html-26137-807');
|
||||
$this->assertEquals(STORAGE_PATH_RIPLOGHTML . '/73/16/26137_808.html', $filer->path([26137, 808]), 'file-html-26137-808');
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_RIPLOGHTML . '/72/00/27_44.html',
|
||||
new File\RipLogHTML(27, 44)->path(),
|
||||
'file-html-27-44'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_RIPLOGHTML . '/73/16/26137_807.html',
|
||||
new File\RipLogHTML(26137, 807)->path(),
|
||||
'file-html-26137-807'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_RIPLOGHTML . '/73/16/26137_808.html',
|
||||
new File\RipLogHTML(26137, 808)->path(),
|
||||
'file-html-26137-808'
|
||||
);
|
||||
}
|
||||
|
||||
public function testContestsRipLogHTML(): void {
|
||||
$filer = new File\RipLogHTML();
|
||||
$id = [2651337, 306];
|
||||
$this->assertFalse($filer->exists($id), 'file-h-not-exists');
|
||||
$this->assertFalse($filer->get($id), 'file-h-not-get');
|
||||
$this->assertFalse($filer->remove($id), 'file-h-not-remove');
|
||||
public function testTorrentPath(): void {
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/10/00/1.torrent',
|
||||
new File\Torrent(1)->path(),
|
||||
'file-torrent-00001'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/01/00/10.torrent',
|
||||
new File\Torrent(10)->path(),
|
||||
'file-torrent-00010'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/00/10/100.torrent',
|
||||
new File\Torrent(100)->path(),
|
||||
'file-torrent-00100'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/00/01/1000.torrent',
|
||||
new File\Torrent(1000)->path(),
|
||||
'file-torrent-01000'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/00/00/10000.torrent',
|
||||
new File\Torrent(10000)->path(),
|
||||
'file-torrent-10000'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/10/00/10001.torrent',
|
||||
new File\Torrent(10001)->path(),
|
||||
'file-torrent-10001'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/20/00/10002.torrent',
|
||||
new File\Torrent(10002)->path(),
|
||||
'file-torrent-10002'
|
||||
);
|
||||
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/43/21/1234.torrent',
|
||||
new File\Torrent(1234)->path(),
|
||||
'file-torrent-1234'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/53/21/1235.torrent',
|
||||
new File\Torrent(1235)->path(),
|
||||
'file-torrent-1235'
|
||||
);
|
||||
$this->assertEquals(
|
||||
STORAGE_PATH_TORRENT . '/43/21/81234.torrent',
|
||||
new File\Torrent(81234)->path(),
|
||||
'file-torrent-81234'
|
||||
);
|
||||
}
|
||||
|
||||
public function testFileRipLogHTML(): void {
|
||||
$file = new File\RipLogHTML(2651337, 306);
|
||||
$this->assertFalse($file->exists(), 'file-h-not-exists');
|
||||
$this->assertFalse($file->get(), 'file-h-not-get');
|
||||
$this->assertEquals(0, $file->remove(), 'file-h-not-remove');
|
||||
|
||||
$text = "<h1>phpunit test " . randomString() . "</h1>";
|
||||
$this->assertTrue($filer->put($text, $id), 'file-h-put-ok');
|
||||
$this->assertTrue($file->put($text), 'file-h-put-ok');
|
||||
|
||||
$this->assertTrue($filer->exists($id), 'file-h-exists-ok');
|
||||
$this->assertEquals($text, $filer->get($id), 'file-h-get-ok');
|
||||
$this->assertTrue($filer->remove($id), 'file-h-remove-ok');
|
||||
$this->assertFalse($filer->get($id), 'file-h-get-after-remove');
|
||||
$this->assertTrue($file->exists(), 'file-h-exists-ok');
|
||||
$this->assertEquals($text, $file->get(), 'file-h-get-ok');
|
||||
$this->assertEquals(1, $file->remove(), 'file-h-remove-ok');
|
||||
$this->assertFalse($file->flush()->get(), 'file-h-get-after-remove');
|
||||
$this->assertEquals('', $file->link(), 'file-h-link');
|
||||
$this->assertEquals('', $file->location(), 'file-h-location');
|
||||
}
|
||||
|
||||
public function testContestsRipLog(): void {
|
||||
public function testFileRipLogBinary(): void {
|
||||
/**
|
||||
* = File\RipLog cannot easily be unit-tested, as PHP goes to great
|
||||
* lengths to ensure there is no funny business happening during file
|
||||
* uploads and there is no easy way to mock it.
|
||||
*/
|
||||
$id = [0, 0];
|
||||
$filer = new File\RipLog();
|
||||
$this->assertFalse($filer->exists($id), 'file-r-exists-nok');
|
||||
$this->assertFalse($filer->get($id), 'file-r-get-nok');
|
||||
$file = new File\RipLog(0, 0);
|
||||
$this->assertFalse($file->exists(), 'file-r-exists-nok');
|
||||
$this->assertFalse($file->get(), 'file-r-get-nok');
|
||||
|
||||
$json = new Json\RipLog(0, 0);
|
||||
$this->assertInstanceOf(Json\RipLog::class, $json, 'json-riplog-class');
|
||||
$payload = $json->payload();
|
||||
$this->assertCount(17, $payload, 'json-riplog-payload');
|
||||
$this->assertFalse($payload['success'], 'json-riplog-success-404');
|
||||
|
||||
$this->assertFalse($file->flush()->get(), 'file-riplog-get-after-remove');
|
||||
$this->assertEquals('', $file->link(), 'file-riplog-link');
|
||||
$this->assertEquals('', $file->location(), 'file-riplog-location');
|
||||
}
|
||||
|
||||
public function testContestsTorrent(): void {
|
||||
$filer = new File\Torrent();
|
||||
public function testFileTorrent(): void {
|
||||
$file = new File\Torrent(906622);
|
||||
$text = "This is a phpunit torrent file";
|
||||
$id = 906622;
|
||||
$this->assertTrue($filer->put($text, $id), 'file-t-put-ok');
|
||||
$this->assertEquals($text, $filer->get($id), 'file-t-get-ok');
|
||||
$this->assertTrue($filer->remove($id), 'file-t-put-ok');
|
||||
$this->assertTrue($file->put($text), 'file-t-put-ok');
|
||||
$this->assertEquals($text, $file->get(), 'file-t-get-ok');
|
||||
$this->assertEquals(1, $file->remove(), 'file-t-put-ok');
|
||||
|
||||
$this->assertFalse($file->flush()->get(), 'file-t-get-after-remove');
|
||||
$this->assertEquals('', $file->link(), 'file-t-link');
|
||||
$this->assertEquals('', $file->location(), 'file-t-location');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,10 +92,7 @@ class LogcheckerTest extends TestCase {
|
||||
$this->assertCount(1, $logfileSummary->all(), 'logfilesummary-all');
|
||||
$this->assertEquals(1, $logfileSummary->total(), 'logfilesummary-total');
|
||||
|
||||
$torrentLogManager = new Manager\TorrentLog(
|
||||
new File\RipLog(),
|
||||
new File\RipLogHTML()
|
||||
);
|
||||
$torrentLogManager = new Manager\TorrentLog();
|
||||
$checkerVersion = Logchecker::getLogcheckerVersion();
|
||||
$torrentLog = null;
|
||||
foreach ($logfileSummary->all() as $logfile) {
|
||||
|
||||
@@ -88,13 +88,13 @@ class TorrentTest extends TestCase {
|
||||
$bencoder->decodeFile(__DIR__ . '/../fixture/valid_torrent.torrent');
|
||||
$info = $bencoder->getData();
|
||||
$this->assertIsArray($info, 'torrent-file-data-array');
|
||||
$torrentFiler = new File\Torrent();
|
||||
$torrentFile = new File\Torrent($this->torrent->id);
|
||||
$this->assertTrue(
|
||||
$torrentFiler->put($bencoder->getEncode(), $this->torrent->id()),
|
||||
$torrentFile->put($bencoder->getEncode()),
|
||||
'torrent-file-put'
|
||||
);
|
||||
$this->assertTrue(
|
||||
$torrentFiler->exists($this->torrent->id()),
|
||||
$torrentFile->exists(),
|
||||
'torrent-file-exists'
|
||||
);
|
||||
|
||||
@@ -137,8 +137,9 @@ class TorrentTest extends TestCase {
|
||||
|
||||
$this->assertEquals(8215612, $totalSize, 'torrent-file-total-size');
|
||||
$this->assertCount(3, $fileList, 'torrent-file-list');
|
||||
$this->assertTrue(
|
||||
$torrentFiler->remove($this->torrent->id()),
|
||||
$this->assertEquals(
|
||||
1,
|
||||
$torrentFile->remove(),
|
||||
'torrent-file-remove'
|
||||
);
|
||||
}
|
||||
@@ -169,7 +170,7 @@ class TorrentTest extends TestCase {
|
||||
4,
|
||||
new Manager\User()->sendRemovalPm(
|
||||
$this->user,
|
||||
$torrent->id(),
|
||||
$torrent->id,
|
||||
$name,
|
||||
$path,
|
||||
log: 'phpunit removal test',
|
||||
@@ -275,18 +276,14 @@ class TorrentTest extends TestCase {
|
||||
);
|
||||
$this->assertEquals(
|
||||
0,
|
||||
$this->torrent->removeAllLogs(
|
||||
$this->user,
|
||||
new File\RipLog(),
|
||||
new File\RipLogHTML(),
|
||||
),
|
||||
$this->torrent->removeAllLogs($this->user),
|
||||
'torrent-remove-all-logs'
|
||||
);
|
||||
}
|
||||
|
||||
public function testTorrentBBCode(): void {
|
||||
$torrentId = $this->torrent->id();
|
||||
$tgroupId = $this->torrent->group()->id();
|
||||
$torrentId = $this->torrent->id;
|
||||
$tgroupId = $this->torrent->group()->id;
|
||||
|
||||
$torrentRegexp = "^<a href=\"artist\.php\?id=\d+\" dir=\"ltr\">.*</a> – <a title=\".*?\" href=\"/torrents\.php\?id={$tgroupId}&torrentid={$torrentId}#torrent{$torrentId}\">.* \[\d+ .*?\]</a>";
|
||||
$this->assertMatchesRegularExpression("@{$torrentRegexp} .*$@",
|
||||
|
||||
Reference in New Issue
Block a user