NNTmux /
newznab-tmux
| 1 | <?php |
||||
| 2 | |||||
| 3 | namespace App\Services; |
||||
| 4 | |||||
| 5 | use App\Models\BookInfo; |
||||
| 6 | use App\Models\Category; |
||||
| 7 | use App\Models\Release; |
||||
| 8 | use App\Models\Settings; |
||||
| 9 | use Blacklight\ColorCLI; |
||||
| 10 | use Illuminate\Database\Eloquent\Model; |
||||
| 11 | use Illuminate\Support\Facades\Cache; |
||||
| 12 | use Illuminate\Support\Facades\DB; |
||||
| 13 | |||||
| 14 | /** |
||||
| 15 | * Service class for book data fetching and processing. |
||||
| 16 | */ |
||||
| 17 | class BookService |
||||
| 18 | { |
||||
| 19 | public bool $echooutput; |
||||
| 20 | |||||
| 21 | public ?string $pubkey; |
||||
| 22 | |||||
| 23 | public ?string $privkey; |
||||
| 24 | |||||
| 25 | public ?string $asstag; |
||||
| 26 | |||||
| 27 | public int $bookqty; |
||||
| 28 | |||||
| 29 | public int $sleeptime; |
||||
| 30 | |||||
| 31 | public string $imgSavePath; |
||||
| 32 | |||||
| 33 | public ?string $bookreqids; |
||||
| 34 | |||||
| 35 | public string $renamed; |
||||
| 36 | |||||
| 37 | public array $failCache; |
||||
| 38 | |||||
| 39 | protected ColorCLI $colorCli; |
||||
| 40 | |||||
| 41 | /** |
||||
| 42 | * @throws \Exception |
||||
| 43 | */ |
||||
| 44 | public function __construct() |
||||
| 45 | { |
||||
| 46 | $this->echooutput = config('nntmux.echocli'); |
||||
| 47 | $this->colorCli = new ColorCLI; |
||||
| 48 | |||||
| 49 | $this->pubkey = Settings::settingValue('amazonpubkey'); |
||||
| 50 | $this->privkey = Settings::settingValue('amazonprivkey'); |
||||
| 51 | $this->asstag = Settings::settingValue('amazonassociatetag'); |
||||
| 52 | $this->bookqty = Settings::settingValue('maxbooksprocessed') !== '' ? (int) Settings::settingValue('maxbooksprocessed') : 300; |
||||
| 53 | $this->sleeptime = Settings::settingValue('amazonsleep') !== '' ? (int) Settings::settingValue('amazonsleep') : 1000; |
||||
| 54 | $this->imgSavePath = storage_path('covers/book/'); |
||||
| 55 | |||||
| 56 | $this->bookreqids = Category::BOOKS_EBOOK; |
||||
| 57 | $this->renamed = (int) Settings::settingValue('lookupbooks') === 2 ? 'AND isrenamed = 1' : ''; |
||||
| 58 | |||||
| 59 | $this->failCache = []; |
||||
| 60 | } |
||||
| 61 | |||||
| 62 | /** |
||||
| 63 | * Get book info by ID. |
||||
| 64 | */ |
||||
| 65 | public function getBookInfo(?int $id): ?Model |
||||
| 66 | { |
||||
| 67 | if ($id === null) { |
||||
| 68 | return null; |
||||
| 69 | } |
||||
| 70 | |||||
| 71 | return BookInfo::query()->where('id', $id)->first(); |
||||
| 72 | } |
||||
| 73 | |||||
| 74 | /** |
||||
| 75 | * Get book info by name using full-text search. |
||||
| 76 | */ |
||||
| 77 | public function getBookInfoByName(string $title): ?Model |
||||
| 78 | { |
||||
| 79 | $searchWords = ''; |
||||
| 80 | $title = preg_replace(['/( - | -|\(.+\)|\(|\))/', '/[^\w ]+/'], [' ', ''], $title); |
||||
| 81 | $title = trim(trim(preg_replace('/\s\s+/i', ' ', $title))); |
||||
| 82 | foreach (explode(' ', $title) as $word) { |
||||
| 83 | $word = trim(rtrim(trim($word), '-')); |
||||
| 84 | if ($word !== '' && $word !== '-') { |
||||
| 85 | $word = '+'.$word; |
||||
| 86 | $searchWords .= sprintf('%s ', $word); |
||||
| 87 | } |
||||
| 88 | } |
||||
| 89 | $searchWords = trim($searchWords); |
||||
| 90 | |||||
| 91 | return BookInfo::search($searchWords)->first(); |
||||
| 92 | } |
||||
| 93 | |||||
| 94 | /** |
||||
| 95 | * Get book range with pagination. |
||||
| 96 | */ |
||||
| 97 | public function getBookRange(int $page, array $cat, int $start, int $num, string $orderBy, array $excludedCats = []): array |
||||
| 98 | { |
||||
| 99 | $page = max(1, $page); |
||||
| 100 | $start = max(0, $start); |
||||
| 101 | |||||
| 102 | $browseby = $this->getBrowseBy(); |
||||
| 103 | $catsrch = ''; |
||||
| 104 | if (\count($cat) > 0 && $cat[0] !== -1) { |
||||
| 105 | $catsrch = Category::getCategorySearch($cat); |
||||
| 106 | } |
||||
| 107 | $exccatlist = ''; |
||||
| 108 | if (\count($excludedCats) > 0) { |
||||
| 109 | $exccatlist = ' AND r.categories_id NOT IN ('.implode(',', $excludedCats).')'; |
||||
| 110 | } |
||||
| 111 | $order = $this->getBookOrder($orderBy); |
||||
| 112 | $booksql = sprintf( |
||||
| 113 | " |
||||
| 114 | SELECT SQL_CALC_FOUND_ROWS boo.id, |
||||
| 115 | GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id |
||||
| 116 | FROM bookinfo boo |
||||
| 117 | LEFT JOIN releases r ON boo.id = r.bookinfo_id |
||||
| 118 | WHERE boo.cover = 1 |
||||
| 119 | AND boo.title != '' |
||||
| 120 | AND r.passwordstatus %s |
||||
| 121 | %s %s %s |
||||
| 122 | GROUP BY boo.id |
||||
| 123 | ORDER BY %s %s %s", |
||||
| 124 | app(\App\Services\Releases\ReleaseBrowseService::class)->showPasswords(), |
||||
| 125 | $browseby, |
||||
| 126 | $catsrch, |
||||
| 127 | $exccatlist, |
||||
| 128 | $order[0], |
||||
| 129 | $order[1], |
||||
| 130 | ($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start) |
||||
| 131 | ); |
||||
| 132 | $expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium')); |
||||
| 133 | $booksCache = Cache::get(md5($booksql.$page)); |
||||
| 134 | if ($booksCache !== null) { |
||||
| 135 | $books = $booksCache; |
||||
| 136 | } else { |
||||
| 137 | $data = DB::select($booksql); |
||||
| 138 | $books = ['total' => DB::select('SELECT FOUND_ROWS() AS total'), 'result' => $data]; |
||||
| 139 | Cache::put(md5($booksql.$page), $books, $expiresAt); |
||||
| 140 | } |
||||
| 141 | $bookIDs = $releaseIDs = []; |
||||
| 142 | if (\is_array($books['result'])) { |
||||
| 143 | foreach ($books['result'] as $book => $id) { |
||||
| 144 | $bookIDs[] = $id->id; |
||||
| 145 | $releaseIDs[] = $id->grp_release_id; |
||||
| 146 | } |
||||
| 147 | } |
||||
| 148 | $sql = sprintf( |
||||
| 149 | ' |
||||
| 150 | SELECT |
||||
| 151 | r.id, r.rarinnerfilecount, r.grabs, r.comments, r.totalpart, r.size, r.postdate, r.searchname, r.haspreview, r.passwordstatus, r.guid, df.failed AS failed, |
||||
| 152 | boo.*, |
||||
| 153 | r.bookinfo_id, |
||||
| 154 | g.name AS group_name, |
||||
| 155 | rn.releases_id AS nfoid |
||||
| 156 | FROM releases r |
||||
| 157 | LEFT OUTER JOIN usenet_groups g ON g.id = r.groups_id |
||||
| 158 | LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id |
||||
| 159 | LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id |
||||
| 160 | INNER JOIN bookinfo boo ON boo.id = r.bookinfo_id |
||||
| 161 | WHERE boo.id IN (%s) |
||||
| 162 | AND r.id IN (%s) |
||||
| 163 | %s |
||||
| 164 | GROUP BY boo.id |
||||
| 165 | ORDER BY %s %s', |
||||
| 166 | \is_array($bookIDs) && ! empty($bookIDs) ? implode(',', $bookIDs) : -1, |
||||
| 167 | \is_array($releaseIDs) && ! empty($releaseIDs) ? implode(',', $releaseIDs) : -1, |
||||
| 168 | $catsrch, |
||||
| 169 | $order[0], |
||||
| 170 | $order[1] |
||||
| 171 | ); |
||||
| 172 | $return = Cache::get(md5($sql.$page)); |
||||
| 173 | if ($return !== null) { |
||||
| 174 | return $return; |
||||
| 175 | } |
||||
| 176 | $return = DB::select($sql); |
||||
| 177 | if (\count($return) > 0) { |
||||
| 178 | $return[0]->_totalcount = $books['total'][0]->total ?? 0; |
||||
| 179 | } |
||||
| 180 | Cache::put(md5($sql.$page), $return, $expiresAt); |
||||
| 181 | |||||
| 182 | return $return; |
||||
| 183 | } |
||||
| 184 | |||||
| 185 | /** |
||||
| 186 | * Get book order array. |
||||
| 187 | */ |
||||
| 188 | public function getBookOrder(string $orderBy): array |
||||
| 189 | { |
||||
| 190 | $order = $orderBy === '' ? 'r.postdate' : $orderBy; |
||||
| 191 | $orderArr = explode('_', $order); |
||||
| 192 | $orderfield = match ($orderArr[0]) { |
||||
| 193 | 'title' => 'boo.title', |
||||
| 194 | 'author' => 'boo.author', |
||||
| 195 | 'publishdate' => 'boo.publishdate', |
||||
| 196 | 'size' => 'r.size', |
||||
| 197 | 'files' => 'r.totalpart', |
||||
| 198 | 'stats' => 'r.grabs', |
||||
| 199 | default => 'r.postdate', |
||||
| 200 | }; |
||||
| 201 | $ordersort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc'; |
||||
| 202 | |||||
| 203 | return [$orderfield, $ordersort]; |
||||
| 204 | } |
||||
| 205 | |||||
| 206 | /** |
||||
| 207 | * Get book ordering options. |
||||
| 208 | */ |
||||
| 209 | public function getBookOrdering(): array |
||||
| 210 | { |
||||
| 211 | return [ |
||||
| 212 | 'title_asc', |
||||
| 213 | 'title_desc', |
||||
| 214 | 'posted_asc', |
||||
| 215 | 'posted_desc', |
||||
| 216 | 'size_asc', |
||||
| 217 | 'size_desc', |
||||
| 218 | 'files_asc', |
||||
| 219 | 'files_desc', |
||||
| 220 | 'stats_asc', |
||||
| 221 | 'stats_desc', |
||||
| 222 | 'releasedate_asc', |
||||
| 223 | 'releasedate_desc', |
||||
| 224 | 'author_asc', |
||||
| 225 | 'author_desc', |
||||
| 226 | ]; |
||||
| 227 | } |
||||
| 228 | |||||
| 229 | /** |
||||
| 230 | * Get browse by options. |
||||
| 231 | */ |
||||
| 232 | public function getBrowseByOptions(): array |
||||
| 233 | { |
||||
| 234 | return ['author' => 'author', 'title' => 'title']; |
||||
| 235 | } |
||||
| 236 | |||||
| 237 | /** |
||||
| 238 | * Get browse by SQL clause. |
||||
| 239 | */ |
||||
| 240 | public function getBrowseBy(): string |
||||
| 241 | { |
||||
| 242 | $browseby = ' '; |
||||
| 243 | foreach ($this->getBrowseByOptions() as $bbk => $bbv) { |
||||
| 244 | if (! empty($_REQUEST[$bbk])) { |
||||
| 245 | $bbs = stripslashes($_REQUEST[$bbk]); |
||||
| 246 | $browseby .= ' AND boo.'.$bbv.' '.'LIKE '.escapeString('%'.$bbs.'%'); |
||||
| 247 | } |
||||
| 248 | } |
||||
| 249 | |||||
| 250 | return $browseby; |
||||
| 251 | } |
||||
| 252 | |||||
| 253 | /** |
||||
| 254 | * Update book by ID. |
||||
| 255 | */ |
||||
| 256 | public function update( |
||||
| 257 | int $id, |
||||
| 258 | string $title, |
||||
| 259 | ?string $asin, |
||||
| 260 | ?string $url, |
||||
| 261 | ?string $author, |
||||
| 262 | ?string $publisher, |
||||
| 263 | $publishdate, |
||||
| 264 | int $cover |
||||
| 265 | ): bool { |
||||
| 266 | return BookInfo::query()->where('id', $id)->update([ |
||||
| 267 | 'title' => $title, |
||||
| 268 | 'asin' => $asin, |
||||
| 269 | 'url' => $url, |
||||
| 270 | 'author' => $author, |
||||
| 271 | 'publisher' => $publisher, |
||||
| 272 | 'publishdate' => $publishdate, |
||||
| 273 | 'cover' => $cover, |
||||
| 274 | ]) > 0; |
||||
| 275 | } |
||||
| 276 | |||||
| 277 | /** |
||||
| 278 | * Process book releases, 1 category at a time. |
||||
| 279 | * |
||||
| 280 | * @throws \Exception |
||||
| 281 | */ |
||||
| 282 | public function processBookReleases(string $groupID = '', string $guidChar = ''): void |
||||
| 283 | { |
||||
| 284 | $bookids = []; |
||||
| 285 | if (ctype_digit((string) $this->bookreqids)) { |
||||
| 286 | $bookids[] = $this->bookreqids; |
||||
| 287 | } else { |
||||
| 288 | $bookids = explode(', ', $this->bookreqids); |
||||
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||||
| 289 | } |
||||
| 290 | |||||
| 291 | $total = \count($bookids); |
||||
| 292 | if ($total > 0) { |
||||
| 293 | foreach ($bookids as $i => $iValue) { |
||||
| 294 | $query = Release::query() |
||||
| 295 | ->whereNull('bookinfo_id') |
||||
| 296 | ->whereIn('categories_id', [$iValue]) |
||||
| 297 | ->orderByDesc('postdate') |
||||
|
0 ignored issues
–
show
'postdate' of type string is incompatible with the type Closure|Illuminate\Datab...\Database\Query\Builder expected by parameter $column of Illuminate\Database\Query\Builder::orderByDesc().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 298 | ->limit($this->bookqty); |
||||
| 299 | |||||
| 300 | if ($guidChar !== '') { |
||||
| 301 | $query->where('leftguid', 'like', $guidChar.'%'); |
||||
| 302 | } |
||||
| 303 | |||||
| 304 | if ($groupID !== '') { |
||||
| 305 | $query->where('groups_id', $groupID); |
||||
| 306 | } |
||||
| 307 | |||||
| 308 | $this->processBookReleasesHelper( |
||||
| 309 | $query->get(['searchname', 'id', 'categories_id']), $iValue |
||||
| 310 | ); |
||||
| 311 | } |
||||
| 312 | } |
||||
| 313 | } |
||||
| 314 | |||||
| 315 | /** |
||||
| 316 | * Process book releases helper. |
||||
| 317 | * |
||||
| 318 | * @throws \Exception |
||||
| 319 | */ |
||||
| 320 | protected function processBookReleasesHelper($res, $categoryID): void |
||||
| 321 | { |
||||
| 322 | if ($res->count() > 0) { |
||||
| 323 | if ($this->echooutput) { |
||||
| 324 | $this->colorCli->header('Processing '.$res->count().' book release(s) for categories id '.$categoryID); |
||||
| 325 | } |
||||
| 326 | |||||
| 327 | $bookId = -2; |
||||
| 328 | foreach ($res as $arr) { |
||||
| 329 | $startTime = now()->timestamp; |
||||
| 330 | $usedAmazon = false; |
||||
| 331 | // audiobooks are also books and should be handled in an identical manor, even though it falls under a music category |
||||
| 332 | if ($arr['categories_id'] === (int) Category::MUSIC_AUDIOBOOK) { |
||||
| 333 | // audiobook |
||||
| 334 | $bookInfo = $this->parseTitle($arr['searchname'], $arr['id'], 'audiobook'); |
||||
| 335 | } else { |
||||
| 336 | // ebook |
||||
| 337 | $bookInfo = $this->parseTitle($arr['searchname'], $arr['id'], 'ebook'); |
||||
| 338 | } |
||||
| 339 | |||||
| 340 | if ($bookInfo !== false) { |
||||
| 341 | if ($this->echooutput) { |
||||
| 342 | $this->colorCli->info('Looking up: '.$bookInfo); |
||||
| 343 | } |
||||
| 344 | |||||
| 345 | // Do a local lookup first |
||||
| 346 | $bookCheck = $this->getBookInfoByName($bookInfo); |
||||
| 347 | |||||
| 348 | if ($bookCheck === null && \in_array($bookInfo, $this->failCache, false)) { |
||||
| 349 | // Lookup recently failed, no point trying again |
||||
| 350 | if ($this->echooutput) { |
||||
| 351 | $this->colorCli->info('Cached previous failure. Skipping.'); |
||||
| 352 | } |
||||
| 353 | $bookId = -2; |
||||
| 354 | } elseif ($bookCheck === null) { |
||||
| 355 | $bookId = $this->updateBookInfo($bookInfo); |
||||
| 356 | $usedAmazon = true; |
||||
| 357 | if ($bookId === -2) { |
||||
| 358 | $this->failCache[] = $bookInfo; |
||||
| 359 | } |
||||
| 360 | } else { |
||||
| 361 | $bookId = $bookCheck['id']; |
||||
| 362 | } |
||||
| 363 | |||||
| 364 | // Update release. |
||||
| 365 | Release::query()->where('id', $arr['id'])->update(['bookinfo_id' => $bookId]); |
||||
| 366 | } else { // Could not parse release title. |
||||
| 367 | Release::query()->where('id', $arr['id'])->update(['bookinfo_id' => $bookId]); |
||||
| 368 | if ($this->echooutput) { |
||||
| 369 | echo '.'; |
||||
| 370 | } |
||||
| 371 | } |
||||
| 372 | // Sleep to not flood amazon. |
||||
| 373 | $diff = floor((now()->timestamp - $startTime) * 1000000); |
||||
| 374 | if ($this->sleeptime * 1000 - $diff > 0 && $usedAmazon === true) { |
||||
| 375 | usleep($this->sleeptime * 1000 - $diff); |
||||
|
0 ignored issues
–
show
$this->sleeptime * 1000 - $diff of type double is incompatible with the type integer expected by parameter $microseconds of usleep().
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 376 | } |
||||
| 377 | } |
||||
| 378 | } elseif ($this->echooutput) { |
||||
| 379 | $this->colorCli->header('No book releases to process for categories id '.$categoryID); |
||||
| 380 | } |
||||
| 381 | } |
||||
| 382 | |||||
| 383 | /** |
||||
| 384 | * Parse release title. |
||||
| 385 | * |
||||
| 386 | * @return bool|string |
||||
| 387 | */ |
||||
| 388 | public function parseTitle($release_name, $releaseID, $releasetype) |
||||
| 389 | { |
||||
| 390 | $a = preg_replace('/\d{1,2} \d{1,2} \d{2,4}|(19|20)\d\d|anybody got .+?[a-z]\? |[ ._-](Novel|TIA)([ ._-]|$)|([ \.])HQ([-\. ])|[\(\)\.\-_ ](AVI|AZW3?|DOC|EPUB|LIT|MOBI|NFO|RETAIL|(si)?PDF|RTF|TXT)[\)\]\.\-_ ](?![a-z0-9])|compleet|DAGSTiDNiNGEN|DiRFiX|\+ extra|r?e ?Books?([\.\-_ ]English|ers)?|azw3?|ePu([bp])s?|html|mobi|^NEW[\.\-_ ]|PDF([\.\-_ ]English)?|Please post more|Post description|Proper|Repack(fix)?|[\.\-_ ](Chinese|English|French|German|Italian|Retail|Scan|Swedish)|^R4 |Repost|Skytwohigh|TIA!+|TruePDF|V413HAV|(would someone )?please (re)?post.+? "|with the authors name right/i', '', $release_name); |
||||
| 391 | $b = preg_replace('/^(As Req |conversion |eq |Das neue Abenteuer \d+|Fixed version( ignore previous post)?|Full |Per Req As Found|(\s+)?R4 |REQ |revised |version |\d+(\s+)?$)|(COMPLETE|INTERNAL|RELOADED| (AZW3|eB|docx|ENG?|exe|FR|Fix|gnv64|MU|NIV|R\d\s+\d{1,2} \d{1,2}|R\d|Req|TTL|UC|v(\s+)?\d))(\s+)?$/i', '', $a); |
||||
| 392 | |||||
| 393 | // remove book series from title as this gets more matches on amazon |
||||
| 394 | $c = preg_replace('/ - \[.+\]|\[.+\]/', '', $b); |
||||
| 395 | |||||
| 396 | // remove any brackets left behind |
||||
| 397 | $d = preg_replace('/(\(\)|\[\])/', '', $c); |
||||
| 398 | $releasename = trim(preg_replace('/\s\s+/i', ' ', $d)); |
||||
| 399 | |||||
| 400 | // the default existing type was ebook, this handles that in the same manor as before |
||||
| 401 | if ($releasetype === 'ebook') { |
||||
| 402 | if (preg_match('/^([a-z0-9] )+$|ArtofUsenet|ekiosk|(ebook|mobi).+collection|erotica|Full Video|ImwithJamie|linkoff org|Mega.+pack|^[a-z0-9]+ (?!((January|February|March|April|May|June|July|August|September|O([ck])tober|November|De([cz])ember)))[a-z]+( (ebooks?|The))?$|NY Times|(Book|Massive) Dump|Sexual/i', $releasename)) { |
||||
| 403 | if ($this->echooutput) { |
||||
| 404 | $this->colorCli->headerOver('Changing category to misc books: ').$this->colorCli->primary($releasename); |
||||
|
0 ignored issues
–
show
Are you sure
$this->colorCli->headerO...egory to misc books: ') of type void can be used in concatenation?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
Are you sure the usage of
$this->colorCli->primary($releasename) targeting Blacklight\ColorCLI::primary() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
Are you sure the usage of
$this->colorCli->headerO...egory to misc books: ') targeting Blacklight\ColorCLI::headerOver() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
|
|||||
| 405 | } |
||||
| 406 | Release::query()->where('id', $releaseID)->update(['categories_id' => Category::BOOKS_UNKNOWN]); |
||||
| 407 | |||||
| 408 | return false; |
||||
| 409 | } |
||||
| 410 | |||||
| 411 | if (preg_match('/^([a-z0-9ü!]+ ){1,2}(N|Vol)?\d{1,4}([abc])?$|^([a-z0-9]+ ){1,2}(Jan( |unar|$)|Feb( |ruary|$)|Mar( |ch|$)|Apr( |il|$)|May(?![a-z0-9])|Jun([ e$])|Jul([ y$])|Aug( |ust|$)|Sep( |tember|$)|O([ck])t( |ober|$)|Nov( |ember|$)|De([cz])( |ember|$))/ui', $releasename) && ! preg_match('/Part \d+/i', $releasename)) { |
||||
| 412 | if ($this->echooutput) { |
||||
| 413 | $this->colorCli->headerOver('Changing category to magazines: ').$this->colorCli->primary($releasename); |
||||
|
0 ignored issues
–
show
Are you sure
$this->colorCli->headerO...tegory to magazines: ') of type void can be used in concatenation?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
Are you sure the usage of
$this->colorCli->primary($releasename) targeting Blacklight\ColorCLI::primary() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
Are you sure the usage of
$this->colorCli->headerO...tegory to magazines: ') targeting Blacklight\ColorCLI::headerOver() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
|
|||||
| 414 | } |
||||
| 415 | Release::query()->where('id', $releaseID)->update(['categories_id' => Category::BOOKS_MAGAZINES]); |
||||
| 416 | |||||
| 417 | return false; |
||||
| 418 | } |
||||
| 419 | if (! empty($releasename) && ! preg_match('/^[a-z0-9]+$|^([0-9]+ ){1,}$|Part \d+/i', $releasename)) { |
||||
| 420 | return $releasename; |
||||
| 421 | } |
||||
| 422 | |||||
| 423 | return false; |
||||
| 424 | } |
||||
| 425 | if ($releasetype === 'audiobook') { |
||||
| 426 | if (! empty($releasename) && ! preg_match('/^[a-z0-9]+$|^([0-9]+ ){1,}$|Part \d+/i', $releasename)) { |
||||
| 427 | // we can skip category for audiobooks, since we already know it, so as long as the release name is valid return it so that it is postprocessed by amazon. In the future, determining the type of audiobook could be added (Lecture or book), since we can skip lookups on lectures, but for now handle them all the same way |
||||
| 428 | return $releasename; |
||||
| 429 | } |
||||
| 430 | |||||
| 431 | return false; |
||||
| 432 | } |
||||
| 433 | |||||
| 434 | return false; |
||||
| 435 | } |
||||
| 436 | |||||
| 437 | /** |
||||
| 438 | * Update book info from external sources. |
||||
| 439 | * |
||||
| 440 | * @return false|int|string |
||||
| 441 | * |
||||
| 442 | * @throws \Exception |
||||
| 443 | */ |
||||
| 444 | public function updateBookInfo(string $bookInfo = '', $amazdata = null) |
||||
| 445 | { |
||||
| 446 | $ri = new ReleaseImageService; |
||||
| 447 | |||||
| 448 | $bookId = -2; |
||||
| 449 | |||||
| 450 | $book = false; |
||||
| 451 | if ($bookInfo !== '') { |
||||
| 452 | if (! $book) { |
||||
|
0 ignored issues
–
show
|
|||||
| 453 | $this->colorCli->info('Fetching data from iTunes for '.$bookInfo); |
||||
| 454 | $book = $this->fetchItunesBookProperties($bookInfo); |
||||
| 455 | } elseif ($amazdata !== null) { |
||||
| 456 | $book = $amazdata; |
||||
| 457 | } |
||||
| 458 | } |
||||
| 459 | |||||
| 460 | if (empty($book)) { |
||||
| 461 | return false; |
||||
| 462 | } |
||||
| 463 | |||||
| 464 | $check = BookInfo::query()->where('asin', $book['asin'])->first(); |
||||
| 465 | if ($check === null) { |
||||
| 466 | $bookId = BookInfo::query()->insertGetId( |
||||
| 467 | [ |
||||
| 468 | 'title' => $book['title'], |
||||
| 469 | 'author' => $book['author'], |
||||
| 470 | 'asin' => $book['asin'], |
||||
| 471 | 'isbn' => $book['isbn'], |
||||
| 472 | 'ean' => $book['ean'], |
||||
| 473 | 'url' => $book['url'], |
||||
| 474 | 'salesrank' => $book['salesrank'], |
||||
| 475 | 'publisher' => $book['publisher'], |
||||
| 476 | 'publishdate' => $book['publishdate'], |
||||
| 477 | 'pages' => $book['pages'], |
||||
| 478 | 'overview' => $book['overview'], |
||||
| 479 | 'genre' => $book['genre'], |
||||
| 480 | 'cover' => $book['cover'], |
||||
| 481 | 'created_at' => now(), |
||||
| 482 | 'updated_at' => now(), |
||||
| 483 | ] |
||||
| 484 | ); |
||||
| 485 | } else { |
||||
| 486 | if ($check !== null) { |
||||
| 487 | $bookId = $check['id']; |
||||
| 488 | } |
||||
| 489 | BookInfo::query()->where('id', $bookId)->update( |
||||
| 490 | [ |
||||
| 491 | 'title' => $book['title'], |
||||
| 492 | 'author' => $book['author'], |
||||
| 493 | 'asin' => $book['asin'], |
||||
| 494 | 'isbn' => $book['isbn'], |
||||
| 495 | 'ean' => $book['ean'], |
||||
| 496 | 'url' => $book['url'], |
||||
| 497 | 'salesrank' => $book['salesrank'], |
||||
| 498 | 'publisher' => $book['publisher'], |
||||
| 499 | 'publishdate' => $book['publishdate'], |
||||
| 500 | 'pages' => $book['pages'], |
||||
| 501 | 'overview' => $book['overview'], |
||||
| 502 | 'genre' => $book['genre'], |
||||
| 503 | 'cover' => $book['cover'], |
||||
| 504 | ] |
||||
| 505 | ); |
||||
| 506 | } |
||||
| 507 | |||||
| 508 | if ($bookId && $bookId !== -2) { |
||||
| 509 | if ($this->echooutput) { |
||||
| 510 | $this->colorCli->header('Added/updated book: '); |
||||
| 511 | if ($book['author'] !== '') { |
||||
| 512 | $this->colorCli->alternateOver(' Author: ').$this->colorCli->primary($book['author']); |
||||
|
0 ignored issues
–
show
Are you sure the usage of
$this->colorCli->primary($book['author']) targeting Blacklight\ColorCLI::primary() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
Are you sure the usage of
$this->colorCli->alternateOver(' Author: ') targeting Blacklight\ColorCLI::alternateOver() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
Are you sure
$this->colorCli->alternateOver(' Author: ') of type void can be used in concatenation?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
|
|||||
| 513 | } |
||||
| 514 | $this->colorCli->alternateOver(' Title: ').$this->colorCli->primary(' '.$book['title']); |
||||
|
0 ignored issues
–
show
Are you sure
$this->colorCli->alternateOver(' Title: ') of type void can be used in concatenation?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
Are you sure the usage of
$this->colorCli->primary(' ' . $book['title']) targeting Blacklight\ColorCLI::primary() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
Are you sure the usage of
$this->colorCli->alternateOver(' Title: ') targeting Blacklight\ColorCLI::alternateOver() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
|
|||||
| 515 | if ($book['genre'] !== 'null') { |
||||
| 516 | $this->colorCli->alternateOver(' Genre: ').$this->colorCli->primary(' '.$book['genre']); |
||||
|
0 ignored issues
–
show
Are you sure the usage of
$this->colorCli->primary(' ' . $book['genre']) targeting Blacklight\ColorCLI::primary() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
Are you sure
$this->colorCli->alternateOver(' Genre: ') of type void can be used in concatenation?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
Are you sure the usage of
$this->colorCli->alternateOver(' Genre: ') targeting Blacklight\ColorCLI::alternateOver() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
|
|||||
| 517 | } |
||||
| 518 | } |
||||
| 519 | |||||
| 520 | $book['cover'] = $ri->saveImage($bookId, $book['coverurl'], $this->imgSavePath, 250, 250); |
||||
| 521 | } elseif ($this->echooutput) { |
||||
| 522 | $this->colorCli->header('Nothing to update: '). |
||||
|
0 ignored issues
–
show
Are you sure
$this->colorCli->header('Nothing to update: ') of type void can be used in concatenation?
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
Loading history...
Are you sure the usage of
$this->colorCli->header('Nothing to update: ') targeting Blacklight\ColorCLI::header() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
|
|||||
| 523 | $this->colorCli->header($book['author']. |
||||
|
0 ignored issues
–
show
Are you sure the usage of
$this->colorCli->header(...' - ' . $book['title']) targeting Blacklight\ColorCLI::header() seems to always return null.
This check looks for function or method calls that always return null and whose return value is used. class A
{
function getObject()
{
return null;
}
}
$a = new A();
if ($a->getObject()) {
The method The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes. Loading history...
|
|||||
| 524 | ' - '. |
||||
| 525 | $book['title']); |
||||
| 526 | } |
||||
| 527 | |||||
| 528 | return $bookId; |
||||
| 529 | } |
||||
| 530 | |||||
| 531 | /** |
||||
| 532 | * Fetch book properties from iTunes. |
||||
| 533 | * |
||||
| 534 | * @return array|bool |
||||
| 535 | */ |
||||
| 536 | public function fetchItunesBookProperties(string $bookInfo) |
||||
| 537 | { |
||||
| 538 | $itunes = new ItunesService(); |
||||
| 539 | $iTunesBook = $itunes->findEbook($bookInfo); |
||||
| 540 | |||||
| 541 | if ($iTunesBook === null) { |
||||
| 542 | $this->colorCli->notice('Could not find a match on iTunes!'); |
||||
| 543 | |||||
| 544 | return false; |
||||
| 545 | } |
||||
| 546 | |||||
| 547 | $this->colorCli->info('Found matching title: '.$iTunesBook['name']); |
||||
| 548 | |||||
| 549 | $book = [ |
||||
| 550 | 'title' => $iTunesBook['name'], |
||||
| 551 | 'author' => $iTunesBook['author'], |
||||
| 552 | 'asin' => $iTunesBook['id'], |
||||
| 553 | 'isbn' => 'null', |
||||
| 554 | 'ean' => 'null', |
||||
| 555 | 'url' => $iTunesBook['store_url'], |
||||
| 556 | 'salesrank' => '', |
||||
| 557 | 'publisher' => '', |
||||
| 558 | 'pages' => '', |
||||
| 559 | 'coverurl' => ! empty($iTunesBook['cover']) ? $iTunesBook['cover'] : '', |
||||
| 560 | 'genre' => is_array($iTunesBook['genres']) ? implode(', ', $iTunesBook['genres']) : $iTunesBook['genre'], |
||||
| 561 | 'overview' => strip_tags($iTunesBook['description'] ?? ''), |
||||
| 562 | 'publishdate' => $iTunesBook['release_date'], |
||||
| 563 | ]; |
||||
| 564 | |||||
| 565 | if (! empty($book['coverurl'])) { |
||||
| 566 | $book['cover'] = 1; |
||||
| 567 | } else { |
||||
| 568 | $book['cover'] = 0; |
||||
| 569 | } |
||||
| 570 | |||||
| 571 | return $book; |
||||
| 572 | } |
||||
| 573 | } |
||||
| 574 | |||||
| 575 |