NNTmux /
newznab-tmux
| 1 | <?php |
||||
| 2 | |||||
| 3 | declare(strict_types=1); |
||||
| 4 | |||||
| 5 | namespace App\Services\NameFixing; |
||||
| 6 | |||||
| 7 | use App\Models\Category; |
||||
| 8 | use App\Models\Release; |
||||
| 9 | use App\Services\NameFixing\Contracts\NameSourceFixerInterface; |
||||
| 10 | use App\Services\NameFixing\DTO\NameFixResult; |
||||
| 11 | use App\Services\NameFixing\Extractors\NfoNameExtractor; |
||||
| 12 | use App\Services\NameFixing\Extractors\FileNameExtractor; |
||||
| 13 | use App\Services\NNTP\NNTPService; |
||||
| 14 | use App\Services\Search\ElasticSearchService; |
||||
| 15 | use App\Services\Search\ManticoreSearchService; |
||||
| 16 | use Blacklight\ColorCLI; |
||||
| 17 | use Illuminate\Support\Arr; |
||||
| 18 | |||||
| 19 | /** |
||||
| 20 | * Main service for name fixing operations. |
||||
| 21 | * |
||||
| 22 | * Orchestrates the various name fixing sources (NFO, Files, CRC, SRR, etc.) |
||||
| 23 | * and handles the overall processing flow. |
||||
| 24 | */ |
||||
| 25 | class NameFixingService |
||||
| 26 | { |
||||
| 27 | // Constants for name fixing status |
||||
| 28 | public const PROC_NFO_NONE = 0; |
||||
| 29 | public const PROC_NFO_DONE = 1; |
||||
| 30 | public const PROC_FILES_NONE = 0; |
||||
| 31 | public const PROC_FILES_DONE = 1; |
||||
| 32 | public const PROC_PAR2_NONE = 0; |
||||
| 33 | public const PROC_PAR2_DONE = 1; |
||||
| 34 | public const PROC_UID_NONE = 0; |
||||
| 35 | public const PROC_UID_DONE = 1; |
||||
| 36 | public const PROC_HASH16K_NONE = 0; |
||||
| 37 | public const PROC_HASH16K_DONE = 1; |
||||
| 38 | public const PROC_SRR_NONE = 0; |
||||
| 39 | public const PROC_SRR_DONE = 1; |
||||
| 40 | public const PROC_CRC_NONE = 0; |
||||
| 41 | public const PROC_CRC_DONE = 1; |
||||
| 42 | |||||
| 43 | // Constants for overall rename status |
||||
| 44 | public const IS_RENAMED_NONE = 0; |
||||
| 45 | public const IS_RENAMED_DONE = 1; |
||||
| 46 | |||||
| 47 | protected ReleaseUpdateService $updateService; |
||||
| 48 | protected NameCheckerService $checkerService; |
||||
| 49 | protected NfoNameExtractor $nfoExtractor; |
||||
| 50 | protected FileNameExtractor $fileExtractor; |
||||
| 51 | protected FileNameCleaner $fileNameCleaner; |
||||
| 52 | protected FilePrioritizer $filePrioritizer; |
||||
| 53 | protected ManticoreSearchService $manticore; |
||||
| 54 | protected ElasticSearchService $elasticsearch; |
||||
| 55 | protected ColorCLI $colorCLI; |
||||
| 56 | protected bool $echoOutput; |
||||
| 57 | |||||
| 58 | protected string $othercats; |
||||
| 59 | protected string $timeother; |
||||
| 60 | protected string $timeall; |
||||
| 61 | protected string $fullother; |
||||
| 62 | protected string $fullall; |
||||
| 63 | |||||
| 64 | protected int $_totalReleases = 0; |
||||
| 65 | |||||
| 66 | public function __construct( |
||||
| 67 | ?ReleaseUpdateService $updateService = null, |
||||
| 68 | ?NameCheckerService $checkerService = null, |
||||
| 69 | ?NfoNameExtractor $nfoExtractor = null, |
||||
| 70 | ?FileNameExtractor $fileExtractor = null, |
||||
| 71 | ?FileNameCleaner $fileNameCleaner = null, |
||||
| 72 | ?FilePrioritizer $filePrioritizer = null, |
||||
| 73 | ?ManticoreSearchService $manticore = null, |
||||
| 74 | ?ElasticSearchService $elasticsearch = null, |
||||
| 75 | ?ColorCLI $colorCLI = null |
||||
| 76 | ) { |
||||
| 77 | $this->updateService = $updateService ?? new ReleaseUpdateService(); |
||||
| 78 | $this->checkerService = $checkerService ?? new NameCheckerService(); |
||||
| 79 | $this->nfoExtractor = $nfoExtractor ?? new NfoNameExtractor(); |
||||
| 80 | $this->fileExtractor = $fileExtractor ?? new FileNameExtractor(); |
||||
| 81 | $this->fileNameCleaner = $fileNameCleaner ?? new FileNameCleaner(); |
||||
| 82 | $this->filePrioritizer = $filePrioritizer ?? new FilePrioritizer(); |
||||
| 83 | $this->manticore = $manticore ?? app(ManticoreSearchService::class); |
||||
| 84 | $this->elasticsearch = $elasticsearch ?? app(ElasticSearchService::class); |
||||
| 85 | $this->colorCLI = $colorCLI ?? new ColorCLI(); |
||||
| 86 | $this->echoOutput = config('nntmux.echocli'); |
||||
| 87 | |||||
| 88 | $this->othercats = implode(',', Category::OTHERS_GROUP); |
||||
| 89 | $this->timeother = sprintf(' AND rel.adddate > (NOW() - INTERVAL 6 HOUR) AND rel.categories_id IN (%s) GROUP BY rel.id ORDER BY postdate DESC', $this->othercats); |
||||
| 90 | $this->timeall = ' AND rel.adddate > (NOW() - INTERVAL 6 HOUR) GROUP BY rel.id ORDER BY postdate DESC'; |
||||
| 91 | $this->fullother = sprintf(' AND rel.categories_id IN (%s) GROUP BY rel.id', $this->othercats); |
||||
| 92 | $this->fullall = ''; |
||||
| 93 | } |
||||
| 94 | |||||
| 95 | /** |
||||
| 96 | * Fix names using NFO content. |
||||
| 97 | */ |
||||
| 98 | public function fixNamesWithNfo(int $time, bool $echo, int $cats, bool $nameStatus, bool $show): void |
||||
| 99 | { |
||||
| 100 | $this->echoStartMessage($time, '.nfo files'); |
||||
| 101 | $type = 'NFO, '; |
||||
| 102 | |||||
| 103 | $preId = false; |
||||
| 104 | if ($cats === 3) { |
||||
| 105 | $query = sprintf( |
||||
| 106 | 'SELECT rel.id AS releases_id, rel.fromname |
||||
| 107 | FROM releases rel |
||||
| 108 | INNER JOIN release_nfos nfo ON (nfo.releases_id = rel.id) |
||||
| 109 | WHERE rel.predb_id = 0' |
||||
| 110 | ); |
||||
| 111 | $cats = 2; |
||||
| 112 | $preId = true; |
||||
| 113 | } else { |
||||
| 114 | $query = sprintf( |
||||
| 115 | 'SELECT rel.id AS releases_id, rel.fromname |
||||
| 116 | FROM releases rel |
||||
| 117 | INNER JOIN release_nfos nfo ON (nfo.releases_id = rel.id) |
||||
| 118 | WHERE (rel.isrenamed = %d OR rel.categories_id IN (%d, %d)) |
||||
| 119 | AND rel.predb_id = 0 |
||||
| 120 | AND rel.proc_nfo = %d', |
||||
| 121 | self::IS_RENAMED_NONE, |
||||
| 122 | Category::OTHER_MISC, |
||||
| 123 | Category::OTHER_HASHED, |
||||
| 124 | self::PROC_NFO_NONE |
||||
| 125 | ); |
||||
| 126 | } |
||||
| 127 | |||||
| 128 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 129 | $total = $releases->count(); |
||||
| 130 | |||||
| 131 | if ($total > 0) { |
||||
| 132 | $this->_totalReleases = $total; |
||||
| 133 | $this->colorCLI->info(number_format($total) . ' releases to process.'); |
||||
| 134 | |||||
| 135 | foreach ($releases as $rel) { |
||||
| 136 | $releaseRow = Release::fromQuery( |
||||
| 137 | sprintf( |
||||
| 138 | 'SELECT nfo.releases_id AS nfoid, rel.groups_id, rel.fromname, rel.categories_id, rel.name, rel.searchname, |
||||
| 139 | UNCOMPRESS(nfo) AS textstring, rel.id AS releases_id |
||||
| 140 | FROM releases rel |
||||
| 141 | INNER JOIN release_nfos nfo ON (nfo.releases_id = rel.id) |
||||
| 142 | WHERE rel.id = %d LIMIT 1', |
||||
| 143 | $rel->releases_id |
||||
| 144 | ) |
||||
| 145 | ); |
||||
| 146 | |||||
| 147 | $this->updateService->incrementChecked(); |
||||
| 148 | |||||
| 149 | // Ignore encrypted NFOs |
||||
| 150 | if (preg_match('/^=newz\[NZB\]=\w+/', $releaseRow[0]->textstring)) { |
||||
| 151 | $this->updateService->updateSingleColumn('proc_nfo', self::PROC_NFO_DONE, $rel->releases_id); |
||||
| 152 | continue; |
||||
| 153 | } |
||||
| 154 | |||||
| 155 | $this->updateService->reset(); |
||||
| 156 | |||||
| 157 | // Try NFO extraction |
||||
| 158 | $nfoResult = $this->nfoExtractor->extractFromNfo($releaseRow[0]->textstring); |
||||
| 159 | if ($nfoResult !== null) { |
||||
| 160 | $this->updateService->updateRelease( |
||||
| 161 | $releaseRow[0], |
||||
| 162 | $nfoResult->newName, |
||||
| 163 | 'nfoCheck: ' . $nfoResult->method, |
||||
| 164 | $echo, |
||||
| 165 | $type, |
||||
| 166 | $nameStatus, |
||||
| 167 | $show |
||||
| 168 | ); |
||||
| 169 | } |
||||
| 170 | |||||
| 171 | // If NFO extraction didn't work, try pattern checkers |
||||
| 172 | if (!$this->updateService->matched) { |
||||
| 173 | $this->checkWithPatternMatchers($releaseRow[0], $echo, $type, $nameStatus, $show, $preId); |
||||
| 174 | } |
||||
| 175 | |||||
| 176 | $this->echoRenamed($show); |
||||
| 177 | } |
||||
| 178 | $this->echoFoundCount($echo, ' NFO\'s'); |
||||
| 179 | } else { |
||||
| 180 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 181 | } |
||||
| 182 | } |
||||
| 183 | |||||
| 184 | /** |
||||
| 185 | * Fix names using file names. |
||||
| 186 | */ |
||||
| 187 | public function fixNamesWithFiles(int $time, bool $echo, int $cats, bool $nameStatus, bool $show): void |
||||
| 188 | { |
||||
| 189 | $this->echoStartMessage($time, 'file names'); |
||||
| 190 | $type = 'Filenames, '; |
||||
| 191 | |||||
| 192 | $preId = false; |
||||
|
0 ignored issues
–
show
Unused Code
introduced
by
Loading history...
|
|||||
| 193 | if ($cats === 3) { |
||||
| 194 | $query = sprintf( |
||||
| 195 | 'SELECT rf.name AS textstring, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, |
||||
| 196 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 197 | FROM releases rel |
||||
| 198 | INNER JOIN release_files rf ON rf.releases_id = rel.id |
||||
| 199 | WHERE predb_id = 0' |
||||
| 200 | ); |
||||
| 201 | $cats = 2; |
||||
| 202 | $preId = true; |
||||
| 203 | } else { |
||||
| 204 | $query = sprintf( |
||||
| 205 | 'SELECT rf.name AS textstring, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, |
||||
| 206 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 207 | FROM releases rel |
||||
| 208 | INNER JOIN release_files rf ON rf.releases_id = rel.id |
||||
| 209 | WHERE (rel.isrenamed = %d OR rel.categories_id IN (%d, %d)) |
||||
| 210 | AND rel.predb_id = 0 |
||||
| 211 | AND proc_files = %d', |
||||
| 212 | self::IS_RENAMED_NONE, |
||||
| 213 | Category::OTHER_MISC, |
||||
| 214 | Category::OTHER_HASHED, |
||||
| 215 | self::PROC_FILES_NONE |
||||
| 216 | ); |
||||
| 217 | } |
||||
| 218 | |||||
| 219 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 220 | $total = $releases->count(); |
||||
| 221 | |||||
| 222 | if ($total > 0) { |
||||
| 223 | $this->_totalReleases = $total; |
||||
| 224 | $this->colorCLI->info(number_format($total) . ' file names to process.'); |
||||
| 225 | |||||
| 226 | // Group files by release |
||||
| 227 | $releaseFiles = []; |
||||
| 228 | foreach ($releases as $release) { |
||||
| 229 | $releaseId = $release->releases_id; |
||||
| 230 | if (!isset($releaseFiles[$releaseId])) { |
||||
| 231 | $releaseFiles[$releaseId] = [ |
||||
| 232 | 'release' => $release, |
||||
| 233 | 'files' => [], |
||||
| 234 | ]; |
||||
| 235 | } |
||||
| 236 | $releaseFiles[$releaseId]['files'][] = $release->textstring; |
||||
| 237 | } |
||||
| 238 | |||||
| 239 | foreach ($releaseFiles as $releaseId => $data) { |
||||
| 240 | $this->updateService->reset(); |
||||
| 241 | $this->updateService->incrementChecked(); |
||||
| 242 | |||||
| 243 | // Prioritize files for matching |
||||
| 244 | $prioritizedFiles = $this->filePrioritizer->prioritizeForMatching($data['files']); |
||||
| 245 | |||||
| 246 | foreach ($prioritizedFiles as $filename) { |
||||
| 247 | $release = clone $data['release']; |
||||
| 248 | $release->textstring = $filename; |
||||
| 249 | |||||
| 250 | // Try file name extraction |
||||
| 251 | $fileResult = $this->fileExtractor->extractFromFile($filename); |
||||
| 252 | if ($fileResult !== null) { |
||||
| 253 | $this->updateService->updateRelease( |
||||
| 254 | $release, |
||||
| 255 | $fileResult->newName, |
||||
| 256 | 'fileCheck: ' . $fileResult->method, |
||||
| 257 | $echo, |
||||
| 258 | $type, |
||||
| 259 | $nameStatus, |
||||
| 260 | $show |
||||
| 261 | ); |
||||
| 262 | } |
||||
| 263 | |||||
| 264 | // If not matched, try PreDB search |
||||
| 265 | if (!$this->updateService->matched) { |
||||
| 266 | $this->preDbFileCheck($release, $echo, $type, $nameStatus, $show); |
||||
| 267 | } |
||||
| 268 | |||||
| 269 | if (!$this->updateService->matched) { |
||||
| 270 | $this->preDbTitleCheck($release, $echo, $type, $nameStatus, $show); |
||||
| 271 | } |
||||
| 272 | |||||
| 273 | if ($this->updateService->matched) { |
||||
| 274 | break; |
||||
| 275 | } |
||||
| 276 | } |
||||
| 277 | |||||
| 278 | $this->echoRenamed($show); |
||||
| 279 | } |
||||
| 280 | |||||
| 281 | $this->echoFoundCount($echo, ' files'); |
||||
| 282 | } else { |
||||
| 283 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 284 | } |
||||
| 285 | } |
||||
| 286 | |||||
| 287 | /** |
||||
| 288 | * Fix names using SRR files. |
||||
| 289 | */ |
||||
| 290 | public function fixNamesWithSrr(int $time, bool $echo, int $cats, bool $nameStatus, bool $show): void |
||||
| 291 | { |
||||
| 292 | $this->echoStartMessage($time, 'SRR file names'); |
||||
| 293 | $type = 'SRR, '; |
||||
| 294 | |||||
| 295 | if ($cats === 3) { |
||||
| 296 | $query = sprintf( |
||||
| 297 | 'SELECT rf.name AS textstring, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, |
||||
| 298 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 299 | FROM releases rel |
||||
| 300 | INNER JOIN release_files rf ON (rf.releases_id = rel.id) |
||||
| 301 | WHERE predb_id = 0 |
||||
| 302 | AND (rf.name LIKE %s OR rf.name LIKE %s)', |
||||
| 303 | escapeString('%.srr'), |
||||
| 304 | escapeString('%.srs') |
||||
| 305 | ); |
||||
| 306 | $cats = 2; |
||||
| 307 | } else { |
||||
| 308 | $query = sprintf( |
||||
| 309 | 'SELECT rf.name AS textstring, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, |
||||
| 310 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 311 | FROM releases rel |
||||
| 312 | INNER JOIN release_files rf ON (rf.releases_id = rel.id) |
||||
| 313 | WHERE (rel.isrenamed = %d OR rel.categories_id IN (%d, %d)) |
||||
| 314 | AND rel.predb_id = 0 |
||||
| 315 | AND (rf.name LIKE %s OR rf.name LIKE %s) |
||||
| 316 | AND rel.proc_srr = %d', |
||||
| 317 | self::IS_RENAMED_NONE, |
||||
| 318 | Category::OTHER_MISC, |
||||
| 319 | Category::OTHER_HASHED, |
||||
| 320 | escapeString('%.srr'), |
||||
| 321 | escapeString('%.srs'), |
||||
| 322 | self::PROC_SRR_NONE |
||||
| 323 | ); |
||||
| 324 | } |
||||
| 325 | |||||
| 326 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 327 | $total = $releases->count(); |
||||
| 328 | |||||
| 329 | if ($total > 0) { |
||||
| 330 | $this->_totalReleases = $total; |
||||
| 331 | $this->colorCLI->info(number_format($total) . ' srr file extensions to process.'); |
||||
| 332 | |||||
| 333 | foreach ($releases as $release) { |
||||
| 334 | $this->updateService->reset(); |
||||
| 335 | $this->updateService->incrementChecked(); |
||||
| 336 | |||||
| 337 | $this->srrNameCheck($release, $echo, $type, $nameStatus, $show); |
||||
| 338 | $this->echoRenamed($show); |
||||
| 339 | } |
||||
| 340 | |||||
| 341 | $this->echoFoundCount($echo, ' files'); |
||||
| 342 | } else { |
||||
| 343 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 344 | } |
||||
| 345 | } |
||||
| 346 | |||||
| 347 | /** |
||||
| 348 | * Fix names using CRC32 hashes. |
||||
| 349 | */ |
||||
| 350 | public function fixNamesWithCrc(int $time, bool $echo, int $cats, bool $nameStatus, bool $show): void |
||||
| 351 | { |
||||
| 352 | $this->echoStartMessage($time, 'CRC32'); |
||||
| 353 | $type = 'CRC32, '; |
||||
| 354 | |||||
| 355 | $preId = false; |
||||
| 356 | if ($cats === 3) { |
||||
| 357 | $query = sprintf( |
||||
| 358 | 'SELECT rf.crc32 AS textstring, rf.name AS filename, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, rel.size as relsize, |
||||
| 359 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 360 | FROM releases rel |
||||
| 361 | INNER JOIN release_files rf ON rf.releases_id = rel.id |
||||
| 362 | WHERE predb_id = 0 |
||||
| 363 | AND rf.crc32 != \'\' |
||||
| 364 | AND rf.crc32 IS NOT NULL' |
||||
| 365 | ); |
||||
| 366 | $cats = 2; |
||||
| 367 | $preId = true; |
||||
| 368 | } else { |
||||
| 369 | $query = sprintf( |
||||
| 370 | 'SELECT rf.crc32 AS textstring, rf.name AS filename, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, rel.size as relsize, |
||||
| 371 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 372 | FROM releases rel |
||||
| 373 | INNER JOIN release_files rf ON rf.releases_id = rel.id |
||||
| 374 | WHERE (rel.isrenamed = %d OR rel.categories_id IN (%d, %d)) |
||||
| 375 | AND rel.predb_id = 0 |
||||
| 376 | AND rel.proc_crc32 = %d |
||||
| 377 | AND rf.crc32 != \'\' |
||||
| 378 | AND rf.crc32 IS NOT NULL', |
||||
| 379 | self::IS_RENAMED_NONE, |
||||
| 380 | Category::OTHER_MISC, |
||||
| 381 | Category::OTHER_HASHED, |
||||
| 382 | self::PROC_CRC_NONE |
||||
| 383 | ); |
||||
| 384 | } |
||||
| 385 | |||||
| 386 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 387 | $total = $releases->count(); |
||||
| 388 | |||||
| 389 | if ($total > 0) { |
||||
| 390 | $this->_totalReleases = $total; |
||||
| 391 | $this->colorCLI->info(number_format($total) . ' CRC32\'s to process.'); |
||||
| 392 | |||||
| 393 | // Group by release |
||||
| 394 | $releasesCrc = []; |
||||
| 395 | foreach ($releases as $release) { |
||||
| 396 | $releaseId = $release->releases_id; |
||||
| 397 | if (!isset($releasesCrc[$releaseId])) { |
||||
| 398 | $releasesCrc[$releaseId] = [ |
||||
| 399 | 'release' => $release, |
||||
| 400 | 'crcs' => [], |
||||
| 401 | ]; |
||||
| 402 | } |
||||
| 403 | if (!empty($release->textstring)) { |
||||
| 404 | $priority = $this->filePrioritizer->getCrcPriority($release->filename ?? ''); |
||||
| 405 | $releasesCrc[$releaseId]['crcs'][$priority][] = $release->textstring; |
||||
| 406 | } |
||||
| 407 | } |
||||
| 408 | |||||
| 409 | foreach ($releasesCrc as $releaseId => $data) { |
||||
| 410 | $this->updateService->reset(); |
||||
| 411 | $this->updateService->incrementChecked(); |
||||
| 412 | |||||
| 413 | ksort($data['crcs']); |
||||
| 414 | foreach ($data['crcs'] as $crcs) { |
||||
| 415 | foreach ($crcs as $crc) { |
||||
| 416 | $release = clone $data['release']; |
||||
| 417 | $release->textstring = $crc; |
||||
| 418 | |||||
| 419 | $this->crcCheck($release, $echo, $type, $nameStatus, $show, $preId); |
||||
| 420 | |||||
| 421 | if ($this->updateService->matched) { |
||||
| 422 | break 2; |
||||
| 423 | } |
||||
| 424 | } |
||||
| 425 | } |
||||
| 426 | |||||
| 427 | $this->echoRenamed($show); |
||||
| 428 | } |
||||
| 429 | |||||
| 430 | $this->echoFoundCount($echo, ' crc32\'s'); |
||||
| 431 | } else { |
||||
| 432 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 433 | } |
||||
| 434 | } |
||||
| 435 | |||||
| 436 | /** |
||||
| 437 | * Fix names using Media info unique IDs. |
||||
| 438 | */ |
||||
| 439 | public function fixNamesWithMedia(int $time, bool $echo, int $cats, bool $nameStatus, bool $show): void |
||||
| 440 | { |
||||
| 441 | $type = 'UID, '; |
||||
| 442 | $this->echoStartMessage($time, 'mediainfo Unique_IDs'); |
||||
| 443 | |||||
| 444 | if ($cats === 3) { |
||||
| 445 | $query = sprintf( |
||||
| 446 | 'SELECT rel.id AS releases_id, rel.size AS relsize, rel.groups_id, rel.fromname, rel.categories_id, |
||||
| 447 | rel.name, rel.name AS textstring, rel.predb_id, rel.searchname, |
||||
| 448 | ru.unique_id AS uid |
||||
| 449 | FROM releases rel |
||||
| 450 | LEFT JOIN media_infos ru ON ru.releases_id = rel.id |
||||
| 451 | WHERE ru.releases_id IS NOT NULL |
||||
| 452 | AND rel.predb_id = 0' |
||||
| 453 | ); |
||||
| 454 | $cats = 2; |
||||
| 455 | } else { |
||||
| 456 | $query = sprintf( |
||||
| 457 | 'SELECT rel.id AS releases_id, rel.size AS relsize, rel.groups_id, rel.fromname, rel.categories_id, |
||||
| 458 | rel.name, rel.name AS textstring, rel.predb_id, rel.searchname, |
||||
| 459 | ru.unique_id AS uid |
||||
| 460 | FROM releases rel |
||||
| 461 | LEFT JOIN media_infos ru ON ru.releases_id = rel.id |
||||
| 462 | WHERE ru.releases_id IS NOT NULL |
||||
| 463 | AND (rel.isrenamed = %d OR rel.categories_id IN (%d, %d)) |
||||
| 464 | AND rel.predb_id = 0 |
||||
| 465 | AND rel.proc_uid = %d', |
||||
| 466 | self::IS_RENAMED_NONE, |
||||
| 467 | Category::OTHER_MISC, |
||||
| 468 | Category::OTHER_HASHED, |
||||
| 469 | self::PROC_UID_NONE |
||||
| 470 | ); |
||||
| 471 | } |
||||
| 472 | |||||
| 473 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 474 | $total = $releases->count(); |
||||
| 475 | |||||
| 476 | if ($total > 0) { |
||||
| 477 | $this->_totalReleases = $total; |
||||
| 478 | $this->colorCLI->info(number_format($total) . ' unique ids to process.'); |
||||
| 479 | |||||
| 480 | foreach ($releases as $rel) { |
||||
| 481 | $this->updateService->reset(); |
||||
| 482 | $this->updateService->incrementChecked(); |
||||
| 483 | $this->uidCheck($rel, $echo, $type, $nameStatus, $show); |
||||
| 484 | $this->echoRenamed($show); |
||||
| 485 | } |
||||
| 486 | |||||
| 487 | $this->echoFoundCount($echo, ' UID\'s'); |
||||
| 488 | } else { |
||||
| 489 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 490 | } |
||||
| 491 | } |
||||
| 492 | |||||
| 493 | /** |
||||
| 494 | * Fix names using PAR2 hash_16K. |
||||
| 495 | */ |
||||
| 496 | public function fixNamesWithParHash(int $time, bool $echo, int $cats, bool $nameStatus, bool $show): void |
||||
| 497 | { |
||||
| 498 | $type = 'PAR2 hash, '; |
||||
| 499 | $this->echoStartMessage($time, 'PAR2 hash_16K'); |
||||
| 500 | |||||
| 501 | if ($cats === 3) { |
||||
| 502 | $query = sprintf( |
||||
| 503 | 'SELECT rel.id AS releases_id, rel.size AS relsize, rel.groups_id, rel.fromname, rel.categories_id, |
||||
| 504 | rel.name, rel.name AS textstring, rel.predb_id, rel.searchname, |
||||
| 505 | IFNULL(ph.hash, \'\') AS hash |
||||
| 506 | FROM releases rel |
||||
| 507 | LEFT JOIN par_hashes ph ON ph.releases_id = rel.id |
||||
| 508 | WHERE ph.hash != \'\' |
||||
| 509 | AND rel.predb_id = 0' |
||||
| 510 | ); |
||||
| 511 | $cats = 2; |
||||
| 512 | } else { |
||||
| 513 | $query = sprintf( |
||||
| 514 | 'SELECT rel.id AS releases_id, rel.size AS relsize, rel.groups_id, rel.fromname, rel.categories_id, |
||||
| 515 | rel.name, rel.name AS textstring, rel.predb_id, rel.searchname, |
||||
| 516 | IFNULL(ph.hash, \'\') AS hash |
||||
| 517 | FROM releases rel |
||||
| 518 | LEFT JOIN par_hashes ph ON ph.releases_id = rel.id |
||||
| 519 | WHERE (rel.isrenamed = %d OR rel.categories_id IN (%d, %d)) |
||||
| 520 | AND rel.predb_id = 0 |
||||
| 521 | AND ph.hash != \'\' |
||||
| 522 | AND rel.proc_hash16k = %d', |
||||
| 523 | self::IS_RENAMED_NONE, |
||||
| 524 | Category::OTHER_MISC, |
||||
| 525 | Category::OTHER_HASHED, |
||||
| 526 | self::PROC_HASH16K_NONE |
||||
| 527 | ); |
||||
| 528 | } |
||||
| 529 | |||||
| 530 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 531 | $total = $releases->count(); |
||||
| 532 | |||||
| 533 | if ($total > 0) { |
||||
| 534 | $this->_totalReleases = $total; |
||||
| 535 | $this->colorCLI->info(number_format($total) . ' hash_16K to process.'); |
||||
| 536 | |||||
| 537 | foreach ($releases as $rel) { |
||||
| 538 | $this->updateService->reset(); |
||||
| 539 | $this->updateService->incrementChecked(); |
||||
| 540 | $this->hashCheck($rel, $echo, $type, $nameStatus, $show); |
||||
| 541 | $this->echoRenamed($show); |
||||
| 542 | } |
||||
| 543 | |||||
| 544 | $this->echoFoundCount($echo, ' hashes'); |
||||
| 545 | } else { |
||||
| 546 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 547 | } |
||||
| 548 | } |
||||
| 549 | |||||
| 550 | /** |
||||
| 551 | * Check with pattern matchers (TV, Movie, Game, App). |
||||
| 552 | */ |
||||
| 553 | protected function checkWithPatternMatchers(object $release, bool $echo, string $type, bool $nameStatus, bool $show, bool $preId): void |
||||
| 554 | { |
||||
| 555 | // Check for PreDB match first |
||||
| 556 | $preDbMatch = $this->updateService->checkPreDbMatch($release, $release->textstring); |
||||
| 557 | if ($preDbMatch !== null) { |
||||
| 558 | $this->updateService->updateRelease( |
||||
| 559 | $release, |
||||
| 560 | $preDbMatch['title'], |
||||
| 561 | 'preDB: Match', |
||||
| 562 | $echo, |
||||
| 563 | $type, |
||||
| 564 | $nameStatus, |
||||
| 565 | $show, |
||||
| 566 | $preDbMatch['id'] |
||||
| 567 | ); |
||||
| 568 | return; |
||||
| 569 | } |
||||
| 570 | |||||
| 571 | if ($preId) { |
||||
| 572 | return; |
||||
| 573 | } |
||||
| 574 | |||||
| 575 | // Try pattern checkers |
||||
| 576 | $result = $this->checkerService->check($release, $release->textstring); |
||||
| 577 | if ($result !== null) { |
||||
| 578 | $this->updateService->updateRelease( |
||||
| 579 | $release, |
||||
| 580 | $result->newName, |
||||
| 581 | $result->getFormattedMethod(), |
||||
| 582 | $echo, |
||||
| 583 | $type, |
||||
| 584 | $nameStatus, |
||||
| 585 | $show |
||||
| 586 | ); |
||||
| 587 | } |
||||
| 588 | } |
||||
| 589 | |||||
| 590 | /** |
||||
| 591 | * Check SRR file for release name. |
||||
| 592 | */ |
||||
| 593 | protected function srrNameCheck(object $release, bool $echo, string $type, bool $nameStatus, bool $show): bool |
||||
| 594 | { |
||||
| 595 | $extractedName = null; |
||||
| 596 | |||||
| 597 | if (preg_match('/^(.+)\.srr$/i', $release->textstring, $hit)) { |
||||
| 598 | $extractedName = $hit[1]; |
||||
| 599 | } elseif (preg_match('/^(.+)\.srs$/i', $release->textstring, $hit)) { |
||||
| 600 | $extractedName = $hit[1]; |
||||
| 601 | } |
||||
| 602 | |||||
| 603 | if ($extractedName !== null) { |
||||
| 604 | if (preg_match('/[\\\\\/]([^\\\\\/]+)$/', $extractedName, $pathMatch)) { |
||||
| 605 | $extractedName = $pathMatch[1]; |
||||
| 606 | } |
||||
| 607 | |||||
| 608 | if (preg_match(ReleaseUpdateService::PREDB_REGEX, $extractedName)) { |
||||
| 609 | $this->updateService->updateRelease( |
||||
| 610 | $release, |
||||
| 611 | $extractedName, |
||||
| 612 | 'fileCheck: SRR extension', |
||||
| 613 | $echo, |
||||
| 614 | $type, |
||||
| 615 | $nameStatus, |
||||
| 616 | $show |
||||
| 617 | ); |
||||
| 618 | return true; |
||||
| 619 | } |
||||
| 620 | } |
||||
| 621 | |||||
| 622 | $this->updateService->updateSingleColumn('proc_srr', self::PROC_SRR_DONE, $release->releases_id); |
||||
| 623 | return false; |
||||
| 624 | } |
||||
| 625 | |||||
| 626 | /** |
||||
| 627 | * Check CRC32 for matches. |
||||
| 628 | */ |
||||
| 629 | protected function crcCheck(object $release, bool $echo, string $type, bool $nameStatus, bool $show, bool $preId): bool |
||||
|
0 ignored issues
–
show
The parameter
$preId is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. Loading history...
|
|||||
| 630 | { |
||||
| 631 | if ($release->textstring === '') { |
||||
| 632 | $this->updateService->updateSingleColumn('proc_crc32', self::PROC_CRC_DONE, $release->releases_id); |
||||
| 633 | return false; |
||||
| 634 | } |
||||
| 635 | |||||
| 636 | $result = Release::fromQuery( |
||||
| 637 | sprintf( |
||||
| 638 | 'SELECT rf.crc32, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, rel.size as relsize, rel.predb_id as predb_id, |
||||
| 639 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 640 | FROM releases rel |
||||
| 641 | LEFT JOIN release_files rf ON rf.releases_id = rel.id |
||||
| 642 | WHERE rel.predb_id > 0 |
||||
| 643 | AND rf.crc32 = %s', |
||||
| 644 | escapeString($release->textstring) |
||||
| 645 | ) |
||||
| 646 | ); |
||||
| 647 | |||||
| 648 | foreach ($result as $res) { |
||||
| 649 | $floor = round(($res->relsize - $release->relsize) / $res->relsize * 100, 1); |
||||
| 650 | if ($floor >= -5 && $floor <= 5) { |
||||
| 651 | $this->updateService->updateRelease( |
||||
| 652 | $release, |
||||
| 653 | $res->searchname, |
||||
| 654 | 'crcCheck: CRC32', |
||||
| 655 | $echo, |
||||
| 656 | $type, |
||||
| 657 | $nameStatus, |
||||
| 658 | $show, |
||||
| 659 | $res->predb_id |
||||
| 660 | ); |
||||
| 661 | return true; |
||||
| 662 | } |
||||
| 663 | } |
||||
| 664 | |||||
| 665 | $this->updateService->updateSingleColumn('proc_crc32', self::PROC_CRC_DONE, $release->releases_id); |
||||
| 666 | return false; |
||||
| 667 | } |
||||
| 668 | |||||
| 669 | /** |
||||
| 670 | * Check UID for matches. |
||||
| 671 | */ |
||||
| 672 | protected function uidCheck(object $release, bool $echo, string $type, bool $nameStatus, bool $show): bool |
||||
| 673 | { |
||||
| 674 | if (empty($release->uid)) { |
||||
| 675 | $this->updateService->updateSingleColumn('proc_uid', self::PROC_UID_DONE, $release->releases_id); |
||||
| 676 | return false; |
||||
| 677 | } |
||||
| 678 | |||||
| 679 | $result = Release::fromQuery(sprintf( |
||||
| 680 | 'SELECT r.id AS releases_id, r.size AS relsize, r.name AS textstring, r.searchname, r.fromname, r.predb_id |
||||
| 681 | FROM releases r |
||||
| 682 | LEFT JOIN media_infos ru ON ru.releases_id = r.id |
||||
| 683 | WHERE ru.releases_id IS NOT NULL |
||||
| 684 | AND ru.unique_id = %s |
||||
| 685 | AND ru.releases_id != %d |
||||
| 686 | AND (r.predb_id > 0 OR r.anidbid > 0 OR r.fromname = %s)', |
||||
| 687 | escapeString($release->uid), |
||||
| 688 | $release->releases_id, |
||||
| 689 | escapeString('[email protected] (EF)') |
||||
| 690 | )); |
||||
| 691 | |||||
| 692 | foreach ($result as $res) { |
||||
| 693 | $floor = round(($res->relsize - $release->relsize) / $res->relsize * 100, 1); |
||||
| 694 | if ($floor >= -10 && $floor <= 10) { |
||||
| 695 | $this->updateService->updateRelease( |
||||
| 696 | $release, |
||||
| 697 | $res->searchname, |
||||
| 698 | 'uidCheck: Unique_ID', |
||||
| 699 | $echo, |
||||
| 700 | $type, |
||||
| 701 | $nameStatus, |
||||
| 702 | $show, |
||||
| 703 | $res->predb_id |
||||
| 704 | ); |
||||
| 705 | return true; |
||||
| 706 | } |
||||
| 707 | } |
||||
| 708 | |||||
| 709 | $this->updateService->updateSingleColumn('proc_uid', self::PROC_UID_DONE, $release->releases_id); |
||||
| 710 | return false; |
||||
| 711 | } |
||||
| 712 | |||||
| 713 | /** |
||||
| 714 | * Check PAR2 hash for matches. |
||||
| 715 | */ |
||||
| 716 | protected function hashCheck(object $release, bool $echo, string $type, bool $nameStatus, bool $show): bool |
||||
| 717 | { |
||||
| 718 | $result = Release::fromQuery(sprintf( |
||||
| 719 | 'SELECT r.id AS releases_id, r.size AS relsize, r.name AS textstring, r.searchname, r.fromname, r.predb_id |
||||
| 720 | FROM releases r |
||||
| 721 | LEFT JOIN par_hashes ph ON ph.releases_id = r.id |
||||
| 722 | WHERE ph.hash = %s |
||||
| 723 | AND ph.releases_id != %d |
||||
| 724 | AND (r.predb_id > 0 OR r.anidbid > 0)', |
||||
| 725 | escapeString($release->hash), |
||||
| 726 | $release->releases_id |
||||
| 727 | )); |
||||
| 728 | |||||
| 729 | foreach ($result as $res) { |
||||
| 730 | $floor = round(($res->relsize - $release->relsize) / $res->relsize * 100, 1); |
||||
| 731 | if ($floor >= -5 && $floor <= 5) { |
||||
| 732 | $this->updateService->updateRelease( |
||||
| 733 | $release, |
||||
| 734 | $res->searchname, |
||||
| 735 | 'hashCheck: PAR2 hash_16K', |
||||
| 736 | $echo, |
||||
| 737 | $type, |
||||
| 738 | $nameStatus, |
||||
| 739 | $show, |
||||
| 740 | $res->predb_id |
||||
| 741 | ); |
||||
| 742 | return true; |
||||
| 743 | } |
||||
| 744 | } |
||||
| 745 | |||||
| 746 | $this->updateService->updateSingleColumn('proc_hash16k', self::PROC_HASH16K_DONE, $release->releases_id); |
||||
| 747 | return false; |
||||
| 748 | } |
||||
| 749 | |||||
| 750 | /** |
||||
| 751 | * Check PreDB for filename matches. |
||||
| 752 | */ |
||||
| 753 | protected function preDbFileCheck(object $release, bool $echo, string $type, bool $nameStatus, bool $show): bool |
||||
| 754 | { |
||||
| 755 | $fileName = $this->fileNameCleaner->cleanForMatching($release->textstring); |
||||
| 756 | |||||
| 757 | if (empty($fileName)) { |
||||
| 758 | return false; |
||||
| 759 | } |
||||
| 760 | |||||
| 761 | if (config('nntmux.elasticsearch_enabled') === true) { |
||||
| 762 | $results = $this->elasticsearch->searchPreDb($fileName); |
||||
| 763 | foreach ($results as $hit) { |
||||
| 764 | if (!empty($hit)) { |
||||
| 765 | $this->updateService->updateRelease( |
||||
| 766 | $release, |
||||
| 767 | $hit['title'], |
||||
| 768 | 'PreDb: Filename match', |
||||
| 769 | $echo, |
||||
| 770 | $type, |
||||
| 771 | $nameStatus, |
||||
| 772 | $show, |
||||
| 773 | $hit['id'] |
||||
| 774 | ); |
||||
| 775 | return true; |
||||
| 776 | } |
||||
| 777 | } |
||||
| 778 | } else { |
||||
| 779 | $predbSearch = Arr::get($this->manticore->searchIndexes('predb_rt', $fileName, ['filename', 'title']), 'data'); |
||||
| 780 | if (!empty($predbSearch)) { |
||||
| 781 | foreach ($predbSearch as $hit) { |
||||
| 782 | if (!empty($hit)) { |
||||
| 783 | $this->updateService->updateRelease( |
||||
| 784 | $release, |
||||
| 785 | $hit['title'], |
||||
| 786 | 'PreDb: Filename match', |
||||
| 787 | $echo, |
||||
| 788 | $type, |
||||
| 789 | $nameStatus, |
||||
| 790 | $show |
||||
| 791 | ); |
||||
| 792 | return true; |
||||
| 793 | } |
||||
| 794 | } |
||||
| 795 | } |
||||
| 796 | } |
||||
| 797 | |||||
| 798 | return false; |
||||
| 799 | } |
||||
| 800 | |||||
| 801 | /** |
||||
| 802 | * Check PreDB for title matches. |
||||
| 803 | */ |
||||
| 804 | protected function preDbTitleCheck(object $release, bool $echo, string $type, bool $nameStatus, bool $show): bool |
||||
| 805 | { |
||||
| 806 | $fileName = $this->fileNameCleaner->cleanForMatching($release->textstring); |
||||
| 807 | |||||
| 808 | if (empty($fileName)) { |
||||
| 809 | return false; |
||||
| 810 | } |
||||
| 811 | |||||
| 812 | if (config('nntmux.elasticsearch_enabled') === true) { |
||||
| 813 | $results = $this->elasticsearch->searchPreDb($fileName); |
||||
| 814 | foreach ($results as $hit) { |
||||
| 815 | if (!empty($hit)) { |
||||
| 816 | $this->updateService->updateRelease( |
||||
| 817 | $release, |
||||
| 818 | $hit['title'], |
||||
| 819 | 'PreDb: Title match', |
||||
| 820 | $echo, |
||||
| 821 | $type, |
||||
| 822 | $nameStatus, |
||||
| 823 | $show, |
||||
| 824 | $hit['id'] |
||||
| 825 | ); |
||||
| 826 | return true; |
||||
| 827 | } |
||||
| 828 | } |
||||
| 829 | } else { |
||||
| 830 | $results = Arr::get($this->manticore->searchIndexes('predb_rt', $fileName, ['title']), 'data'); |
||||
| 831 | if (!empty($results)) { |
||||
| 832 | foreach ($results as $hit) { |
||||
| 833 | if (!empty($hit)) { |
||||
| 834 | $this->updateService->updateRelease( |
||||
| 835 | $release, |
||||
| 836 | $hit['title'], |
||||
| 837 | 'PreDb: Title match', |
||||
| 838 | $echo, |
||||
| 839 | $type, |
||||
| 840 | $nameStatus, |
||||
| 841 | $show |
||||
| 842 | ); |
||||
| 843 | return true; |
||||
| 844 | } |
||||
| 845 | } |
||||
| 846 | } |
||||
| 847 | } |
||||
| 848 | |||||
| 849 | return false; |
||||
| 850 | } |
||||
| 851 | |||||
| 852 | /** |
||||
| 853 | * Get releases based on time and category parameters. |
||||
| 854 | */ |
||||
| 855 | protected function getReleases(int $time, int $cats, string $query, int $limit = 0): \Illuminate\Database\Eloquent\Collection|bool |
||||
| 856 | { |
||||
| 857 | $releases = false; |
||||
| 858 | $queryLimit = ($limit === 0) ? '' : ' LIMIT ' . $limit; |
||||
| 859 | |||||
| 860 | if ($time === 1 && $cats === 1) { |
||||
| 861 | $releases = Release::fromQuery($query . $this->timeother . $queryLimit); |
||||
| 862 | } |
||||
| 863 | if ($time === 1 && $cats === 2) { |
||||
| 864 | $releases = Release::fromQuery($query . $this->timeall . $queryLimit); |
||||
| 865 | } |
||||
| 866 | if ($time === 2 && $cats === 1) { |
||||
| 867 | $releases = Release::fromQuery($query . $this->fullother . $queryLimit); |
||||
| 868 | } |
||||
| 869 | if ($time === 2 && $cats === 2) { |
||||
| 870 | $releases = Release::fromQuery($query . $this->fullall . $queryLimit); |
||||
| 871 | } |
||||
| 872 | |||||
| 873 | return $releases; |
||||
| 874 | } |
||||
| 875 | |||||
| 876 | /** |
||||
| 877 | * Echo start message. |
||||
| 878 | */ |
||||
| 879 | protected function echoStartMessage(int $time, string $type): void |
||||
| 880 | { |
||||
| 881 | $this->colorCLI->info( |
||||
| 882 | sprintf( |
||||
| 883 | 'Fixing search names %s using %s.', |
||||
| 884 | ($time === 1 ? 'in the past 6 hours' : 'since the beginning'), |
||||
| 885 | $type |
||||
| 886 | ) |
||||
| 887 | ); |
||||
| 888 | } |
||||
| 889 | |||||
| 890 | /** |
||||
| 891 | * Echo found count. |
||||
| 892 | */ |
||||
| 893 | protected function echoFoundCount(bool $echo, string $type): void |
||||
| 894 | { |
||||
| 895 | $stats = $this->updateService->getStats(); |
||||
| 896 | if ($echo === true) { |
||||
| 897 | $this->colorCLI->info( |
||||
| 898 | PHP_EOL . |
||||
| 899 | number_format($stats['fixed']) . |
||||
| 900 | ' releases have had their names changed out of: ' . |
||||
| 901 | number_format($stats['checked']) . |
||||
| 902 | $type . '.' |
||||
| 903 | ); |
||||
| 904 | } else { |
||||
| 905 | $this->colorCLI->info( |
||||
| 906 | PHP_EOL . |
||||
| 907 | number_format($stats['fixed']) . |
||||
| 908 | ' releases could have their names changed. ' . |
||||
| 909 | number_format($stats['checked']) . |
||||
| 910 | $type . ' were checked.' |
||||
| 911 | ); |
||||
| 912 | } |
||||
| 913 | } |
||||
| 914 | |||||
| 915 | /** |
||||
| 916 | * Echo renamed progress. |
||||
| 917 | */ |
||||
| 918 | protected function echoRenamed(bool $show): void |
||||
| 919 | { |
||||
| 920 | $stats = $this->updateService->getStats(); |
||||
| 921 | |||||
| 922 | // Show milestone message every 500 releases |
||||
| 923 | if ($stats['checked'] % 500 === 0 && $stats['checked'] > 0) { |
||||
| 924 | $this->colorCLI->alternate(PHP_EOL . number_format($stats['checked']) . ' files processed.' . PHP_EOL); |
||||
| 925 | } |
||||
| 926 | |||||
| 927 | // Show active counter on the same line (overwrites previous) |
||||
| 928 | if ($show === true) { |
||||
| 929 | $percent = $this->_totalReleases > 0 |
||||
| 930 | ? round(($stats['checked'] / $this->_totalReleases) * 100, 1) |
||||
| 931 | : 0; |
||||
| 932 | |||||
| 933 | // Use carriage return to overwrite the same line |
||||
| 934 | echo "\rRenamed: " . number_format($stats['fixed']) . |
||||
| 935 | ' | Processed: ' . number_format($stats['checked']) . |
||||
| 936 | '/' . number_format($this->_totalReleases) . |
||||
| 937 | ' (' . $percent . '%) '; |
||||
| 938 | } |
||||
| 939 | } |
||||
| 940 | |||||
| 941 | /** |
||||
| 942 | * Get the update service. |
||||
| 943 | */ |
||||
| 944 | public function getUpdateService(): ReleaseUpdateService |
||||
| 945 | { |
||||
| 946 | return $this->updateService; |
||||
| 947 | } |
||||
| 948 | |||||
| 949 | /** |
||||
| 950 | * Get the checker service. |
||||
| 951 | */ |
||||
| 952 | public function getCheckerService(): NameCheckerService |
||||
| 953 | { |
||||
| 954 | return $this->checkerService; |
||||
| 955 | } |
||||
| 956 | |||||
| 957 | /** |
||||
| 958 | * Fix names using PAR2 files (requires NNTP connection). |
||||
| 959 | */ |
||||
| 960 | public function fixNamesWithPar2(int $time, bool $echo, int $cats, bool $nameStatus, bool $show, NNTPService $nntp): void |
||||
|
0 ignored issues
–
show
The parameter
$nntp is not used and could be removed.
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for parameters that have been defined for a function or method, but which are not used in the method body. Loading history...
|
|||||
| 961 | { |
||||
| 962 | $this->echoStartMessage($time, 'par2 files'); |
||||
| 963 | |||||
| 964 | if ($cats === 3) { |
||||
| 965 | $query = sprintf( |
||||
| 966 | 'SELECT rel.id AS releases_id, rel.guid, rel.groups_id, rel.fromname |
||||
| 967 | FROM releases rel |
||||
| 968 | WHERE rel.predb_id = 0' |
||||
| 969 | ); |
||||
| 970 | $cats = 2; |
||||
| 971 | } else { |
||||
| 972 | $query = sprintf( |
||||
| 973 | 'SELECT rel.id AS releases_id, rel.guid, rel.groups_id, rel.fromname |
||||
| 974 | FROM releases rel |
||||
| 975 | WHERE (rel.isrenamed = %d OR rel.categories_id IN (%d, %d)) |
||||
| 976 | AND rel.predb_id = 0 |
||||
| 977 | AND rel.proc_par2 = %d', |
||||
| 978 | self::IS_RENAMED_NONE, |
||||
| 979 | Category::OTHER_MISC, |
||||
| 980 | Category::OTHER_HASHED, |
||||
| 981 | self::PROC_PAR2_NONE |
||||
| 982 | ); |
||||
| 983 | } |
||||
| 984 | |||||
| 985 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 986 | $total = $releases ? $releases->count() : 0; |
||||
| 987 | |||||
| 988 | if ($total > 0) { |
||||
| 989 | $this->_totalReleases = $total; |
||||
| 990 | $this->colorCLI->info(number_format($total) . ' releases to process.'); |
||||
| 991 | $nzbContents = new \Blacklight\NZBContents(); |
||||
| 992 | |||||
| 993 | foreach ($releases as $release) { |
||||
| 994 | if ($nzbContents->checkPAR2($release->guid, $release->releases_id, $release->groups_id, (int) $nameStatus, (int) $show)) { |
||||
| 995 | $this->updateService->fixed++; |
||||
| 996 | } |
||||
| 997 | |||||
| 998 | $this->updateService->incrementChecked(); |
||||
| 999 | $this->echoRenamed($show); |
||||
| 1000 | } |
||||
| 1001 | $this->echoFoundCount($echo, ' files'); |
||||
| 1002 | } else { |
||||
| 1003 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 1004 | } |
||||
| 1005 | } |
||||
| 1006 | |||||
| 1007 | /** |
||||
| 1008 | * Fix XXX release names using specific file names. |
||||
| 1009 | */ |
||||
| 1010 | public function fixXXXNamesWithFiles(int $time, bool $echo, int $cats, bool $nameStatus, bool $show): void |
||||
| 1011 | { |
||||
| 1012 | $this->echoStartMessage($time, 'file names'); |
||||
| 1013 | $type = 'Filenames, '; |
||||
| 1014 | |||||
| 1015 | if ($cats === 3) { |
||||
| 1016 | $query = sprintf( |
||||
| 1017 | 'SELECT rf.name AS textstring, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, |
||||
| 1018 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 1019 | FROM releases rel |
||||
| 1020 | INNER JOIN release_files rf ON rf.releases_id = rel.id |
||||
| 1021 | WHERE predb_id = 0' |
||||
| 1022 | ); |
||||
| 1023 | $cats = 2; |
||||
| 1024 | } else { |
||||
| 1025 | $query = sprintf( |
||||
| 1026 | 'SELECT rf.name AS textstring, rel.categories_id, rel.name, rel.searchname, rel.fromname, rel.groups_id, |
||||
| 1027 | rf.releases_id AS fileid, rel.id AS releases_id |
||||
| 1028 | FROM releases rel |
||||
| 1029 | INNER JOIN release_files rf ON rf.releases_id = rel.id |
||||
| 1030 | WHERE (rel.isrenamed = %d OR rel.categories_id IN (%d, %d)) |
||||
| 1031 | AND rel.predb_id = 0 |
||||
| 1032 | AND rf.name LIKE %s', |
||||
| 1033 | self::IS_RENAMED_NONE, |
||||
| 1034 | Category::OTHER_MISC, |
||||
| 1035 | Category::OTHER_HASHED, |
||||
| 1036 | escapeString('%SDPORN%') |
||||
| 1037 | ); |
||||
| 1038 | } |
||||
| 1039 | |||||
| 1040 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 1041 | $total = $releases ? $releases->count() : 0; |
||||
| 1042 | |||||
| 1043 | if ($total > 0) { |
||||
| 1044 | $this->_totalReleases = $total; |
||||
| 1045 | $this->colorCLI->info(number_format($total) . ' xxx file names to process.'); |
||||
| 1046 | |||||
| 1047 | foreach ($releases as $release) { |
||||
| 1048 | $this->updateService->reset(); |
||||
| 1049 | $this->xxxNameCheck($release, $echo, $type, $nameStatus, $show); |
||||
| 1050 | $this->updateService->incrementChecked(); |
||||
| 1051 | $this->echoRenamed($show); |
||||
| 1052 | } |
||||
| 1053 | $this->echoFoundCount($echo, ' files'); |
||||
| 1054 | } else { |
||||
| 1055 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 1056 | } |
||||
| 1057 | } |
||||
| 1058 | |||||
| 1059 | /** |
||||
| 1060 | * Fix release names using mediainfo movie_name. |
||||
| 1061 | */ |
||||
| 1062 | public function fixNamesWithMediaMovieName(int $time, bool $echo, int $cats, bool $nameStatus, bool $show): void |
||||
| 1063 | { |
||||
| 1064 | $type = 'Mediainfo, '; |
||||
| 1065 | $this->echoStartMessage($time, 'Mediainfo movie_name'); |
||||
| 1066 | |||||
| 1067 | if ($cats === 3) { |
||||
| 1068 | $query = sprintf( |
||||
| 1069 | 'SELECT rel.id AS releases_id, rel.name, rel.name AS textstring, rel.predb_id, rel.searchname, rel.fromname, rel.groups_id, rel.categories_id, rel.id AS releases_id, rf.movie_name as movie_name |
||||
| 1070 | FROM releases rel |
||||
| 1071 | INNER JOIN media_infos rf ON rf.releases_id = rel.id |
||||
| 1072 | WHERE rel.predb_id = 0' |
||||
| 1073 | ); |
||||
| 1074 | $cats = 2; |
||||
| 1075 | } else { |
||||
| 1076 | $query = sprintf( |
||||
| 1077 | 'SELECT rel.id AS releases_id, rel.name, rel.name AS textstring, rel.predb_id, rel.searchname, rel.fromname, rel.groups_id, rel.categories_id, rel.id AS releases_id, rf.movie_name as movie_name, rf.file_name as file_name |
||||
| 1078 | FROM releases rel |
||||
| 1079 | INNER JOIN media_infos rf ON rf.releases_id = rel.id |
||||
| 1080 | WHERE rel.isrenamed = %d |
||||
| 1081 | AND rel.predb_id = 0', |
||||
| 1082 | self::IS_RENAMED_NONE |
||||
| 1083 | ); |
||||
| 1084 | if ($cats === 2) { |
||||
| 1085 | $query .= PHP_EOL . 'AND rel.categories_id IN (' . Category::OTHER_MISC . ',' . Category::OTHER_HASHED . ')'; |
||||
| 1086 | } |
||||
| 1087 | } |
||||
| 1088 | |||||
| 1089 | $releases = $this->getReleases($time, $cats, $query); |
||||
| 1090 | $total = $releases ? $releases->count() : 0; |
||||
| 1091 | |||||
| 1092 | if ($total > 0) { |
||||
| 1093 | $this->_totalReleases = $total; |
||||
| 1094 | $this->colorCLI->info(number_format($total) . ' mediainfo movie names to process.'); |
||||
| 1095 | |||||
| 1096 | foreach ($releases as $rel) { |
||||
| 1097 | $this->updateService->incrementChecked(); |
||||
| 1098 | $this->updateService->reset(); |
||||
| 1099 | $this->mediaMovieNameCheck($rel, $echo, $type, $nameStatus, $show); |
||||
| 1100 | $this->echoRenamed($show); |
||||
| 1101 | } |
||||
| 1102 | $this->echoFoundCount($echo, ' MediaInfo\'s'); |
||||
| 1103 | } else { |
||||
| 1104 | $this->colorCLI->info('Nothing to fix.'); |
||||
| 1105 | } |
||||
| 1106 | } |
||||
| 1107 | |||||
| 1108 | /** |
||||
| 1109 | * Check for XXX release name. |
||||
| 1110 | */ |
||||
| 1111 | protected function xxxNameCheck(object $release, bool $echo, string $type, bool $nameStatus, bool $show): bool |
||||
| 1112 | { |
||||
| 1113 | if (preg_match('/^.+?SDPORN/i', $release->textstring, $hit)) { |
||||
| 1114 | $this->updateService->updateRelease($release, $hit[0], 'fileCheck: XXX SDPORN', $echo, $type, $nameStatus, $show); |
||||
| 1115 | return true; |
||||
| 1116 | } |
||||
| 1117 | |||||
| 1118 | $this->updateService->updateSingleColumn('proc_files', self::PROC_FILES_DONE, $release->releases_id); |
||||
| 1119 | return false; |
||||
| 1120 | } |
||||
| 1121 | |||||
| 1122 | /** |
||||
| 1123 | * Check mediainfo movie_name for release name. |
||||
| 1124 | */ |
||||
| 1125 | protected function mediaMovieNameCheck(object $release, bool $echo, string $type, bool $nameStatus, bool $show): bool |
||||
| 1126 | { |
||||
| 1127 | $newName = ''; |
||||
| 1128 | |||||
| 1129 | if (!empty($release->movie_name)) { |
||||
| 1130 | if (preg_match(ReleaseUpdateService::PREDB_REGEX, $release->movie_name, $hit)) { |
||||
| 1131 | $newName = $hit[1]; |
||||
| 1132 | } elseif (preg_match('/(.+),(\sRMZ\.cr)?$/i', $release->movie_name, $hit)) { |
||||
| 1133 | $newName = $hit[1]; |
||||
| 1134 | } else { |
||||
| 1135 | $newName = $release->movie_name; |
||||
| 1136 | } |
||||
| 1137 | } |
||||
| 1138 | |||||
| 1139 | if ($newName !== '') { |
||||
| 1140 | $this->updateService->updateRelease($release, $newName, 'MediaInfo: Movie Name', $echo, $type, $nameStatus, $show, $release->predb_id ?? 0); |
||||
| 1141 | return true; |
||||
| 1142 | } |
||||
| 1143 | |||||
| 1144 | $this->updateService->updateSingleColumn('proc_uid', self::PROC_UID_DONE, $release->releases_id); |
||||
| 1145 | return false; |
||||
| 1146 | } |
||||
| 1147 | |||||
| 1148 | /** |
||||
| 1149 | * Check the array using regex for a clean name. |
||||
| 1150 | * |
||||
| 1151 | * @throws \Exception |
||||
| 1152 | */ |
||||
| 1153 | public function checkName(object $release, bool $echo, string $type, bool $nameStatus, bool $show, bool $preId = false): bool |
||||
| 1154 | { |
||||
| 1155 | // Check PreDB first |
||||
| 1156 | $preDbMatch = $this->updateService->checkPreDbMatch($release, $release->textstring); |
||||
| 1157 | if ($preDbMatch !== null) { |
||||
| 1158 | $this->updateService->updateRelease($release, $preDbMatch['title'], 'preDB: Match', $echo, $type, $nameStatus, $show, $preDbMatch['id']); |
||||
| 1159 | return true; |
||||
| 1160 | } |
||||
| 1161 | |||||
| 1162 | if ($preId) { |
||||
| 1163 | return $this->updateService->matched; |
||||
| 1164 | } |
||||
| 1165 | |||||
| 1166 | // Route to appropriate checker based on type |
||||
| 1167 | switch ($type) { |
||||
| 1168 | case 'PAR2, ': |
||||
| 1169 | $result = $this->fileExtractor->extractFromFile($release->textstring); |
||||
| 1170 | if ($result !== null) { |
||||
| 1171 | $this->updateService->updateRelease($release, $result->newName, 'fileCheck: ' . $result->method, $echo, $type, $nameStatus, $show); |
||||
| 1172 | } |
||||
| 1173 | break; |
||||
| 1174 | |||||
| 1175 | case 'NFO, ': |
||||
| 1176 | $result = $this->nfoExtractor->extractFromNfo($release->textstring); |
||||
| 1177 | if ($result !== null) { |
||||
| 1178 | $this->updateService->updateRelease($release, $result->newName, 'nfoCheck: ' . $result->method, $echo, $type, $nameStatus, $show); |
||||
| 1179 | } |
||||
| 1180 | break; |
||||
| 1181 | |||||
| 1182 | case 'Filenames, ': |
||||
| 1183 | // Try PreDB file check |
||||
| 1184 | if (!$this->updateService->matched) { |
||||
| 1185 | $this->preDbFileCheck($release, $echo, $type, $nameStatus, $show); |
||||
| 1186 | } |
||||
| 1187 | // Try PreDB title check |
||||
| 1188 | if (!$this->updateService->matched) { |
||||
| 1189 | $this->preDbTitleCheck($release, $echo, $type, $nameStatus, $show); |
||||
| 1190 | } |
||||
| 1191 | // Try file name extraction |
||||
| 1192 | if (!$this->updateService->matched) { |
||||
| 1193 | $result = $this->fileExtractor->extractFromFile($release->textstring); |
||||
| 1194 | if ($result !== null) { |
||||
| 1195 | $this->updateService->updateRelease($release, $result->newName, 'fileCheck: ' . $result->method, $echo, $type, $nameStatus, $show); |
||||
| 1196 | } |
||||
| 1197 | } |
||||
| 1198 | break; |
||||
| 1199 | |||||
| 1200 | default: |
||||
| 1201 | // Use pattern checker service |
||||
| 1202 | $result = $this->checkerService->check($release, $release->textstring); |
||||
| 1203 | if ($result !== null) { |
||||
| 1204 | $this->updateService->updateRelease($release, $result->newName, $result->getFormattedMethod(), $echo, $type, $nameStatus, $show); |
||||
| 1205 | } |
||||
| 1206 | } |
||||
| 1207 | |||||
| 1208 | // Update processing flags if not matched |
||||
| 1209 | if ($nameStatus === true && !$this->updateService->matched) { |
||||
| 1210 | $this->updateProcessingFlags($type, $release->releases_id); |
||||
| 1211 | } |
||||
| 1212 | |||||
| 1213 | return $this->updateService->matched; |
||||
| 1214 | } |
||||
| 1215 | |||||
| 1216 | /** |
||||
| 1217 | * Update processing flags based on type. |
||||
| 1218 | */ |
||||
| 1219 | protected function updateProcessingFlags(string $type, int $releaseId): void |
||||
| 1220 | { |
||||
| 1221 | switch ($type) { |
||||
| 1222 | case 'NFO, ': |
||||
| 1223 | $this->updateService->updateSingleColumn('proc_nfo', self::PROC_NFO_DONE, $releaseId); |
||||
| 1224 | break; |
||||
| 1225 | case 'Filenames, ': |
||||
| 1226 | $this->updateService->updateSingleColumn('proc_files', self::PROC_FILES_DONE, $releaseId); |
||||
| 1227 | break; |
||||
| 1228 | case 'PAR2, ': |
||||
| 1229 | $this->updateService->updateSingleColumn('proc_par2', self::PROC_PAR2_DONE, $releaseId); |
||||
| 1230 | break; |
||||
| 1231 | case 'PAR2 hash, ': |
||||
| 1232 | $this->updateService->updateSingleColumn('proc_hash16k', self::PROC_HASH16K_DONE, $releaseId); |
||||
| 1233 | break; |
||||
| 1234 | case 'SRR, ': |
||||
| 1235 | $this->updateService->updateSingleColumn('proc_srr', self::PROC_SRR_DONE, $releaseId); |
||||
| 1236 | break; |
||||
| 1237 | case 'UID, ': |
||||
| 1238 | case 'Mediainfo, ': |
||||
| 1239 | $this->updateService->updateSingleColumn('proc_uid', self::PROC_UID_DONE, $releaseId); |
||||
| 1240 | break; |
||||
| 1241 | case 'CRC32, ': |
||||
| 1242 | $this->updateService->updateSingleColumn('proc_crc32', self::PROC_CRC_DONE, $releaseId); |
||||
| 1243 | break; |
||||
| 1244 | } |
||||
| 1245 | } |
||||
| 1246 | |||||
| 1247 | /** |
||||
| 1248 | * Match a release filename to a PreDB filename or title. |
||||
| 1249 | * |
||||
| 1250 | * @throws \Exception |
||||
| 1251 | */ |
||||
| 1252 | public function matchPreDbFiles(object $release, bool $echo, bool $nameStatus, bool $show): int |
||||
| 1253 | { |
||||
| 1254 | $matching = 0; |
||||
| 1255 | |||||
| 1256 | $files = explode('||', $release->filename ?? ''); |
||||
| 1257 | $prioritizedFiles = $this->filePrioritizer->prioritizeForPreDb($files); |
||||
| 1258 | |||||
| 1259 | foreach ($prioritizedFiles as $fileName) { |
||||
| 1260 | $cleanedFileName = $this->fileNameCleaner->cleanForMatching($fileName); |
||||
| 1261 | |||||
| 1262 | if (empty($cleanedFileName) || strlen($cleanedFileName) < 8) { |
||||
| 1263 | continue; |
||||
| 1264 | } |
||||
| 1265 | |||||
| 1266 | $preMatch = $this->preMatch($cleanedFileName); |
||||
| 1267 | if ($preMatch[0] === true) { |
||||
| 1268 | if (config('nntmux.elasticsearch_enabled') === true) { |
||||
| 1269 | $results = $this->elasticsearch->searchPreDb($preMatch[1]); |
||||
| 1270 | } else { |
||||
| 1271 | $results = Arr::get($this->manticore->searchIndexes('predb_rt', $preMatch[1], ['filename', 'title']), 'data'); |
||||
| 1272 | } |
||||
| 1273 | |||||
| 1274 | if (!empty($results)) { |
||||
| 1275 | foreach ($results as $result) { |
||||
| 1276 | if (!empty($result)) { |
||||
| 1277 | $preFtMatch = $this->preMatch($result['filename'] ?? ''); |
||||
| 1278 | if ($preFtMatch[0] === true) { |
||||
| 1279 | if ($result['title'] !== $release->searchname) { |
||||
| 1280 | $this->updateService->updateRelease($release, $result['title'], 'file matched source: ' . $result['source'], $echo, 'PreDB file match, ', $nameStatus, $show); |
||||
| 1281 | } else { |
||||
| 1282 | $this->updateService->updateSingleColumn('predb_id', $result['id'], $release->releases_id); |
||||
| 1283 | } |
||||
| 1284 | $matching++; |
||||
| 1285 | return $matching; |
||||
| 1286 | } |
||||
| 1287 | } |
||||
| 1288 | } |
||||
| 1289 | } |
||||
| 1290 | } |
||||
| 1291 | } |
||||
| 1292 | |||||
| 1293 | return $matching; |
||||
| 1294 | } |
||||
| 1295 | |||||
| 1296 | /** |
||||
| 1297 | * Pre-match check for filename patterns. |
||||
| 1298 | */ |
||||
| 1299 | protected function preMatch(string $fileName): array |
||||
| 1300 | { |
||||
| 1301 | $result = preg_match('/(\d{2}\.\d{2}\.\d{2})+([\w\-.]+[\w]$)/i', $fileName, $hit); |
||||
| 1302 | return [$result === 1, $hit[0] ?? '']; |
||||
| 1303 | } |
||||
| 1304 | |||||
| 1305 | /** |
||||
| 1306 | * Check if a release name looks like a season pack. |
||||
| 1307 | */ |
||||
| 1308 | public function isSeasonPack(string $name): bool |
||||
| 1309 | { |
||||
| 1310 | // Season pack pattern: S01 without E01 |
||||
| 1311 | return (bool) preg_match('/S\d{1,2}(?!E\d)/i', $name); |
||||
| 1312 | } |
||||
| 1313 | |||||
| 1314 | /** |
||||
| 1315 | * Reset the update service state. |
||||
| 1316 | */ |
||||
| 1317 | public function reset(): void |
||||
| 1318 | { |
||||
| 1319 | $this->updateService->reset(); |
||||
| 1320 | } |
||||
| 1321 | |||||
| 1322 | /** |
||||
| 1323 | * Retrieves releases and their file names to attempt PreDB matches. |
||||
| 1324 | * |
||||
| 1325 | * @throws \Exception |
||||
| 1326 | */ |
||||
| 1327 | public function getPreFileNames(array $args = []): void |
||||
| 1328 | { |
||||
| 1329 | $show = isset($args[2]) && $args[2] === 'show'; |
||||
| 1330 | |||||
| 1331 | if (isset($args[1]) && is_numeric($args[1])) { |
||||
| 1332 | $limit = 'LIMIT ' . $args[1]; |
||||
| 1333 | $orderBy = 'ORDER BY r.id DESC'; |
||||
| 1334 | } else { |
||||
| 1335 | $orderBy = 'ORDER BY r.id ASC'; |
||||
| 1336 | $limit = 'LIMIT 1000000'; |
||||
| 1337 | } |
||||
| 1338 | |||||
| 1339 | $this->colorCLI->info(PHP_EOL . 'Match PreFiles ' . ($args[1] ?? 'all') . ' Started at ' . now()); |
||||
| 1340 | $this->colorCLI->info('Matching predb filename to cleaned release_files.name.'); |
||||
| 1341 | |||||
| 1342 | $counter = $counted = 0; |
||||
| 1343 | $timeStart = now(); |
||||
| 1344 | |||||
| 1345 | $query = Release::fromQuery( |
||||
| 1346 | sprintf( |
||||
| 1347 | "SELECT r.id AS releases_id, r.name, r.searchname, |
||||
| 1348 | r.fromname, r.groups_id, r.categories_id, |
||||
| 1349 | GROUP_CONCAT(rf.name ORDER BY LENGTH(rf.name) DESC SEPARATOR '||') AS filename |
||||
| 1350 | FROM releases r |
||||
| 1351 | INNER JOIN release_files rf ON r.id = rf.releases_id |
||||
| 1352 | WHERE rf.name IS NOT NULL |
||||
| 1353 | AND r.predb_id = 0 |
||||
| 1354 | AND r.categories_id IN (%s) |
||||
| 1355 | AND r.isrenamed = 0 |
||||
| 1356 | GROUP BY r.id |
||||
| 1357 | %s %s", |
||||
| 1358 | implode(',', Category::OTHERS_GROUP), |
||||
| 1359 | $orderBy, |
||||
| 1360 | $limit |
||||
| 1361 | ) |
||||
| 1362 | ); |
||||
| 1363 | |||||
| 1364 | if ($query->isNotEmpty()) { |
||||
| 1365 | $total = $query->count(); |
||||
| 1366 | |||||
| 1367 | if ($total > 0) { |
||||
| 1368 | $this->colorCLI->info(PHP_EOL . number_format($total) . ' releases to process.'); |
||||
| 1369 | |||||
| 1370 | foreach ($query as $row) { |
||||
| 1371 | $success = $this->matchPreDbFiles($row, true, true, $show); |
||||
| 1372 | if ($success === 1) { |
||||
| 1373 | $counted++; |
||||
| 1374 | } |
||||
| 1375 | if ($show === false) { |
||||
| 1376 | $this->colorCLI->info('Renamed Releases: [' . number_format($counted) . '] ' . (new ColorCLI())->percentString(++$counter, $total)); |
||||
| 1377 | } |
||||
| 1378 | } |
||||
| 1379 | $this->colorCLI->info(PHP_EOL . 'Renamed ' . number_format($counted) . ' releases in ' . now()->diffInSeconds($timeStart, true) . ' seconds.'); |
||||
| 1380 | } else { |
||||
| 1381 | $this->colorCLI->info('Nothing to do.'); |
||||
| 1382 | } |
||||
| 1383 | } |
||||
| 1384 | } |
||||
| 1385 | } |
||||
| 1386 |