1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Blacklight; |
4
|
|
|
|
5
|
|
|
use App\Models\Release; |
6
|
|
|
use App\Models\BookInfo; |
7
|
|
|
use App\Models\Category; |
8
|
|
|
use App\Models\Settings; |
9
|
|
|
use DariusIII\ItunesApi\iTunes; |
10
|
|
|
use Illuminate\Support\Facades\DB; |
11
|
|
|
use Illuminate\Support\Facades\Cache; |
12
|
|
|
use DariusIII\ItunesApi\Exceptions\EbookNotFoundException; |
13
|
|
|
use DariusIII\ItunesApi\Exceptions\SearchNoResultsException; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* Class Books. |
17
|
|
|
*/ |
18
|
|
|
class Books |
19
|
|
|
{ |
20
|
|
|
/** |
21
|
|
|
* @var bool |
22
|
|
|
*/ |
23
|
|
|
public $echooutput; |
24
|
|
|
|
25
|
|
|
/** |
26
|
|
|
* @var null|string |
27
|
|
|
*/ |
28
|
|
|
public $pubkey; |
29
|
|
|
|
30
|
|
|
/** |
31
|
|
|
* @var null|string |
32
|
|
|
*/ |
33
|
|
|
public $privkey; |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @var null|string |
37
|
|
|
*/ |
38
|
|
|
public $asstag; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* @var int|null|string |
42
|
|
|
*/ |
43
|
|
|
public $bookqty; |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var int|null|string |
47
|
|
|
*/ |
48
|
|
|
public $sleeptime; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* @var string |
52
|
|
|
*/ |
53
|
|
|
public $imgSavePath; |
54
|
|
|
|
55
|
|
|
/** |
56
|
|
|
* @var null|string |
57
|
|
|
*/ |
58
|
|
|
public $bookreqids; |
59
|
|
|
|
60
|
|
|
/** |
61
|
|
|
* @var string |
62
|
|
|
*/ |
63
|
|
|
public $renamed; |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* @var array |
67
|
|
|
*/ |
68
|
|
|
public $failCache; |
69
|
|
|
|
70
|
|
|
/** |
71
|
|
|
* @var \Blacklight\ColorCLI |
72
|
|
|
*/ |
73
|
|
|
protected $colorCli; |
74
|
|
|
|
75
|
|
|
/** |
76
|
|
|
* @param array $options Class instances / Echo to cli. |
77
|
|
|
* |
78
|
|
|
* @throws \Exception |
79
|
|
|
*/ |
80
|
|
|
public function __construct(array $options = []) |
81
|
|
|
{ |
82
|
|
|
$defaults = [ |
83
|
|
|
'Echo' => false, |
84
|
|
|
'Settings' => null, |
85
|
|
|
]; |
86
|
|
|
$options += $defaults; |
87
|
|
|
|
88
|
|
|
$this->echooutput = ($options['Echo'] && config('nntmux.echocli')); |
89
|
|
|
|
90
|
|
|
$this->colorCli = new ColorCLI(); |
91
|
|
|
|
92
|
|
|
$this->pubkey = Settings::settingValue('APIs..amazonpubkey'); |
93
|
|
|
$this->privkey = Settings::settingValue('APIs..amazonprivkey'); |
94
|
|
|
$this->asstag = Settings::settingValue('APIs..amazonassociatetag'); |
95
|
|
|
$this->bookqty = Settings::settingValue('..maxbooksprocessed') !== '' ? (int) Settings::settingValue('..maxbooksprocessed') : 300; |
|
|
|
|
96
|
|
|
$this->sleeptime = Settings::settingValue('..amazonsleep') !== '' ? (int) Settings::settingValue('..amazonsleep') : 1000; |
|
|
|
|
97
|
|
|
$this->imgSavePath = NN_COVERS.'book'.DS; |
98
|
|
|
$result = Settings::settingValue('..book_reqids'); |
99
|
|
|
$this->bookreqids = $result ?? Category::BOOKS_EBOOK; |
100
|
|
|
$this->renamed = (int) Settings::settingValue('..lookupbooks') === 2 ? 'AND isrenamed = 1' : ''; |
101
|
|
|
|
102
|
|
|
$this->failCache = []; |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
/** |
106
|
|
|
* @param $id |
107
|
|
|
* |
108
|
|
|
* @return \Illuminate\Database\Eloquent\Model|null|static |
109
|
|
|
*/ |
110
|
|
|
public function getBookInfo($id) |
111
|
|
|
{ |
112
|
|
|
return BookInfo::query()->where('id', $id)->first(); |
113
|
|
|
} |
114
|
|
|
|
115
|
|
|
/** |
116
|
|
|
* @param $title |
117
|
|
|
* |
118
|
|
|
* @return \Illuminate\Database\Eloquent\Model |
119
|
|
|
*/ |
120
|
|
|
public function getBookInfoByName($title) |
121
|
|
|
{ |
122
|
|
|
|
123
|
|
|
//only used to get a count of words |
124
|
|
|
$searchWords = ''; |
125
|
|
|
$title = preg_replace('/( - | -|\(.+\)|\(|\))/', ' ', $title); |
126
|
|
|
$title = preg_replace('/[^\w ]+/', '', $title); |
127
|
|
|
$title = trim(trim(preg_replace('/\s\s+/i', ' ', $title))); |
128
|
|
|
foreach (explode(' ', $title) as $word) { |
129
|
|
|
$word = trim(rtrim(trim($word), '-')); |
130
|
|
|
if ($word !== '' && $word !== '-') { |
131
|
|
|
$word = '+'.$word; |
132
|
|
|
$searchWords .= sprintf('%s ', $word); |
133
|
|
|
} |
134
|
|
|
} |
135
|
|
|
$searchWords = trim($searchWords); |
136
|
|
|
|
137
|
|
|
return BookInfo::search($searchWords)->first(); |
138
|
|
|
} |
139
|
|
|
|
140
|
|
|
/** |
141
|
|
|
* @param $page |
142
|
|
|
* @param $cat |
143
|
|
|
* @param $start |
144
|
|
|
* @param $num |
145
|
|
|
* @param $orderby |
146
|
|
|
* @param array $excludedcats |
147
|
|
|
* |
148
|
|
|
* @return array |
149
|
|
|
* @throws \Exception |
150
|
|
|
*/ |
151
|
|
|
public function getBookRange($page, $cat, $start, $num, $orderby, array $excludedcats = []): array |
152
|
|
|
{ |
153
|
|
|
$browseby = $this->getBrowseBy(); |
154
|
|
|
$catsrch = ''; |
155
|
|
|
if (\count($cat) > 0 && $cat[0] !== -1) { |
156
|
|
|
$catsrch = Category::getCategorySearch($cat); |
157
|
|
|
} |
158
|
|
|
$exccatlist = ''; |
159
|
|
|
if (\count($excludedcats) > 0) { |
160
|
|
|
$exccatlist = ' AND r.categories_id NOT IN ('.implode(',', $excludedcats).')'; |
161
|
|
|
} |
162
|
|
|
$order = $this->getBookOrder($orderby); |
163
|
|
|
$booksql = sprintf( |
164
|
|
|
" |
165
|
|
|
SELECT SQL_CALC_FOUND_ROWS boo.id, |
166
|
|
|
GROUP_CONCAT(r.id ORDER BY r.postdate DESC SEPARATOR ',') AS grp_release_id |
167
|
|
|
FROM bookinfo boo |
168
|
|
|
LEFT JOIN releases r ON boo.id = r.bookinfo_id |
169
|
|
|
WHERE r.nzbstatus = 1 |
170
|
|
|
AND boo.cover = 1 |
171
|
|
|
AND boo.title != '' |
172
|
|
|
AND r.passwordstatus %s |
173
|
|
|
%s %s %s |
174
|
|
|
GROUP BY boo.id |
175
|
|
|
ORDER BY %s %s %s", |
176
|
|
|
(new Releases())->showPasswords(), |
177
|
|
|
$browseby, |
178
|
|
|
$catsrch, |
179
|
|
|
$exccatlist, |
180
|
|
|
$order[0], |
181
|
|
|
$order[1], |
182
|
|
|
($start === false ? '' : ' LIMIT '.$num.' OFFSET '.$start) |
183
|
|
|
); |
184
|
|
|
$expiresAt = now()->addMinutes(config('nntmux.cache_expiry_medium')); |
185
|
|
|
$bookscache = Cache::get(md5($booksql.$page)); |
186
|
|
|
if ($bookscache !== null) { |
187
|
|
|
$books = $bookscache; |
188
|
|
|
} else { |
189
|
|
|
$data = DB::select($booksql); |
190
|
|
|
$books = ['total' => DB::select('SELECT FOUND_ROWS() AS total'), 'result' => $data]; |
191
|
|
|
Cache::put(md5($booksql.$page), $books, $expiresAt); |
192
|
|
|
} |
193
|
|
|
$bookIDs = $releaseIDs = false; |
194
|
|
|
if (\is_array($books['result'])) { |
195
|
|
|
foreach ($books['result'] as $book => $id) { |
196
|
|
|
$bookIDs[] = $id->id; |
197
|
|
|
$releaseIDs[] = $id->grp_release_id; |
198
|
|
|
} |
199
|
|
|
} |
200
|
|
|
$sql = sprintf( |
201
|
|
|
' |
202
|
|
|
SELECT |
203
|
|
|
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, |
204
|
|
|
boo.*, |
205
|
|
|
r.bookinfo_id, |
206
|
|
|
g.name AS group_name, |
207
|
|
|
rn.releases_id AS nfoid |
208
|
|
|
FROM releases r |
209
|
|
|
LEFT OUTER JOIN groups g ON g.id = r.groups_id |
210
|
|
|
LEFT OUTER JOIN release_nfos rn ON rn.releases_id = r.id |
211
|
|
|
LEFT OUTER JOIN dnzb_failures df ON df.release_id = r.id |
212
|
|
|
INNER JOIN bookinfo boo ON boo.id = r.bookinfo_id |
213
|
|
|
WHERE boo.id IN (%s) |
214
|
|
|
AND r.id IN (%s) |
215
|
|
|
%s |
216
|
|
|
GROUP BY boo.id |
217
|
|
|
ORDER BY %s %s', |
218
|
|
|
(\is_array($bookIDs) ? implode(',', $bookIDs) : -1), |
|
|
|
|
219
|
|
|
(\is_array($releaseIDs) ? implode(',', $releaseIDs) : -1), |
|
|
|
|
220
|
|
|
$catsrch, |
221
|
|
|
$order[0], |
222
|
|
|
$order[1] |
223
|
|
|
); |
224
|
|
|
$return = Cache::get(md5($sql.$page)); |
225
|
|
|
if ($return !== null) { |
226
|
|
|
return $return; |
227
|
|
|
} |
228
|
|
|
$return = DB::select($sql); |
229
|
|
|
if (\count($return) > 0) { |
230
|
|
|
$return[0]->_totalcount = $books['total'][0]->total ?? 0; |
231
|
|
|
} |
232
|
|
|
Cache::put(md5($sql.$page), $return, $expiresAt); |
233
|
|
|
|
234
|
|
|
return $return; |
235
|
|
|
} |
236
|
|
|
|
237
|
|
|
/** |
238
|
|
|
* @param $orderby |
239
|
|
|
* |
240
|
|
|
* @return array |
241
|
|
|
*/ |
242
|
|
|
public function getBookOrder($orderby): array |
243
|
|
|
{ |
244
|
|
|
$order = $orderby === '' ? 'r.postdate' : $orderby; |
245
|
|
|
$orderArr = explode('_', $order); |
246
|
|
|
switch ($orderArr[0]) { |
247
|
|
|
case 'title': |
|
|
|
|
248
|
|
|
$orderfield = 'boo.title'; |
249
|
|
|
break; |
250
|
|
|
case 'author': |
|
|
|
|
251
|
|
|
$orderfield = 'boo.author'; |
252
|
|
|
break; |
253
|
|
|
case 'publishdate': |
254
|
|
|
$orderfield = 'boo.publishdate'; |
255
|
|
|
break; |
256
|
|
|
case 'size': |
257
|
|
|
$orderfield = 'r.size'; |
258
|
|
|
break; |
259
|
|
|
case 'files': |
260
|
|
|
$orderfield = 'r.totalpart'; |
261
|
|
|
break; |
262
|
|
|
case 'stats': |
263
|
|
|
$orderfield = 'r.grabs'; |
264
|
|
|
break; |
265
|
|
|
case 'posted': |
266
|
|
|
default: |
267
|
|
|
$orderfield = 'r.postdate'; |
268
|
|
|
break; |
269
|
|
|
} |
270
|
|
|
$ordersort = (isset($orderArr[1]) && preg_match('/^asc|desc$/i', $orderArr[1])) ? $orderArr[1] : 'desc'; |
271
|
|
|
|
272
|
|
|
return [$orderfield, $ordersort]; |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* @return array |
277
|
|
|
*/ |
278
|
|
|
public function getBookOrdering(): array |
279
|
|
|
{ |
280
|
|
|
return [ |
281
|
|
|
'title_asc', |
282
|
|
|
'title_desc', |
283
|
|
|
'posted_asc', |
284
|
|
|
'posted_desc', |
285
|
|
|
'size_asc', |
286
|
|
|
'size_desc', |
287
|
|
|
'files_asc', |
288
|
|
|
'files_desc', |
289
|
|
|
'stats_asc', |
290
|
|
|
'stats_desc', |
291
|
|
|
'releasedate_asc', |
292
|
|
|
'releasedate_desc', |
293
|
|
|
'author_asc', |
294
|
|
|
'author_desc', |
295
|
|
|
]; |
296
|
|
|
} |
297
|
|
|
|
298
|
|
|
/** |
299
|
|
|
* @return array |
300
|
|
|
*/ |
301
|
|
|
public function getBrowseByOptions(): array |
302
|
|
|
{ |
303
|
|
|
return ['author' => 'author', 'title' => 'title']; |
304
|
|
|
} |
305
|
|
|
|
306
|
|
|
/** |
307
|
|
|
* @return string |
308
|
|
|
*/ |
309
|
|
|
public function getBrowseBy(): string |
310
|
|
|
{ |
311
|
|
|
$browseby = ' '; |
312
|
|
|
foreach ($this->getBrowseByOptions() as $bbk => $bbv) { |
313
|
|
|
if (isset($_REQUEST[$bbk]) && ! empty($_REQUEST[$bbk])) { |
314
|
|
|
$bbs = stripslashes($_REQUEST[$bbk]); |
315
|
|
|
$browseby .= 'AND boo.'.$bbv.' '.'LIKE '.escapeString('%'.$bbs.'%'); |
316
|
|
|
} |
317
|
|
|
} |
318
|
|
|
|
319
|
|
|
return $browseby; |
320
|
|
|
} |
321
|
|
|
|
322
|
|
|
/** |
323
|
|
|
* Process book releases, 1 category at a time. |
324
|
|
|
* |
325
|
|
|
* @throws \Exception |
326
|
|
|
*/ |
327
|
|
|
public function processBookReleases(): void |
328
|
|
|
{ |
329
|
|
|
$bookids = []; |
330
|
|
|
if (ctype_digit((string) $this->bookreqids)) { |
331
|
|
|
$bookids[] = $this->bookreqids; |
332
|
|
|
} else { |
333
|
|
|
$bookids = explode(', ', $this->bookreqids); |
334
|
|
|
} |
335
|
|
|
|
336
|
|
|
$total = \count($bookids); |
337
|
|
|
if ($total > 0) { |
338
|
|
|
foreach ($bookids as $i => $iValue) { |
339
|
|
|
$this->processBookReleasesHelper( |
340
|
|
|
Release::query()->where('nzbstatus', '=', NZB::NZB_ADDED) |
341
|
|
|
->whereNull('bookinfo_id') |
342
|
|
|
->whereIn('categories_id', [$bookids[$i]]) |
343
|
|
|
->orderBy('postdate', 'desc') |
344
|
|
|
->limit($this->bookqty) |
|
|
|
|
345
|
|
|
->get(['searchname', 'id', 'categories_id']), |
346
|
|
|
$bookids[$i] |
347
|
|
|
); |
348
|
|
|
} |
349
|
|
|
} |
350
|
|
|
} |
351
|
|
|
|
352
|
|
|
/** |
353
|
|
|
* @param $res |
354
|
|
|
* @param $categoryID |
355
|
|
|
* |
356
|
|
|
* @throws \Exception |
357
|
|
|
*/ |
358
|
|
|
protected function processBookReleasesHelper($res, $categoryID): void |
359
|
|
|
{ |
360
|
|
|
if ($res->count() > 0) { |
361
|
|
|
if ($this->echooutput) { |
362
|
|
|
$this->colorCli->header('Processing '.$res->count().' book release(s) for categories id '.$categoryID); |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
$bookId = -2; |
366
|
|
|
foreach ($res as $arr) { |
367
|
|
|
$startTime = now()->timestamp; |
368
|
|
|
$usedAmazon = false; |
369
|
|
|
// audiobooks are also books and should be handled in an identical manor, even though it falls under a music category |
370
|
|
|
if ($arr['categories_id'] === '3030') { |
371
|
|
|
// audiobook |
372
|
|
|
$bookInfo = $this->parseTitle($arr['searchname'], $arr['id'], 'audiobook'); |
373
|
|
|
} else { |
374
|
|
|
// ebook |
375
|
|
|
$bookInfo = $this->parseTitle($arr['searchname'], $arr['id'], 'ebook'); |
376
|
|
|
} |
377
|
|
|
|
378
|
|
|
if ($bookInfo !== false) { |
379
|
|
|
if ($this->echooutput) { |
380
|
|
|
$this->colorCli->headerOver('Looking up: ').$this->colorCli->primary($bookInfo); |
|
|
|
|
381
|
|
|
} |
382
|
|
|
|
383
|
|
|
// Do a local lookup first |
384
|
|
|
$bookCheck = $this->getBookInfoByName($bookInfo); |
385
|
|
|
|
386
|
|
|
if ($bookCheck === null && \in_array($bookInfo, $this->failCache, false)) { |
387
|
|
|
// Lookup recently failed, no point trying again |
388
|
|
|
if ($this->echooutput) { |
389
|
|
|
$this->colorCli->headerOver('Cached previous failure. Skipping.'); |
390
|
|
|
} |
391
|
|
|
$bookId = -2; |
392
|
|
|
} elseif ($bookCheck === null) { |
393
|
|
|
$bookId = $this->updateBookInfo($bookInfo); |
394
|
|
|
$usedAmazon = true; |
395
|
|
|
if ($bookId === -2) { |
396
|
|
|
$this->failCache[] = $bookInfo; |
397
|
|
|
} |
398
|
|
|
} elseif ($bookCheck !== null) { |
399
|
|
|
$bookId = $bookCheck['id']; |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
// Update release. |
403
|
|
|
Release::query()->where('id', $arr['id'])->update(['bookinfo_id' => $bookId]); |
404
|
|
|
} else { // Could not parse release title. |
405
|
|
|
Release::query()->where('id', $arr['id'])->update(['bookinfo_id' => $bookId]); |
406
|
|
|
if ($this->echooutput) { |
407
|
|
|
echo '.'; |
408
|
|
|
} |
409
|
|
|
} |
410
|
|
|
// Sleep to not flood amazon. |
411
|
|
|
$diff = floor((now()->timestamp - $startTime) * 1000000); |
412
|
|
|
if ($this->sleeptime * 1000 - $diff > 0 && $usedAmazon === true) { |
413
|
|
|
usleep($this->sleeptime * 1000 - $diff); |
|
|
|
|
414
|
|
|
} |
415
|
|
|
} |
416
|
|
|
} elseif ($this->echooutput) { |
417
|
|
|
$this->colorCli->header('No book releases to process for categories id '.$categoryID); |
418
|
|
|
} |
419
|
|
|
} |
420
|
|
|
|
421
|
|
|
/** |
422
|
|
|
* @param $release_name |
423
|
|
|
* @param $releaseID |
424
|
|
|
* @param $releasetype |
425
|
|
|
* |
426
|
|
|
* @return bool|string |
427
|
|
|
*/ |
428
|
|
|
public function parseTitle($release_name, $releaseID, $releasetype) |
429
|
|
|
{ |
430
|
|
|
$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); |
431
|
|
|
$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); |
432
|
|
|
|
433
|
|
|
//remove book series from title as this gets more matches on amazon |
434
|
|
|
$c = preg_replace('/ - \[.+\]|\[.+\]/', '', $b); |
435
|
|
|
|
436
|
|
|
//remove any brackets left behind |
437
|
|
|
$d = preg_replace('/(\(\)|\[\])/', '', $c); |
438
|
|
|
$releasename = trim(preg_replace('/\s\s+/i', ' ', $d)); |
439
|
|
|
|
440
|
|
|
// the default existing type was ebook, this handles that in the same manor as before |
441
|
|
|
if ($releasetype === 'ebook') { |
442
|
|
|
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)) { |
443
|
|
|
if ($this->echooutput) { |
444
|
|
|
$this->colorCli->headerOver('Changing category to misc books: ').$this->colorCli->primary($releasename); |
|
|
|
|
445
|
|
|
} |
446
|
|
|
Release::query()->where('id', $releaseID)->update(['categories_id' => Category::BOOKS_UNKNOWN]); |
447
|
|
|
|
448
|
|
|
return false; |
449
|
|
|
} |
450
|
|
|
|
451
|
|
|
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)) { |
452
|
|
|
if ($this->echooutput) { |
453
|
|
|
$this->colorCli->headerOver('Changing category to magazines: ').$this->colorCli->primary($releasename); |
|
|
|
|
454
|
|
|
} |
455
|
|
|
Release::query()->where('id', $releaseID)->update(['categories_id' => Category::BOOKS_MAGAZINES]); |
456
|
|
|
|
457
|
|
|
return false; |
458
|
|
|
} |
459
|
|
|
if (! empty($releasename) && ! preg_match('/^[a-z0-9]+$|^([0-9]+ ){1,}$|Part \d+/i', $releasename)) { |
460
|
|
|
return $releasename; |
461
|
|
|
} |
462
|
|
|
|
463
|
|
|
return false; |
464
|
|
|
} |
465
|
|
|
if ($releasetype === 'audiobook') { |
466
|
|
|
if (! empty($releasename) && ! preg_match('/^[a-z0-9]+$|^([0-9]+ ){1,}$|Part \d+/i', $releasename)) { |
467
|
|
|
// 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 |
468
|
|
|
return $releasename; |
469
|
|
|
} |
470
|
|
|
|
471
|
|
|
return false; |
472
|
|
|
} |
473
|
|
|
|
474
|
|
|
return false; |
475
|
|
|
} |
476
|
|
|
|
477
|
|
|
/** |
478
|
|
|
* @param string $bookInfo |
479
|
|
|
* @param null $amazdata |
|
|
|
|
480
|
|
|
* |
481
|
|
|
* @return false|int|string |
482
|
|
|
* @throws \Exception |
483
|
|
|
*/ |
484
|
|
|
public function updateBookInfo($bookInfo = '', $amazdata = null) |
485
|
|
|
{ |
486
|
|
|
$ri = new ReleaseImage(); |
487
|
|
|
|
488
|
|
|
$bookId = -2; |
489
|
|
|
|
490
|
|
|
$book = false; |
491
|
|
|
if ($bookInfo !== '') { |
492
|
|
|
if (! $book) { |
|
|
|
|
493
|
|
|
$this->colorCli->info('Fetching data from iTunes for '.$bookInfo); |
494
|
|
|
$book = $this->fetchItunesBookProperties($bookInfo); |
495
|
|
|
} elseif ($amazdata !== null) { |
496
|
|
|
$book = $amazdata; |
497
|
|
|
} |
498
|
|
|
} |
499
|
|
|
|
500
|
|
|
if (empty($book)) { |
501
|
|
|
return false; |
502
|
|
|
} |
503
|
|
|
|
504
|
|
|
$check = BookInfo::query()->where('asin', $book['asin'])->first(); |
505
|
|
|
if ($check === null) { |
506
|
|
|
$bookId = BookInfo::query()->insertGetId( |
507
|
|
|
[ |
508
|
|
|
'title' => $book['title'], |
509
|
|
|
'author' => $book['author'], |
510
|
|
|
'asin' => $book['asin'], |
511
|
|
|
'isbn' => $book['isbn'], |
512
|
|
|
'ean' => $book['ean'], |
513
|
|
|
'url' => $book['url'], |
514
|
|
|
'salesrank' => $book['salesrank'], |
515
|
|
|
'publisher' => $book['publisher'], |
516
|
|
|
'publishdate' => $book['publishdate'], |
517
|
|
|
'pages' => $book['pages'], |
518
|
|
|
'overview' => $book['overview'], |
519
|
|
|
'genre' => $book['genre'], |
520
|
|
|
'cover' => $book['cover'], |
521
|
|
|
'created_at' => now(), |
522
|
|
|
'updated_at' => now(), |
523
|
|
|
] |
524
|
|
|
); |
525
|
|
|
} else { |
526
|
|
|
if ($check !== null) { |
527
|
|
|
$bookId = $check['id']; |
528
|
|
|
} |
529
|
|
|
BookInfo::query()->where('id', $bookId)->update( |
530
|
|
|
[ |
531
|
|
|
'title' => $book['title'], |
532
|
|
|
'author' => $book['author'], |
533
|
|
|
'asin' => $book['asin'], |
534
|
|
|
'isbn' => $book['isbn'], |
535
|
|
|
'ean' => $book['ean'], |
536
|
|
|
'url' => $book['url'], |
537
|
|
|
'salesrank' => $book['salesrank'], |
538
|
|
|
'publisher' => $book['publisher'], |
539
|
|
|
'publishdate' => $book['publishdate'], |
540
|
|
|
'pages' => $book['pages'], |
541
|
|
|
'overview' => $book['overview'], |
542
|
|
|
'genre' => $book['genre'], |
543
|
|
|
'cover' => $book['cover'], |
544
|
|
|
] |
545
|
|
|
); |
546
|
|
|
} |
547
|
|
|
|
548
|
|
|
if ($bookId && $bookId !== -2) { |
549
|
|
|
if ($this->echooutput) { |
550
|
|
|
$this->colorCli->header('Added/updated book: '); |
551
|
|
|
if ($book['author'] !== '') { |
552
|
|
|
$this->colorCli->alternateOver(' Author: ').$this->colorCli->primary($book['author']); |
|
|
|
|
553
|
|
|
} |
554
|
|
|
$this->colorCli->alternateOver(' Title: ').$this->colorCli->primary(' '.$book['title']); |
|
|
|
|
555
|
|
|
if ($book['genre'] !== 'null') { |
556
|
|
|
$this->colorCli->alternateOver(' Genre: ').$this->colorCli->primary(' '.$book['genre']); |
|
|
|
|
557
|
|
|
} |
558
|
|
|
} |
559
|
|
|
|
560
|
|
|
$book['cover'] = $ri->saveImage($bookId, $book['coverurl'], $this->imgSavePath, 250, 250); |
561
|
|
|
} elseif ($this->echooutput) { |
562
|
|
|
$this->colorCli->header('Nothing to update: '). |
|
|
|
|
563
|
|
|
$this->colorCli->header($book['author']. |
|
|
|
|
564
|
|
|
' - '. |
565
|
|
|
$book['title']); |
566
|
|
|
} |
567
|
|
|
|
568
|
|
|
return $bookId; |
569
|
|
|
} |
570
|
|
|
|
571
|
|
|
/** |
572
|
|
|
* @param string $bookInfo |
573
|
|
|
* @return array|bool |
574
|
|
|
* @throws \DariusIII\ItunesApi\Exceptions\InvalidProviderException |
575
|
|
|
*/ |
576
|
|
|
public function fetchItunesBookProperties(string $bookInfo) |
577
|
|
|
{ |
578
|
|
|
$book = true; |
579
|
|
|
try { |
580
|
|
|
$iTunesBook = iTunes::load('ebook')->fetchOneByName($bookInfo); |
581
|
|
|
} catch (EbookNotFoundException $e) { |
582
|
|
|
$book = false; |
583
|
|
|
} catch (SearchNoResultsException $e) { |
584
|
|
|
$book = false; |
585
|
|
|
} |
586
|
|
|
|
587
|
|
|
if ($book) { |
588
|
|
|
$this->colorCli->info('Found matching title: '.$iTunesBook->getName()); |
589
|
|
|
$book = [ |
590
|
|
|
'title' => $iTunesBook->getName(), |
591
|
|
|
'author' => $iTunesBook->getAuthor(), |
|
|
|
|
592
|
|
|
'asin' => $iTunesBook->getItunesId(), |
593
|
|
|
'isbn' => 'null', |
594
|
|
|
'ean' => 'null', |
595
|
|
|
'url' => $iTunesBook->getStoreUrl(), |
|
|
|
|
596
|
|
|
'salesrank' => '', |
597
|
|
|
'publisher' => '', |
598
|
|
|
'pages' => '', |
599
|
|
|
'coverurl' => ! empty($iTunesBook->getCover()) ? str_replace('100x100', '800x800', $iTunesBook->getCover()) : '', |
|
|
|
|
600
|
|
|
'genre' => implode(', ', $iTunesBook->getGenre()), |
|
|
|
|
601
|
|
|
'overview' => strip_tags($iTunesBook->getDescription()), |
|
|
|
|
602
|
|
|
'publishdate' => $iTunesBook->getReleaseDate()->format('Y-m-d'), |
|
|
|
|
603
|
|
|
]; |
604
|
|
|
if (! empty($book['coverurl'])) { |
605
|
|
|
$book['cover'] = 1; |
606
|
|
|
} else { |
607
|
|
|
$book['cover'] = 0; |
608
|
|
|
} |
609
|
|
|
} else { |
610
|
|
|
$this->colorCli->notice('Could not find a match on iTunes!'); |
611
|
|
|
} |
612
|
|
|
|
613
|
|
|
return $book; |
614
|
|
|
} |
615
|
|
|
} |
616
|
|
|
|