mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 00:01:21 +00:00
Prevent creation of par2 only releases
This commit is contained in:
@@ -422,7 +422,24 @@ final class ReleaseProcessingService
|
||||
? UsenetGroup::getActiveIDs()
|
||||
: [['id' => $normalizedGroupId]];
|
||||
|
||||
$stats = ['minSize' => 0, 'maxSize' => 0, 'minFiles' => 0];
|
||||
$stats = ['minSize' => 0, 'maxSize' => 0, 'minFiles' => 0, 'par2Only' => 0];
|
||||
|
||||
// Delete collections where ALL binaries are par2 files (no actual content)
|
||||
DB::transaction(static function () use (&$stats): void {
|
||||
$par2OnlyCollectionIds = DB::table('collections as c')
|
||||
->join('binaries as b', 'c.id', '=', 'b.collections_id')
|
||||
->where('c.filecheck', CollectionFileCheckStatus::Sized->value)
|
||||
->where('c.filesize', '>', 0)
|
||||
->groupBy('c.id')
|
||||
->havingRaw('COUNT(b.id) = SUM(CASE WHEN b.name REGEXP %s THEN 1 ELSE 0 END)', ['\\.par2'])
|
||||
->pluck('c.id');
|
||||
|
||||
if ($par2OnlyCollectionIds->isNotEmpty()) {
|
||||
$stats['par2Only'] += Collection::query()
|
||||
->whereIn('id', $par2OnlyCollectionIds)
|
||||
->delete();
|
||||
}
|
||||
}, 10);
|
||||
|
||||
foreach ($groupIDs as $grpID) {
|
||||
$groupSettings = UsenetGroup::getGroupByID($grpID['id']);
|
||||
@@ -618,6 +635,7 @@ final class ReleaseProcessingService
|
||||
$stats = $this->deleteDisabledCategoryReleases($stats);
|
||||
$stats = $this->deleteCategoryMinSizeReleases($stats);
|
||||
$stats = $this->deleteDisabledGenreReleases($stats);
|
||||
$stats = $this->deletePar2OnlyReleases($stats);
|
||||
$stats = $this->deleteMiscReleases($stats);
|
||||
|
||||
$this->outputReleaseDeleteStats($stats, $startTime);
|
||||
@@ -1205,6 +1223,38 @@ final class ReleaseProcessingService
|
||||
return $stats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete releases that contain only PAR2 files (no actual content).
|
||||
*
|
||||
* PAR2-only releases are useless since they only contain repair/verification
|
||||
* data without the original content files they are meant to repair.
|
||||
*/
|
||||
private function deletePar2OnlyReleases(ReleaseDeleteStats $stats): ReleaseDeleteStats
|
||||
{
|
||||
// Find releases where ALL associated release_files have names ending in .par2
|
||||
$par2OnlyReleaseIds = DB::table('releases as r')
|
||||
->join('release_files as rf', 'r.id', '=', 'rf.releases_id')
|
||||
->groupBy('r.id')
|
||||
->havingRaw('COUNT(rf.id) = SUM(CASE WHEN rf.name REGEXP %s THEN 1 ELSE 0 END)', ['\\.par2$'])
|
||||
->pluck('r.id');
|
||||
|
||||
if ($par2OnlyReleaseIds->isNotEmpty()) {
|
||||
Release::query()
|
||||
->whereIn('id', $par2OnlyReleaseIds)
|
||||
->select(['id', 'guid'])
|
||||
->chunkById(self::BATCH_SIZE, function ($releases) use (&$stats): bool {
|
||||
foreach ($releases as $release) {
|
||||
$this->deleteSingleRelease($release);
|
||||
$stats = $stats->increment('par2Only');
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
return $stats;
|
||||
}
|
||||
|
||||
private function deleteMiscReleases(ReleaseDeleteStats $stats): ReleaseDeleteStats
|
||||
{
|
||||
if ($this->settings->miscOtherRetentionHours > 0) {
|
||||
@@ -1396,12 +1446,15 @@ final class ReleaseProcessingService
|
||||
*/
|
||||
private function outputCollectionDeleteStats(array $stats, DateTimeInterface $startTime): void
|
||||
{
|
||||
$totalDeleted = $stats['minSize'] + $stats['maxSize'] + $stats['minFiles'];
|
||||
$totalDeleted = $stats['minSize'] + $stats['maxSize'] + $stats['minFiles'] + ($stats['par2Only'] ?? 0);
|
||||
|
||||
if ($totalDeleted > 0) {
|
||||
$this->outputStat('Too small', $stats['minSize']);
|
||||
$this->outputStat('Too large', $stats['maxSize']);
|
||||
$this->outputStat('Too few files', $stats['minFiles']);
|
||||
if (($stats['par2Only'] ?? 0) > 0) {
|
||||
$this->outputStat('Par2 only', $stats['par2Only']);
|
||||
}
|
||||
$this->outputStat('Total removed', $totalDeleted);
|
||||
} else {
|
||||
$this->outputInfo('No collections filtered');
|
||||
@@ -1460,6 +1513,9 @@ final class ReleaseProcessingService
|
||||
if ($stats->miscHashed > 0) {
|
||||
$this->outputStat('Misc->Hashed expired', $stats->miscHashed);
|
||||
}
|
||||
if ($stats->par2Only > 0) {
|
||||
$this->outputStat('Par2-only releases', $stats->par2Only);
|
||||
}
|
||||
|
||||
$this->outputStat('Total releases removed', $total);
|
||||
} else {
|
||||
|
||||
@@ -48,6 +48,8 @@ class ReleaseRemoverService
|
||||
|
||||
private const string TYPE_WMV_ALL = 'wmv_all';
|
||||
|
||||
private const string TYPE_PAR2ONLY = 'par2only';
|
||||
|
||||
protected string $blacklistID = '';
|
||||
|
||||
protected string $crapTime = '';
|
||||
@@ -118,6 +120,7 @@ class ReleaseRemoverService
|
||||
self::TYPE_NZB => fn () => $this->removeSingleNZB(),
|
||||
self::TYPE_CODEC => fn () => $this->removeCodecPoster(),
|
||||
self::TYPE_WMV_ALL => fn () => $this->removeWMV(),
|
||||
self::TYPE_PAR2ONLY => fn () => $this->removePar2Only(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -272,6 +275,7 @@ class ReleaseRemoverService
|
||||
self::TYPE_SIZE,
|
||||
self::TYPE_NZB,
|
||||
self::TYPE_CODEC,
|
||||
self::TYPE_PAR2ONLY,
|
||||
];
|
||||
|
||||
foreach ($defaultTypes as $removalType) {
|
||||
@@ -858,6 +862,31 @@ class ReleaseRemoverService
|
||||
GROUP BY r.id {$this->crapTime}");
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove releases that contain only PAR2 files (no actual content files).
|
||||
*
|
||||
* These releases are useless since PAR2 files are only repair/verification
|
||||
* data and cannot be used without the original content files.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function removePar2Only(): bool|string
|
||||
{
|
||||
return $this->executeSimpleRemoval('Par2Only', sprintf(
|
||||
"SELECT r.guid, r.searchname, r.id
|
||||
FROM releases r
|
||||
INNER JOIN release_files rf ON r.id = rf.releases_id
|
||||
WHERE r.id NOT IN (
|
||||
SELECT rf2.releases_id
|
||||
FROM release_files rf2
|
||||
WHERE rf2.name NOT REGEXP '\\.par2$'
|
||||
)
|
||||
GROUP BY r.id, r.guid, r.searchname
|
||||
%s",
|
||||
$this->crapTime
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a comma-separated list of category IDs.
|
||||
*
|
||||
|
||||
@@ -21,6 +21,7 @@ final readonly class ReleaseDeleteStats
|
||||
public int $disabledGenre = 0,
|
||||
public int $miscOther = 0,
|
||||
public int $miscHashed = 0,
|
||||
public int $par2Only = 0,
|
||||
) {}
|
||||
|
||||
/**
|
||||
@@ -38,6 +39,7 @@ final readonly class ReleaseDeleteStats
|
||||
'disabledGenre' => $this->disabledGenre,
|
||||
'miscOther' => $this->miscOther,
|
||||
'miscHashed' => $this->miscHashed,
|
||||
'par2Only' => $this->par2Only,
|
||||
];
|
||||
|
||||
if (isset($values[$field])) {
|
||||
@@ -60,7 +62,8 @@ final readonly class ReleaseDeleteStats
|
||||
+ $this->categoryMinSize
|
||||
+ $this->disabledGenre
|
||||
+ $this->miscOther
|
||||
+ $this->miscHashed;
|
||||
+ $this->miscHashed
|
||||
+ $this->par2Only;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,6 +83,7 @@ final readonly class ReleaseDeleteStats
|
||||
'disabledGenre' => $this->disabledGenre,
|
||||
'miscOther' => $this->miscOther,
|
||||
'miscHashed' => $this->miscHashed,
|
||||
'par2Only' => $this->par2Only,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -100,6 +104,7 @@ final readonly class ReleaseDeleteStats
|
||||
disabledGenre: $data['disabledGenre'] ?? 0,
|
||||
miscOther: $data['miscOther'] ?? 0,
|
||||
miscHashed: $data['miscHashed'] ?? 0,
|
||||
par2Only: $data['par2Only'] ?? 0,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user