ReleaseCreationService   A
last analyzed

Complexity

Total Complexity 26

Size/Duplication

Total Lines 176
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
wmc 26
eloc 116
dl 0
loc 176
rs 10
c 0
b 0
f 0

2 Methods

Rating   Name   Duplication   Size   Complexity  
F createReleases() 0 163 25
A __construct() 0 3 1
1
<?php
2
3
namespace App\Services;
4
5
use App\Enums\CollectionFileCheckStatus;
6
use App\Models\Category;
7
use App\Models\Collection;
8
use App\Models\Predb;
9
use App\Models\Release;
10
use App\Models\ReleaseRegex;
11
use App\Models\ReleasesGroups;
12
use App\Models\UsenetGroup;
13
use App\Services\Categorization\CategorizationService;
14
use App\Services\Nzb\NzbService;
15
use Illuminate\Support\Facades\DB;
16
use Illuminate\Support\Str;
17
18
class ReleaseCreationService
19
{
20
    public function __construct(
21
        private readonly ReleaseCleaningService $releaseCleaning
0 ignored issues
show
Bug introduced by
The type App\Services\ReleaseCleaningService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
22
    ) {}
23
24
    /**
25
     * Create releases from complete collections.
26
     *
27
     * @return array{added:int,dupes:int}
28
     *
29
     * @throws \Throwable
30
     */
31
    public function createReleases(int|string|null $groupID, int $limit, bool $echoCLI): array
32
    {
33
        $startTime = now()->toImmutable();
34
        $categorize = new CategorizationService;
35
        $returnCount = 0;
36
        $duplicate = 0;
37
38
        if ($echoCLI) {
39
            cli()->header('Process Releases -> Create releases from complete collections.');
40
        }
41
42
        $collectionsQuery = Collection::query()
43
            ->where('collections.filecheck', CollectionFileCheckStatus::Sized->value)
44
            ->where('collections.filesize', '>', 0);
45
        if (! empty($groupID)) {
46
            $collectionsQuery->where('collections.groups_id', $groupID);
47
        }
48
        $collectionsQuery->select(['collections.*', 'usenet_groups.name as gname'])
49
            ->join('usenet_groups', 'usenet_groups.id', '=', 'collections.groups_id')
50
            ->limit($limit);
51
        $collections = $collectionsQuery->get();
52
53
        if ($echoCLI && $collections->count() > 0) {
54
            cli()->primary(\count($collections).' Collections ready to be converted to releases.', true);
55
        }
56
57
        foreach ($collections as $collection) {
58
            $cleanRelName = mb_convert_encoding(str_replace(['#', '@', '$', '%', '^', '§', '¨', '©', 'Ö'], '', $collection->subject), 'UTF-8', mb_list_encodings());
59
            $fromName = mb_convert_encoding(trim($collection->fromname, "'"), 'UTF-8', mb_list_encodings());
60
61
            // Deduplicate by name, from, and ~size
62
            $dupeCheck = Release::query()
63
                ->where(['name' => $cleanRelName, 'fromname' => $fromName])
64
                ->whereBetween('size', [$collection->filesize * .99, $collection->filesize * 1.01])
65
                ->first(['id']);
66
67
            if ($dupeCheck === null) {
68
                $cleanedMeta = $this->releaseCleaning->releaseCleaner(
69
                    $collection->subject,
70
                    $collection->fromname,
71
                    $collection->gname
0 ignored issues
show
Bug introduced by
The property gname does not seem to exist on App\Models\Collection. 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...
72
                );
73
74
                $namingRegexId = 0;
75
                if (\is_array($cleanedMeta)) {
76
                    $namingRegexId = isset($cleanedMeta['id']) ? (int) $cleanedMeta['id'] : 0;
77
                }
78
79
                if (\is_array($cleanedMeta)) {
80
                    $properName = $cleanedMeta['properlynamed'] ?? false;
81
                    $preID = $cleanedMeta['predb'] ?? false;
82
                    $cleanedName = $cleanedMeta['cleansubject'] ?? $cleanRelName;
83
                } else {
84
                    $properName = true;
85
                    $preID = false;
86
                    $cleanedName = $cleanRelName;
87
                }
88
89
                if ($preID === false && $cleanedName !== '') {
90
                    $preMatch = Predb::matchPre($cleanedName);
91
                    if ($preMatch !== false) {
92
                        $cleanedName = $preMatch['title'];
93
                        $preID = $preMatch['predb_id'];
94
                        $properName = true;
95
                    }
96
                }
97
98
                $determinedCategory = $categorize->determineCategory($collection->groups_id, $cleanedName, $fromName);
0 ignored issues
show
Bug introduced by
It seems like $fromName can also be of type array; however, parameter $poster of App\Services\Categorizat...ce::determineCategory() does only seem to accept null|string, maybe add an additional type check? ( Ignorable by Annotation )

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

98
                $determinedCategory = $categorize->determineCategory($collection->groups_id, $cleanedName, /** @scrutinizer ignore-type */ $fromName);
Loading history...
99
100
                $searchName = ! empty($cleanedName) ? mb_convert_encoding($cleanedName, 'UTF-8', mb_list_encodings()) : $cleanRelName;
101
102
                $releaseID = Release::insertRelease([
103
                    'name' => $cleanRelName,
104
                    'searchname' => $searchName,
105
                    'totalpart' => $collection->totalfiles,
106
                    'groups_id' => $collection->groups_id,
107
                    'guid' => Str::uuid()->toString(),
108
                    'postdate' => $collection->date,
109
                    'fromname' => $fromName,
110
                    'size' => $collection->filesize,
111
                    'categories_id' => $determinedCategory['categories_id'] ?? Category::OTHER_MISC,
112
                    'isrenamed' => $properName === true ? 1 : 0,
113
                    'predb_id' => $preID === false ? 0 : $preID,
114
                    'nzbstatus' => NzbService::NZB_NONE,
115
                    'ishashed' => preg_match('/^[a-fA-F0-9]{32}\b|^[a-fA-F0-9]{40}\b|^[a-fA-F0-9]{64}\b|^[a-fA-F0-9]{96}\b|^[a-fA-F0-9]{128}\b/i', $searchName) ? 1 : 0,
0 ignored issues
show
Bug introduced by
It seems like $searchName can also be of type array; however, parameter $subject of preg_match() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

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

115
                    'ishashed' => preg_match('/^[a-fA-F0-9]{32}\b|^[a-fA-F0-9]{40}\b|^[a-fA-F0-9]{64}\b|^[a-fA-F0-9]{96}\b|^[a-fA-F0-9]{128}\b/i', /** @scrutinizer ignore-type */ $searchName) ? 1 : 0,
Loading history...
116
                ]);
117
118
                if ($releaseID !== null) {
119
                    DB::transaction(static function () use ($collection, $releaseID) {
120
                        Collection::query()->where('id', $collection->id)->update([
121
                            'filecheck' => CollectionFileCheckStatus::Inserted->value,
122
                            'releases_id' => $releaseID,
123
                        ]);
124
                    }, 10);
125
126
                    ReleaseRegex::insertOrIgnore([
127
                        'releases_id' => $releaseID,
128
                        'collection_regex_id' => $collection->collection_regexes_id,
129
                        'naming_regex_id' => $namingRegexId,
130
                    ]);
131
132
                    if (preg_match_all('#(\S+):\S+#', $collection->xref, $hits)) {
133
                        foreach ($hits[1] as $grp) {
134
                            $grpTmp = UsenetGroup::isValidGroup($grp);
135
                            if ($grpTmp !== false) {
136
                                $xrefGrpID = UsenetGroup::getIDByName($grpTmp);
137
                                if ($xrefGrpID === '') {
138
                                    $xrefGrpID = UsenetGroup::addGroup([
139
                                        'name' => $grpTmp,
140
                                        'description' => 'Added by Release processing',
141
                                        'backfill_target' => 1,
142
                                        'first_record' => 0,
143
                                        'last_record' => 0,
144
                                        'active' => 0,
145
                                        'backfill' => 0,
146
                                        'minfilestoformrelease' => '',
147
                                        'minsizetoformrelease' => '',
148
                                    ]);
149
                                }
150
151
                                $relGroupsChk = ReleasesGroups::query()->where([
152
                                    ['releases_id', '=', $releaseID],
153
                                    ['groups_id', '=', $xrefGrpID],
154
                                ])->first();
155
156
                                if ($relGroupsChk === null) {
157
                                    ReleasesGroups::query()->insert([
158
                                        'releases_id' => $releaseID,
159
                                        'groups_id' => $xrefGrpID,
160
                                    ]);
161
                                }
162
                            }
163
                        }
164
                    }
165
166
                    $returnCount++;
167
                    if ($echoCLI) {
168
                        echo "Added $returnCount releases.\r";
169
                    }
170
                }
171
            } else {
172
                DB::transaction(static function () use ($collection) {
173
                    Collection::query()->where('collectionhash', $collection->collectionhash)->delete();
174
                }, 10);
175
176
                $duplicate++;
177
            }
178
        }
179
180
        $totalTime = now()->diffInSeconds($startTime, true);
181
        if ($echoCLI) {
182
            cli()->primary(
183
                PHP_EOL.
184
                number_format($returnCount).
185
                ' Releases added and '.
186
                number_format($duplicate).
187
                ' duplicate collections deleted in '.
188
                $totalTime.\Illuminate\Support\Str::plural(' second', $totalTime),
189
                true
190
            );
191
        }
192
193
        return ['added' => $returnCount, 'dupes' => $duplicate];
194
    }
195
}
196