Passed
Push — master ( 4f5b3b...1c5d75 )
by Darko
09:48
created

FindSizeMismatchedReleases   A

Complexity

Total Complexity 16

Size/Duplication

Total Lines 128
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 16
eloc 78
c 1
b 0
f 0
dl 0
loc 128
rs 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A outputReleaseIdsAsCsv() 0 5 1
C handle() 0 87 11
A stripDomainFromString() 0 3 1
A attemptRename() 0 21 3
1
<?php
2
3
namespace App\Console\Commands;
4
5
use App\Models\Release;
6
use Blacklight\NameFixer;
7
use Illuminate\Console\Command;
8
use Illuminate\Support\Facades\DB;
9
10
class FindSizeMismatchedReleases extends Command
11
{
12
    protected $signature = 'nntmux:find-size-mismatches {--threshold=20} {--limit=100} {--season-pack} {--direction=any} {--rename}';
13
14
    protected $description = 'Find releases where size differs significantly from release_files total. Use --direction=bigger|smaller|any';
15
16
    public function handle()
17
    {
18
        $threshold = $this->option('threshold'); // Percentage difference threshold
19
        $limit = $this->option('limit');
20
        $checkSeasonPack = $this->option('season-pack');
21
        $direction = $this->option('direction');
22
        $shouldRename = $this->option('rename');
23
        $nameFixer = new NameFixer;
24
25
        $query = Release::query()
26
            ->select([
27
                'releases.id',
28
                'releases.searchname',
29
                'releases.name',
30
                'releases.groups_id',
31
                'releases.categories_id',
32
                DB::raw('releases.size / POW(1024, 3) as release_size'),
33
                DB::raw('SUM(release_files.size) / POW(1024, 3) as files_total_size'),
34
                DB::raw('(releases.size - SUM(release_files.size)) / POW(1024, 3) as size_diff'),
35
                DB::raw('((releases.size - SUM(release_files.size)) / releases.size * 100) as diff_percent'),
36
            ])
37
            ->join('release_files', 'releases.id', '=', 'release_files.releases_id')
38
            ->where('releases.searchname', 'REGEXP', 'S[0-9]{1,3}E[0-9]{1,3}')
39
            ->groupBy('releases.id');
40
41
        // Apply direction filter
42
        if ($direction === 'bigger') {
43
            $query->having('size_diff', '>', 0)
44
                ->having('diff_percent', '>', $threshold);
45
        } elseif ($direction === 'smaller') {
46
            $query->having('size_diff', '<', 0)
47
                ->having('diff_percent', '<', -$threshold);
48
        } else {
49
            $query->having(DB::raw('ABS(diff_percent)'), '>', $threshold);
50
        }
51
52
        // Order by ID if renaming, otherwise by diff_percent
53
        $query->orderBy($shouldRename ? 'releases.id' : 'diff_percent', $shouldRename ? 'asc' : 'desc');
0 ignored issues
show
Bug introduced by
$shouldRename ? 'releases.id' : 'diff_percent' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderBy(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

53
        $query->orderBy(/** @scrutinizer ignore-type */ $shouldRename ? 'releases.id' : 'diff_percent', $shouldRename ? 'asc' : 'desc');
Loading history...
54
55
        if ($limit > 0) {
56
            $query->limit($limit);
57
        }
58
59
        $mismatches = $query->get();
60
61
        if ($checkSeasonPack) {
62
            $mismatches = $mismatches->filter(function ($release) use ($nameFixer) {
63
                return $nameFixer->isSeasonPack($release->name);
0 ignored issues
show
Bug introduced by
The method isSeasonPack() does not exist on Blacklight\NameFixer. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

63
                return $nameFixer->/** @scrutinizer ignore-call */ isSeasonPack($release->name);

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
64
            });
65
        }
66
67
        if ($mismatches->isEmpty()) {
68
            $this->info('No releases found with size mismatches above '.$threshold.'%'
69
                .($checkSeasonPack ? ' that are season packs' : ''));
70
71
            return;
72
        }
73
74
        if ($shouldRename) {
75
            $this->info("\nAttempting to rename ".$mismatches->count()." releases...\n");
76
77
            foreach ($mismatches as $release) {
78
                $this->attemptRename($release, $nameFixer);
79
            }
80
81
            $this->outputReleaseIdsAsCsv($mismatches);
82
83
            return;
84
        }
85
86
        // Regular table output for non-rename mode
87
        $headers = ['Release ID', 'Searchname', 'Release Size', 'Files Total', 'Difference', 'Diff %'];
88
        $rows = $mismatches->map(function ($release) {
89
            return [
90
                $release->id,
91
                $release->searchname,
92
                number_format($release->release_size, 2).' GiB',
93
                number_format($release->files_total_size, 2).' GiB',
94
                number_format($release->size_diff, 2).' GiB',
95
                number_format($release->diff_percent, 2).'%',
96
            ];
97
        });
98
99
        $this->table($headers, $rows);
100
        $this->info("\nFound ".$mismatches->count().' releases with size mismatches above '.$threshold.'%');
101
102
        $this->outputReleaseIdsAsCsv($mismatches);
103
    }
104
105
    private function attemptRename(Release $release, NameFixer $nameFixer): ?string
106
    {
107
        if (preg_match(NameFixer::PREDB_REGEX, $this->stripDomainFromString($release->name), $matches)) {
0 ignored issues
show
Bug introduced by
The property name does not seem to exist on App\Models\Release. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
108
            $newName = $matches[1];
109
            if ($newName) {
110
                $nameFixer->updateRelease(
111
                    release: $release,
112
                    name: $newName,
113
                    method: 'size-mismatch / season pack',
114
                    echo: true,
115
                    type: '',
116
                    nameStatus: 1,
117
                    show: '1',
118
                    preId: 0
119
                );
120
121
                return $newName;
122
            }
123
        }
124
125
        return null;
126
    }
127
128
    private function outputReleaseIdsAsCsv($mismatches): void
129
    {
130
        $releaseIds = $mismatches->pluck('id')->join(',');
131
        $this->line("\nRelease IDs in CSV format:");
132
        $this->line($releaseIds);
133
    }
134
135
    private function stripDomainFromString(string $str): string
136
    {
137
        return preg_replace("/www\.[^\s]+\.[a-z]{2,4}/i", '', $str);
138
    }
139
}
140