1 | <?php |
||||||
2 | /** |
||||||
3 | * Audio Player |
||||||
4 | * |
||||||
5 | * This file is licensed under the Affero General Public License version 3 or |
||||||
6 | * later. See the LICENSE.md file. |
||||||
7 | * |
||||||
8 | * @author Marcel Scherello <[email protected]> |
||||||
9 | * @author Sebastian Doell <[email protected]> |
||||||
10 | * @copyright 2016-2021 Marcel Scherello |
||||||
11 | * @copyright 2015 Sebastian Doell |
||||||
12 | */ |
||||||
13 | |||||||
14 | namespace OCA\audioplayer\Controller; |
||||||
15 | |||||||
16 | use Doctrine\DBAL\DBALException; |
||||||
0 ignored issues
–
show
|
|||||||
17 | use Exception; |
||||||
18 | use getID3; |
||||||
19 | use getid3_exception; |
||||||
0 ignored issues
–
show
The type
getid3_exception was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths
Loading history...
|
|||||||
20 | use getid3_lib; |
||||||
0 ignored issues
–
show
The type
getid3_lib was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths
Loading history...
|
|||||||
21 | use OC; |
||||||
22 | use OCP\AppFramework\Controller; |
||||||
23 | use OCP\AppFramework\Http\JSONResponse; |
||||||
24 | use OCP\AppFramework\Http\TemplateResponse; |
||||||
25 | use OCP\Files\InvalidPathException; |
||||||
26 | use OCP\Files\NotFoundException; |
||||||
27 | use OCP\Image; |
||||||
28 | use OCP\PreconditionNotMetException; |
||||||
29 | use Symfony\Component\Console\Output\NullOutput; |
||||||
30 | use Symfony\Component\Console\Output\OutputInterface; |
||||||
31 | use OCP\IRequest; |
||||||
32 | use OCP\IConfig; |
||||||
33 | use OCP\IL10N; |
||||||
34 | use OCP\L10N\IFactory; |
||||||
35 | use OCP\IDBConnection; |
||||||
36 | use OCP\Files\IRootFolder; |
||||||
37 | use Psr\Log\LoggerInterface; |
||||||
38 | use OCP\IDateTimeZone; |
||||||
39 | use OCP\IEventSource; |
||||||
40 | use OCP\IEventSourceFactory; |
||||||
0 ignored issues
–
show
The type
OCP\IEventSourceFactory was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths
Loading history...
|
|||||||
41 | |||||||
42 | /** |
||||||
43 | * Controller class for main page. |
||||||
44 | */ |
||||||
45 | class ScannerController extends Controller |
||||||
46 | { |
||||||
47 | |||||||
48 | private $userId; |
||||||
49 | private $l10n; |
||||||
50 | private $iDublicate = 0; |
||||||
51 | private $iAlbumCount = 0; |
||||||
52 | private $numOfSongs; |
||||||
53 | private $db; |
||||||
54 | private $configManager; |
||||||
55 | private $occJob = false; |
||||||
56 | private $noFseek = false; |
||||||
57 | private $languageFactory; |
||||||
58 | private $rootFolder; |
||||||
59 | private $ID3Tags; |
||||||
60 | private $cyrillic; |
||||||
61 | private $logger; |
||||||
62 | private $parentIdPrevious = 0; |
||||||
63 | private $folderPicture = false; |
||||||
64 | private $DBController; |
||||||
65 | private $IDateTimeZone; |
||||||
66 | private $SettingController; |
||||||
67 | private $eventSource; |
||||||
68 | private $lastUpdated; |
||||||
69 | |||||||
70 | public function __construct( |
||||||
71 | $appName, |
||||||
72 | IRequest $request, |
||||||
73 | $userId, |
||||||
74 | IL10N $l10n, |
||||||
75 | IDBConnection $db, |
||||||
76 | IConfig $configManager, |
||||||
77 | IFactory $languageFactory, |
||||||
78 | IRootFolder $rootFolder, |
||||||
79 | LoggerInterface $logger, |
||||||
80 | DbController $DBController, |
||||||
81 | SettingController $SettingController, |
||||||
82 | IDateTimeZone $IDateTimeZone |
||||||
83 | ) |
||||||
84 | { |
||||||
85 | parent::__construct($appName, $request); |
||||||
86 | $this->appName = $appName; |
||||||
87 | $this->userId = $userId; |
||||||
88 | $this->l10n = $l10n; |
||||||
89 | $this->db = $db; |
||||||
90 | $this->configManager = $configManager; |
||||||
91 | $this->languageFactory = $languageFactory; |
||||||
92 | $this->rootFolder = $rootFolder; |
||||||
93 | $this->logger = $logger; |
||||||
94 | $this->DBController = $DBController; |
||||||
95 | $this->SettingController = $SettingController; |
||||||
96 | $this->IDateTimeZone = $IDateTimeZone; |
||||||
97 | $this->lastUpdated = time(); |
||||||
98 | |||||||
99 | // @TODO: Remove method_exists when min-version="28" |
||||||
100 | if (method_exists(\OC::$server, 'createEventSource')) { |
||||||
101 | $this->eventSource = \OC::$server->createEventSource(); |
||||||
102 | } else { |
||||||
103 | $this->eventSource = \OCP\Server::get(IEventSourceFactory::class)->create(); |
||||||
0 ignored issues
–
show
The type
OCP\Server was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths
Loading history...
|
|||||||
104 | } |
||||||
105 | } |
||||||
106 | |||||||
107 | /** |
||||||
108 | * @NoAdminRequired |
||||||
109 | * |
||||||
110 | */ |
||||||
111 | public function getImportTpl() |
||||||
112 | { |
||||||
113 | $params = []; |
||||||
114 | return new TemplateResponse('audioplayer', 'part.import', $params, ''); |
||||||
115 | } |
||||||
116 | |||||||
117 | /** |
||||||
118 | * @NoAdminRequired |
||||||
119 | * |
||||||
120 | * @param $userId |
||||||
121 | * @param $output |
||||||
122 | * @param $scanstop |
||||||
123 | * @return bool|JSONResponse |
||||||
124 | * @throws NotFoundException |
||||||
125 | * @throws getid3_exception |
||||||
126 | */ |
||||||
127 | public function scanForAudios($userId = null, $output = null, $scanstop = null) |
||||||
128 | { |
||||||
129 | set_time_limit(0); |
||||||
130 | if (isset($scanstop)) { |
||||||
131 | $this->DBController->setSessionValue('scanner_running', 'stopped', $this->userId); |
||||||
132 | $params = ['status' => 'stopped']; |
||||||
133 | return new JSONResponse($params); |
||||||
134 | } |
||||||
135 | |||||||
136 | // check if scanner is started from web or occ |
||||||
137 | if ($userId !== null) { |
||||||
138 | $this->occJob = true; |
||||||
139 | $this->userId = $userId; |
||||||
140 | $languageCode = $this->configManager->getUserValue($userId, 'core', 'lang'); |
||||||
141 | $this->l10n = $this->languageFactory->get('audioplayer', $languageCode); |
||||||
142 | } else { |
||||||
143 | $output = new NullOutput(); |
||||||
144 | } |
||||||
145 | |||||||
146 | $output->writeln("Start processing of <info>audio files</info>"); |
||||||
147 | |||||||
148 | $counter = 0; |
||||||
149 | $error_count = 0; |
||||||
150 | $duplicate_tracks = ''; |
||||||
151 | $error_file = ''; |
||||||
152 | $this->cyrillic = $this->configManager->getUserValue($this->userId, $this->appName, 'cyrillic'); |
||||||
153 | $this->DBController->setSessionValue('scanner_running', 'active', $this->userId); |
||||||
154 | |||||||
155 | $this->setScannerVersion(); |
||||||
156 | |||||||
157 | if (!class_exists('getid3_exception')) { |
||||||
158 | require_once __DIR__ . '/../../3rdparty/getid3/getid3.php'; |
||||||
159 | } |
||||||
160 | $getID3 = new getID3; |
||||||
161 | $getID3->setOption(['encoding' => 'UTF-8', |
||||||
162 | 'option_tag_id3v1' => false, |
||||||
163 | 'option_tag_id3v2' => true, |
||||||
164 | 'option_tag_lyrics3' => false, |
||||||
165 | 'option_tag_apetag' => false, |
||||||
166 | 'option_tags_process' => true, |
||||||
167 | 'option_tags_html' => false |
||||||
168 | ]); |
||||||
169 | |||||||
170 | $audios = $this->getAudioObjects($output); |
||||||
171 | $streams = $this->getStreamObjects($output); |
||||||
172 | |||||||
173 | if ($this->cyrillic === 'checked') $output->writeln("Cyrillic processing activated", OutputInterface::VERBOSITY_VERBOSE); |
||||||
174 | $output->writeln("Start processing of <info>audio files</info>", OutputInterface::VERBOSITY_VERBOSE); |
||||||
175 | |||||||
176 | $commitThreshold = max(200, intdiv(count($audios), 10)); |
||||||
177 | $this->DBController->beginTransaction(); |
||||||
178 | try { |
||||||
179 | foreach ($audios as &$audio) { |
||||||
180 | if ($this->scanCancelled()) { break; } |
||||||
181 | |||||||
182 | $counter++; |
||||||
183 | try { |
||||||
184 | $scanResult = $this->scanAudio($audio, $getID3, $output); |
||||||
185 | if ($scanResult === 'error') { |
||||||
186 | $error_file .= $audio->getPath() . '<br />'; |
||||||
187 | $error_count++; |
||||||
188 | } else if ($scanResult === 'duplicate') { |
||||||
189 | $duplicate_tracks .= $audio->getPath() . '<br />'; |
||||||
190 | $this->iDublicate++; |
||||||
191 | } |
||||||
192 | } catch (getid3_exception $e) { |
||||||
193 | $this->logger->error('getID3 error while building library: '. $e); |
||||||
194 | continue; |
||||||
195 | } |
||||||
196 | |||||||
197 | if ($this->timeForUpdate()) { |
||||||
198 | $this->updateProgress($counter, $audio->getPath(), $output); |
||||||
199 | } |
||||||
200 | if ($counter % $commitThreshold == 0) { |
||||||
201 | $this->DBController->commit(); |
||||||
202 | $output->writeln("Status committed to database", OutputInterface::VERBOSITY_VERBOSE); |
||||||
203 | $this->DBController->beginTransaction(); |
||||||
204 | } |
||||||
205 | } |
||||||
206 | |||||||
207 | $output->writeln("Start processing of <info>stream files</info>", OutputInterface::VERBOSITY_VERBOSE); |
||||||
208 | foreach ($streams as &$stream) { |
||||||
209 | if ($this->scanCancelled()) { break; } |
||||||
210 | |||||||
211 | $counter++; |
||||||
212 | $scanResult = $this->scanStream($stream, $output); |
||||||
213 | if ($scanResult === 'duplicate') { |
||||||
214 | $duplicate_tracks .= $stream->getPath() . '<br />'; |
||||||
215 | $this->iDublicate++; |
||||||
216 | } |
||||||
217 | |||||||
218 | if ($this->timeForUpdate()) { |
||||||
219 | $this->updateProgress($counter, $stream->getPath(), $output); |
||||||
220 | } |
||||||
221 | } |
||||||
222 | $this->setScannerTimestamp(); |
||||||
223 | $this->DBController->commit(); |
||||||
224 | } catch (DBALException $e) { |
||||||
225 | $this->logger->error('DB error while building library: '. $e); |
||||||
226 | $this->DBController->rollBack(); |
||||||
227 | } catch (Exception $e) { |
||||||
228 | $this->logger->error('Error while building library: '. $e); |
||||||
229 | $this->DBController->commit(); |
||||||
230 | } |
||||||
231 | |||||||
232 | // different outputs when web or occ |
||||||
233 | if (!$this->occJob) { |
||||||
234 | $message = $this->composeResponseMessage($counter, $error_count, $duplicate_tracks, $error_file); |
||||||
235 | $this->DBController->setSessionValue('scanner_running', '', $this->userId); |
||||||
236 | $response = [ |
||||||
237 | 'message' => $message |
||||||
238 | ]; |
||||||
239 | $response = json_encode($response); |
||||||
240 | $this->eventSource->send('done', $response); |
||||||
241 | $this->eventSource->close(); |
||||||
242 | return new JSONResponse(); |
||||||
243 | } else { |
||||||
244 | $output->writeln("Audios found: " . ($counter) . ""); |
||||||
245 | $output->writeln("Duplicates found: " . ($this->iDublicate) . ""); |
||||||
246 | $output->writeln("Written to library: " . ($counter - $this->iDublicate - $error_count) . ""); |
||||||
247 | $output->writeln("Albums found: " . ($this->iAlbumCount) . ""); |
||||||
248 | $output->writeln("Errors: " . ($error_count) . ""); |
||||||
249 | return true; |
||||||
250 | } |
||||||
251 | } |
||||||
252 | |||||||
253 | /** |
||||||
254 | * Check whether scan got cancelled by user |
||||||
255 | * @return bool |
||||||
256 | */ |
||||||
257 | private function scanCancelled() { |
||||||
258 | //check if scan is still supposed to run, or if dialog was closed in web already |
||||||
259 | if (!$this->occJob) { |
||||||
260 | $scan_running = $this->DBController->getSessionValue('scanner_running'); |
||||||
261 | return ($scan_running !== 'active'); |
||||||
262 | } |
||||||
263 | } |
||||||
264 | |||||||
265 | /** |
||||||
266 | * Process audio track and insert it into DB |
||||||
267 | * @param object $audio audio object to scan |
||||||
268 | * @param object $getID3 ID3 tag helper from getid3 library |
||||||
269 | * @param OutputInterface|null $output |
||||||
270 | * @return string |
||||||
271 | */ |
||||||
272 | private function scanAudio($audio, $getID3, $output) { |
||||||
273 | if ($this->checkFileChanged($audio)) { |
||||||
274 | $this->DBController->deleteFromDB($audio->getId(), $this->userId); |
||||||
275 | } |
||||||
276 | |||||||
277 | $this->analyze($audio, $getID3, $output); |
||||||
278 | |||||||
279 | # catch issue when getID3 does not bring a result in case of corrupt file or fpm-timeout |
||||||
280 | if (!isset($this->ID3Tags['bitrate']) AND !isset($this->ID3Tags['playtime_string'])) { |
||||||
281 | $this->logger->debug('Error with getID3. Does not seem to be a valid audio file: ' . $audio->getPath(), array('app' => 'audioplayer')); |
||||||
282 | $output->writeln(" Error with getID3. Does not seem to be a valid audio file", OutputInterface::VERBOSITY_VERBOSE); |
||||||
0 ignored issues
–
show
The method
writeln() does not exist on null .
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces. This is most likely a typographical error or the method has been renamed.
Loading history...
|
|||||||
283 | return 'error'; |
||||||
284 | } |
||||||
285 | |||||||
286 | $album = $this->getID3Value(array('album')); |
||||||
287 | $genre = $this->getID3Value(array('genre')); |
||||||
288 | $artist = $this->getID3Value(array('artist')); |
||||||
289 | $name = $this->getID3Value(array('title'), $audio->getName()); |
||||||
290 | $trackNr = $this->getID3Value(array('track_number'), ''); |
||||||
291 | $composer = $this->getID3Value(array('composer'), ''); |
||||||
292 | $year = $this->getID3Value(array('year', 'creation_date', 'date'), 0); |
||||||
293 | $subtitle = $this->getID3Value(array('subtitle', 'version'), ''); |
||||||
294 | $disc = $this->getID3Value(array('part_of_a_set', 'discnumber', 'partofset', 'disc_number'), 1); |
||||||
295 | $isrc = $this->getID3Value(array('isrc'), ''); |
||||||
296 | $copyright = $this->getID3Value(array('copyright_message', 'copyright'), ''); |
||||||
297 | |||||||
298 | $iGenreId = $this->DBController->writeGenreToDB($this->userId, $genre); |
||||||
299 | $iArtistId = $this->DBController->writeArtistToDB($this->userId, $artist); |
||||||
300 | |||||||
301 | # write albumartist if available |
||||||
302 | # if no albumartist, NO artist is stored on album level |
||||||
303 | # in DBController loadArtistsToAlbum() takes over deriving the artists from the album tracks |
||||||
304 | # MP3, FLAC & MP4 have different tags for albumartist |
||||||
305 | $iAlbumArtistId = NULL; |
||||||
306 | $album_artist = $this->getID3Value(array('band', 'album_artist', 'albumartist', 'album artist'), '0'); |
||||||
307 | |||||||
308 | if ($album_artist !== '0') { |
||||||
309 | $iAlbumArtistId = $this->DBController->writeArtistToDB($this->userId, $album_artist); |
||||||
310 | } |
||||||
311 | |||||||
312 | $parentId = $audio->getParent()->getId(); |
||||||
313 | $return = $this->DBController->writeAlbumToDB($this->userId, $album, (int)$year, $iAlbumArtistId, $parentId); |
||||||
314 | $iAlbumId = $return['id']; |
||||||
315 | $this->iAlbumCount = $this->iAlbumCount + $return['albumcount']; |
||||||
316 | |||||||
317 | $bitrate = 0; |
||||||
318 | if (isset($this->ID3Tags['bitrate'])) { |
||||||
319 | $bitrate = $this->ID3Tags['bitrate']; |
||||||
320 | } |
||||||
321 | |||||||
322 | $playTimeString = ''; |
||||||
323 | if (isset($this->ID3Tags['playtime_string'])) { |
||||||
324 | $playTimeString = $this->ID3Tags['playtime_string']; |
||||||
325 | } |
||||||
326 | |||||||
327 | $this->getAlbumArt($audio, $iAlbumId, $parentId, $output); |
||||||
328 | |||||||
329 | $aTrack = [ |
||||||
330 | 'title' => $this->truncateStrings($name, '256'), |
||||||
331 | 'number' => $this->normalizeInteger($trackNr), |
||||||
332 | 'artist_id' => (int)$iArtistId, |
||||||
333 | 'album_id' => (int)$iAlbumId, |
||||||
334 | 'length' => $playTimeString, |
||||||
335 | 'file_id' => (int)$audio->getId(), |
||||||
336 | 'bitrate' => (int)$bitrate, |
||||||
337 | 'mimetype' => $audio->getMimetype(), |
||||||
338 | 'genre' => (int)$iGenreId, |
||||||
339 | 'year' => $this->truncateStrings($this->normalizeInteger($year), 4, ''), |
||||||
340 | 'disc' => $this->normalizeInteger($disc), |
||||||
341 | 'subtitle' => $this->truncateStrings($subtitle, '256'), |
||||||
342 | 'composer' => $this->truncateStrings($composer, '256'), |
||||||
343 | 'folder_id' => $parentId, |
||||||
344 | 'isrc' => $this->truncateStrings($isrc, '12'), |
||||||
345 | 'copyright' => $this->truncateStrings($copyright, '256'), |
||||||
346 | ]; |
||||||
347 | |||||||
348 | $return = $this->DBController->writeTrackToDB($this->userId, $aTrack); |
||||||
349 | if ($return['dublicate'] === 1) { |
||||||
350 | $this->logger->debug('Duplicate file: ' . $audio->getPath(), array('app' => 'audioplayer')); |
||||||
351 | $output->writeln(" This title is a duplicate and already existing", OutputInterface::VERBOSITY_VERBOSE); |
||||||
352 | return 'duplicate'; |
||||||
353 | } |
||||||
354 | return 'success'; |
||||||
355 | } |
||||||
356 | |||||||
357 | /** |
||||||
358 | * Process stream and insert it into DB |
||||||
359 | * @param object $stream stream object to scan |
||||||
360 | * @param OutputInterface|null $output |
||||||
361 | * @return string |
||||||
362 | */ |
||||||
363 | private function scanStream($stream, $output) { |
||||||
364 | $title = $this->truncateStrings($stream->getName(), '256'); |
||||||
365 | $aStream = [ |
||||||
366 | 'title' => substr($title, 0, strrpos($title, ".")), |
||||||
367 | 'artist_id' => 0, |
||||||
368 | 'album_id' => 0, |
||||||
369 | 'file_id' => (int)$stream->getId(), |
||||||
370 | 'bitrate' => 0, |
||||||
371 | 'mimetype' => $stream->getMimetype(), |
||||||
372 | ]; |
||||||
373 | $return = $this->DBController->writeStreamToDB($this->userId, $aStream); |
||||||
374 | if ($return['dublicate'] === 1) { |
||||||
375 | $this->logger->debug('Duplicate file: ' . $stream->getPath(), array('app' => 'audioplayer')); |
||||||
376 | $output->writeln(" This title is a duplicate and already existing", OutputInterface::VERBOSITY_VERBOSE); |
||||||
377 | return 'duplicate'; |
||||||
378 | } |
||||||
379 | return 'success'; |
||||||
380 | } |
||||||
381 | |||||||
382 | /** |
||||||
383 | * Summarize scan results in a message |
||||||
384 | * @param $counter number of tracks |
||||||
385 | * @param integer $error_count number of invalid files |
||||||
386 | * @param string $duplicate_tracks list of invalid files |
||||||
387 | * @param $error_file |
||||||
388 | * @return string |
||||||
389 | */ |
||||||
390 | private function composeResponseMessage($counter, |
||||||
391 | $error_count, |
||||||
392 | $duplicate_tracks, |
||||||
393 | $error_file) { |
||||||
394 | $message = (string)$this->l10n->t('Scanning finished!') . '<br />'; |
||||||
395 | $message .= (string)$this->l10n->t('Audios found:') . ' ' . $counter . '<br />'; |
||||||
396 | $message .= (string)$this->l10n->t('Written to library:') . ' ' . ($counter - $this->iDublicate - $error_count) . '<br />'; |
||||||
397 | $message .= (string)$this->l10n->t('Albums found:') . ' ' . $this->iAlbumCount . '<br />'; |
||||||
398 | if ($error_count > 0) { |
||||||
399 | $message .= '<br /><b>' . (string)$this->l10n->t('Errors:') . ' ' . $error_count . '<br />'; |
||||||
400 | $message .= (string)$this->l10n->t('If rescan does not solve this problem the files are broken') . '</b>'; |
||||||
401 | $message .= '<br />' . $error_file . '<br />'; |
||||||
402 | } |
||||||
403 | if ($this->iDublicate > 0) { |
||||||
404 | $message .= '<br /><b>' . (string)$this->l10n->t('Duplicates found:') . ' ' . ($this->iDublicate) . '</b>'; |
||||||
405 | $message .= '<br />' . $duplicate_tracks . '<br />'; |
||||||
406 | } |
||||||
407 | return $message; |
||||||
408 | } |
||||||
409 | |||||||
410 | /** |
||||||
411 | * Give feedback to user via appropriate output |
||||||
412 | * @param integer $filesProcessed |
||||||
413 | * @param string $currentFile |
||||||
414 | * @param OutputInterface|null $output |
||||||
415 | */ |
||||||
416 | private function updateProgress($filesProcessed, $currentFile, OutputInterface $output = null) |
||||||
417 | { |
||||||
418 | if (!$this->occJob) { |
||||||
419 | $response = [ |
||||||
420 | 'filesProcessed' => $filesProcessed, |
||||||
421 | 'filesTotal' => $this->numOfSongs, |
||||||
422 | 'currentFile' => $currentFile |
||||||
423 | ]; |
||||||
424 | $response = json_encode($response); |
||||||
425 | $this->eventSource->send('progress', $response); |
||||||
426 | } else { |
||||||
427 | $output->writeln(" " . $currentFile . "</info>", OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
428 | } |
||||||
429 | } |
||||||
430 | |||||||
431 | /** |
||||||
432 | * Prevent flood over the wire |
||||||
433 | * @return bool |
||||||
434 | */ |
||||||
435 | private function timeForUpdate() |
||||||
436 | { |
||||||
437 | if ($this->occJob) { |
||||||
438 | return true; |
||||||
439 | } |
||||||
440 | $now = time(); |
||||||
441 | if ($now - $this->lastUpdated >= 1) { |
||||||
442 | $this->lastUpdated = $now; |
||||||
443 | return true; |
||||||
444 | } |
||||||
445 | return false; |
||||||
446 | } |
||||||
447 | |||||||
448 | /** |
||||||
449 | * if the scanner is started on an empty library, the current app version is stored |
||||||
450 | * |
||||||
451 | */ |
||||||
452 | private function setScannerVersion() |
||||||
453 | { |
||||||
454 | $stmt = $this->db->prepare('SELECT COUNT(`id`) AS `TRACKCOUNT` FROM `*PREFIX*audioplayer_tracks` WHERE `user_id` = ? '); |
||||||
455 | $stmt->execute(array($this->userId)); |
||||||
456 | $row = $stmt->fetch(); |
||||||
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetch() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetch on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||||
457 | if ((int)$row['TRACKCOUNT'] === 0) { |
||||||
458 | $app_version = $this->configManager->getAppValue($this->appName, 'installed_version', '0.0.0'); |
||||||
459 | $this->configManager->setUserValue($this->userId, $this->appName, 'scanner_version', $app_version); |
||||||
460 | } |
||||||
461 | } |
||||||
462 | |||||||
463 | /** |
||||||
464 | * Add track to db if not exist |
||||||
465 | * |
||||||
466 | * @param OutputInterface $output |
||||||
467 | * @return array |
||||||
468 | * @throws NotFoundException |
||||||
469 | * @throws \OCP\Files\InvalidPathException |
||||||
470 | */ |
||||||
471 | private function getAudioObjects(OutputInterface $output = null) |
||||||
472 | { |
||||||
473 | $audioPath = $this->configManager->getUserValue($this->userId, $this->appName, 'path'); |
||||||
474 | $userView = $this->rootFolder->getUserFolder($this->userId); |
||||||
475 | |||||||
476 | if ($audioPath !== null && $audioPath !== '/' && $audioPath !== '') { |
||||||
477 | try { |
||||||
478 | $userView = $userView->get($audioPath); |
||||||
479 | } catch (InvalidPathException $e) { |
||||||
480 | $output->writeln("!Error: Selected scan folder is not existing"); |
||||||
481 | return; |
||||||
482 | } catch (NotFoundException $e) { |
||||||
483 | $output->writeln("!Error: Selected scan folder is not existing"); |
||||||
484 | return; |
||||||
485 | } |
||||||
486 | } |
||||||
487 | |||||||
488 | $audios_mp3 = $userView->searchByMime('audio/mpeg'); |
||||||
489 | $audios_m4a = $userView->searchByMime('audio/mp4'); |
||||||
490 | $audios_ogg = $userView->searchByMime('audio/ogg'); |
||||||
491 | $audios_wav = $userView->searchByMime('audio/wav'); |
||||||
492 | $audios_flac = $userView->searchByMime('audio/flac'); |
||||||
493 | $audios_aif = $userView->searchByMime('audio/x-aiff'); |
||||||
494 | $audios_aac = $userView->searchByMime('audio/aac'); |
||||||
495 | $audios = array_merge($audios_mp3, $audios_m4a, $audios_ogg, $audios_wav, $audios_flac, $audios_aif, $audios_aac); |
||||||
496 | |||||||
497 | $output->writeln("Scanned Folder: " . $userView->getPath(), OutputInterface::VERBOSITY_VERBOSE); |
||||||
498 | $output->writeln("<info>Total audio files:</info> " . count($audios), OutputInterface::VERBOSITY_VERBOSE); |
||||||
499 | $output->writeln("Checking audio files to be skipped", OutputInterface::VERBOSITY_VERBOSE); |
||||||
500 | |||||||
501 | // get all fileids which are in an excluded folder |
||||||
502 | $stmt = $this->db->prepare('SELECT `fileid` from `*PREFIX*filecache` WHERE `parent` IN (SELECT `parent` FROM `*PREFIX*filecache` WHERE `name` = ? OR `name` = ? ORDER BY `fileid` ASC)'); |
||||||
503 | $stmt->execute(array('.noAudio', '.noaudio')); |
||||||
504 | $results = $stmt->fetchAll(); |
||||||
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetchAll() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetchAll on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||||
505 | $resultExclude = array_column($results, 'fileid'); |
||||||
506 | |||||||
507 | // get all fileids which are already in the Audio Player Database |
||||||
508 | $stmt = $this->db->prepare('SELECT `file_id` FROM `*PREFIX*audioplayer_tracks` WHERE `user_id` = ? '); |
||||||
509 | $stmt->execute(array($this->userId)); |
||||||
510 | $results = $stmt->fetchAll(); |
||||||
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetchAll() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetchAll on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||||
511 | $resultExisting = array_column($results, 'file_id'); |
||||||
512 | |||||||
513 | foreach ($audios as $key => &$audio) { |
||||||
514 | $current_id = $audio->getID(); |
||||||
515 | if (in_array($current_id, $resultExclude)) { |
||||||
516 | $output->writeln(" " . $current_id . " - " . $audio->getPath() . " => excluded", OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
517 | unset($audios[$key]); |
||||||
518 | } elseif (in_array($current_id, $resultExisting)) { |
||||||
519 | if ($this->checkFileChanged($audio)) { |
||||||
520 | $output->writeln(" " . $current_id . " - " . $audio->getPath() . " => indexed title changed => reindex", OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
521 | } else { |
||||||
522 | $output->writeln(" " . $current_id . " - " . $audio->getPath() . " => already indexed", OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
523 | unset($audios[$key]); |
||||||
524 | } |
||||||
525 | } |
||||||
526 | } |
||||||
527 | $this->numOfSongs = count($audios); |
||||||
528 | $output->writeln("Final audio files to be processed: " . $this->numOfSongs, OutputInterface::VERBOSITY_VERBOSE); |
||||||
529 | return $audios; |
||||||
530 | } |
||||||
531 | |||||||
532 | /** |
||||||
533 | * check changed timestamps |
||||||
534 | * |
||||||
535 | * @param object $audio |
||||||
536 | * @return bool |
||||||
537 | */ |
||||||
538 | private function checkFileChanged($audio) |
||||||
539 | { |
||||||
540 | $modTime = $audio->getMTime(); |
||||||
541 | $scannerTime = $this->getScannerTimestamp(); |
||||||
542 | if ($modTime >= $scannerTime - 300) { |
||||||
543 | return true; |
||||||
544 | } else { |
||||||
545 | return false; |
||||||
546 | } |
||||||
547 | } |
||||||
548 | |||||||
549 | /** |
||||||
550 | * check the timestamp of the last scan to derive changed files |
||||||
551 | * |
||||||
552 | */ |
||||||
553 | private function getScannerTimestamp() |
||||||
554 | { |
||||||
555 | return $this->configManager->getUserValue($this->userId, $this->appName, 'scanner_timestamp', 300); |
||||||
556 | } |
||||||
557 | |||||||
558 | /** |
||||||
559 | * Add track to db if not exist |
||||||
560 | * |
||||||
561 | * @param OutputInterface $output |
||||||
562 | * @return array |
||||||
563 | * @throws NotFoundException |
||||||
564 | */ |
||||||
565 | private function getStreamObjects(OutputInterface $output = null) |
||||||
566 | { |
||||||
567 | $audios_clean = array(); |
||||||
568 | $audioPath = $this->configManager->getUserValue($this->userId, $this->appName, 'path'); |
||||||
569 | $userView = $this->rootFolder->getUserFolder($this->userId); |
||||||
570 | |||||||
571 | if ($audioPath !== null && $audioPath !== '/' && $audioPath !== '') { |
||||||
572 | try { |
||||||
573 | $userView = $userView->get($audioPath); |
||||||
574 | } catch (InvalidPathException $e) { |
||||||
575 | $output->writeln("!Error: Selected scan folder is not existing"); |
||||||
576 | return; |
||||||
577 | } catch (NotFoundException $e) { |
||||||
578 | $output->writeln("!Error: Selected scan folder is not existing"); |
||||||
579 | return; |
||||||
580 | } |
||||||
581 | } |
||||||
582 | |||||||
583 | $audios_mpegurl = $userView->searchByMime('audio/mpegurl'); |
||||||
584 | $audios_scpls = $userView->searchByMime('audio/x-scpls'); |
||||||
585 | $audios_xspf = $userView->searchByMime('application/xspf+xml'); |
||||||
586 | $audios = array_merge($audios_mpegurl, $audios_scpls, $audios_xspf); |
||||||
587 | $output->writeln("<info>Total stream files:</info> " . count($audios), OutputInterface::VERBOSITY_VERBOSE); |
||||||
588 | $output->writeln("Checking stream files to be skipped", OutputInterface::VERBOSITY_VERBOSE); |
||||||
589 | |||||||
590 | // get all fileids which are in an excluded folder |
||||||
591 | $stmt = $this->db->prepare('SELECT `fileid` from `*PREFIX*filecache` WHERE `parent` IN (SELECT `parent` FROM `*PREFIX*filecache` WHERE `name` = ? OR `name` = ? ORDER BY `fileid` ASC)'); |
||||||
592 | $stmt->execute(array('.noAudio', '.noaudio')); |
||||||
593 | $results = $stmt->fetchAll(); |
||||||
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetchAll() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetchAll on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||||
594 | $resultExclude = array_column($results, 'fileid'); |
||||||
595 | |||||||
596 | // get all fileids which are already in the Audio Player Database |
||||||
597 | $stmt = $this->db->prepare('SELECT `file_id` FROM `*PREFIX*audioplayer_streams` WHERE `user_id` = ? '); |
||||||
598 | $stmt->execute(array($this->userId)); |
||||||
599 | $results = $stmt->fetchAll(); |
||||||
0 ignored issues
–
show
The function
OCP\DB\IPreparedStatement::fetchAll() has been deprecated: 21.0.0 use \OCP\DB\IResult::fetchAll on the \OCP\DB\IResult returned by \OCP\IDBConnection::prepare
(
Ignorable by Annotation
)
If this is a false-positive, you can also ignore this issue in your code via the
This function has been deprecated. The supplier of the function has supplied an explanatory message. The explanatory message should give you some clue as to whether and when the function will be removed and what other function to use instead.
Loading history...
|
|||||||
600 | $resultExisting = array_column($results, 'file_id'); |
||||||
601 | |||||||
602 | foreach ($audios as $key => &$audio) { |
||||||
603 | $current_id = $audio->getID(); |
||||||
604 | if (in_array($current_id, $resultExclude)) { |
||||||
605 | $output->writeln(" " . $current_id . " - " . $audio->getPath() . " => excluded", OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
606 | unset($audios[$key]); |
||||||
607 | } elseif (in_array($current_id, $resultExisting)) { |
||||||
608 | if ($this->checkFileChanged($audio)) { |
||||||
609 | $output->writeln(" " . $current_id . " - " . $audio->getPath() . " => indexed file changed => reindex", OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
610 | } else { |
||||||
611 | $output->writeln(" " . $current_id . " - " . $audio->getPath() . " => already indexed", OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
612 | unset($audios[$key]); |
||||||
613 | } |
||||||
614 | } |
||||||
615 | } |
||||||
616 | $this->numOfSongs = $this->numOfSongs + count($audios); |
||||||
617 | $output->writeln("Final stream files to be processed: " . count($audios_clean), OutputInterface::VERBOSITY_VERBOSE); |
||||||
618 | return $audios; |
||||||
619 | } |
||||||
620 | |||||||
621 | /** |
||||||
622 | * Analyze ID3 Tags |
||||||
623 | * if fseek is not possible, libsmbclient-php is not installed or an external storage is used which does not support this. |
||||||
624 | * then fallback to slow extraction via tmpfile |
||||||
625 | * |
||||||
626 | * @param $audio object |
||||||
627 | * @param $getID3 object |
||||||
628 | * @param OutputInterface $output |
||||||
629 | */ |
||||||
630 | private function analyze($audio, $getID3, OutputInterface $output = null) |
||||||
631 | { |
||||||
632 | $this->ID3Tags = array(); |
||||||
633 | $ThisFileInfo = array(); |
||||||
634 | if ($audio->getMimetype() === 'audio/mpegurl' or $audio->getMimetype() === 'audio/x-scpls' or $audio->getMimetype() === 'application/xspf+xml') { |
||||||
635 | $ThisFileInfo['comments']['genre'][0] = 'Stream'; |
||||||
636 | $ThisFileInfo['comments']['artist'][0] = 'Stream'; |
||||||
637 | $ThisFileInfo['comments']['album'][0] = 'Stream'; |
||||||
638 | $ThisFileInfo['bitrate'] = 0; |
||||||
639 | $ThisFileInfo['playtime_string'] = 0; |
||||||
640 | } else { |
||||||
641 | |||||||
642 | $availability = $audio->getStorage()->getAvailability(); |
||||||
643 | if (!$availability['available']) { |
||||||
644 | $output->writeln("Some external storage is not available", OutputInterface::VERBOSITY_VERBOSE); |
||||||
645 | $this->logger->debug('Some external storage is not available', array('app' => 'audioplayer')); |
||||||
646 | } else { |
||||||
647 | $handle = $audio->fopen('rb'); |
||||||
648 | if (is_resource($handle) && @fseek($handle, -24, SEEK_END) === 0) { |
||||||
649 | $ThisFileInfo = $getID3->analyze($audio->getPath(), $audio->getSize(), '', $handle); |
||||||
650 | } else { |
||||||
651 | if (!$this->noFseek) { |
||||||
652 | $output->writeln("Attention: Only slow indexing due to server config. See Audio Player wiki on GitHub for details.", OutputInterface::VERBOSITY_VERBOSE); |
||||||
653 | $this->logger->debug('Attention: Only slow indexing due to server config. See Audio Player wiki on GitHub for details.', array('app' => 'audioplayer')); |
||||||
654 | $this->noFseek = true; |
||||||
655 | } |
||||||
656 | $fileName = $audio->getStorage()->getLocalFile($audio->getInternalPath()); |
||||||
657 | $ThisFileInfo = $getID3->analyze($fileName); |
||||||
658 | |||||||
659 | if (!$audio->getStorage()->isLocal($audio->getInternalPath())) { |
||||||
660 | unlink($fileName); |
||||||
661 | } |
||||||
662 | } |
||||||
663 | if ($this->cyrillic === 'checked') $ThisFileInfo = $this->convertCyrillic($ThisFileInfo); |
||||||
664 | getid3_lib::CopyTagsToComments($ThisFileInfo); |
||||||
665 | } |
||||||
666 | } |
||||||
667 | $this->ID3Tags = $ThisFileInfo; |
||||||
668 | } |
||||||
669 | |||||||
670 | /** |
||||||
671 | * Concert cyrillic characters |
||||||
672 | * |
||||||
673 | * @param array $ThisFileInfo |
||||||
674 | * @return array |
||||||
675 | */ |
||||||
676 | private function convertCyrillic($ThisFileInfo) |
||||||
677 | { |
||||||
678 | //$this->logger->debug('cyrillic handling activated', array('app' => 'audioplayer')); |
||||||
679 | // Check, if this tag was win1251 before the incorrect "8859->utf" convertion by the getid3 lib |
||||||
680 | foreach (array('id3v1', 'id3v2') as $ttype) { |
||||||
681 | $ruTag = 0; |
||||||
682 | if (isset($ThisFileInfo['tags'][$ttype])) { |
||||||
683 | // Check, if this tag was win1251 before the incorrect "8859->utf" convertion by the getid3 lib |
||||||
684 | foreach (array('album', 'artist', 'title', 'band', 'genre') as $tkey) { |
||||||
685 | if (isset($ThisFileInfo['tags'][$ttype][$tkey])) { |
||||||
686 | if (preg_match('#[\\xA8\\B8\\x80-\\xFF]{4,}#', iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $ThisFileInfo['tags'][$ttype][$tkey][0]))) { |
||||||
687 | $ruTag = 1; |
||||||
688 | break; |
||||||
689 | } |
||||||
690 | } |
||||||
691 | } |
||||||
692 | // Now make a correct conversion |
||||||
693 | if ($ruTag === 1) { |
||||||
694 | foreach (array('album', 'artist', 'title', 'band', 'genre') as $tkey) { |
||||||
695 | if (isset($ThisFileInfo['tags'][$ttype][$tkey])) { |
||||||
696 | $ThisFileInfo['tags'][$ttype][$tkey][0] = iconv('UTF-8', 'ISO-8859-1//TRANSLIT', $ThisFileInfo['tags'][$ttype][$tkey][0]); |
||||||
697 | $ThisFileInfo['tags'][$ttype][$tkey][0] = iconv('Windows-1251', 'UTF-8', $ThisFileInfo['tags'][$ttype][$tkey][0]); |
||||||
698 | } |
||||||
699 | } |
||||||
700 | } |
||||||
701 | } |
||||||
702 | } |
||||||
703 | return $ThisFileInfo; |
||||||
704 | } |
||||||
705 | |||||||
706 | /** |
||||||
707 | * Get specific ID3 tags from array |
||||||
708 | * |
||||||
709 | * @param string[] $ID3Value |
||||||
710 | * @param string $defaultValue |
||||||
711 | * @return string |
||||||
712 | */ |
||||||
713 | private function getID3Value($ID3Value, $defaultValue = null) |
||||||
714 | { |
||||||
715 | $c = count($ID3Value); |
||||||
716 | // \OCP\Util::writeLog('audioplayer', 'album: '.$this->ID3Tags['comments']['album'][0], \OCP\Util::DEBUG); |
||||||
717 | for ($i = 0; $i < $c; $i++) { |
||||||
718 | if (isset($this->ID3Tags['comments'][$ID3Value[$i]][0]) and rawurlencode($this->ID3Tags['comments'][$ID3Value[$i]][0]) !== '%FF%FE') { |
||||||
719 | return preg_replace('/[\x00-\x1F\x7F\xA0]/u', '', $this->ID3Tags['comments'][$ID3Value[$i]][0]); |
||||||
720 | } elseif ($i === $c - 1 AND $defaultValue !== null) { |
||||||
721 | return $defaultValue; |
||||||
722 | } elseif ($i === $c - 1) { |
||||||
723 | return (string)$this->l10n->t('Unknown'); |
||||||
724 | } |
||||||
725 | } |
||||||
726 | } |
||||||
727 | |||||||
728 | /** |
||||||
729 | * extract cover art from folder or from audio file |
||||||
730 | * folder/cover.jpg/png |
||||||
731 | * |
||||||
732 | * @param object $audio |
||||||
733 | * @param integer $iAlbumId |
||||||
734 | * @param integer $parentId |
||||||
735 | * @param OutputInterface|null $output |
||||||
736 | * @return boolean|null |
||||||
737 | */ |
||||||
738 | private function getAlbumArt($audio, $iAlbumId, $parentId, OutputInterface $output = null) |
||||||
739 | { |
||||||
740 | if ($parentId === $this->parentIdPrevious) { |
||||||
741 | if ($this->folderPicture) { |
||||||
742 | $output->writeln(" Reusing previous folder image", OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
743 | $this->processImageString($iAlbumId, $this->folderPicture->getContent()); |
||||||
744 | } elseif (isset($this->ID3Tags['comments']['picture'][0]['data'])) { |
||||||
745 | $data = $this->ID3Tags['comments']['picture'][0]['data']; |
||||||
746 | $this->processImageString($iAlbumId, $data); |
||||||
747 | } |
||||||
748 | } else { |
||||||
749 | $this->folderPicture = false; |
||||||
750 | if ($audio->getParent()->nodeExists('cover.jpg')) { |
||||||
751 | $this->folderPicture = $audio->getParent()->get('cover.jpg'); |
||||||
752 | } elseif ($audio->getParent()->nodeExists('Cover.jpg')) { |
||||||
753 | $this->folderPicture = $audio->getParent()->get('Cover.jpg'); |
||||||
754 | } elseif ($audio->getParent()->nodeExists('cover.jpeg')) { |
||||||
755 | $this->folderPicture = $audio->getParent()->get('cover.jpeg'); |
||||||
756 | } elseif ($audio->getParent()->nodeExists('Cover.jpeg')) { |
||||||
757 | $this->folderPicture = $audio->getParent()->get('Cover.jpeg'); |
||||||
758 | } elseif ($audio->getParent()->nodeExists('cover.png')) { |
||||||
759 | $this->folderPicture = $audio->getParent()->get('cover.png'); |
||||||
760 | } elseif ($audio->getParent()->nodeExists('Cover.png')) { |
||||||
761 | $this->folderPicture = $audio->getParent()->get('Cover.png'); |
||||||
762 | } elseif ($audio->getParent()->nodeExists('folder.jpg')) { |
||||||
763 | $this->folderPicture = $audio->getParent()->get('folder.jpg'); |
||||||
764 | } elseif ($audio->getParent()->nodeExists('Folder.jpg')) { |
||||||
765 | $this->folderPicture = $audio->getParent()->get('Folder.jpg'); |
||||||
766 | } elseif ($audio->getParent()->nodeExists('folder.jpeg')) { |
||||||
767 | $this->folderPicture = $audio->getParent()->get('folder.jpeg'); |
||||||
768 | } elseif ($audio->getParent()->nodeExists('Folder.jpeg')) { |
||||||
769 | $this->folderPicture = $audio->getParent()->get('Folder.jpeg'); |
||||||
770 | } elseif ($audio->getParent()->nodeExists('folder.png')) { |
||||||
771 | $this->folderPicture = $audio->getParent()->get('folder.png'); |
||||||
772 | } elseif ($audio->getParent()->nodeExists('Folder.png')) { |
||||||
773 | $this->folderPicture = $audio->getParent()->get('Folder.png'); |
||||||
774 | } elseif ($audio->getParent()->nodeExists('front.jpg')) { |
||||||
775 | $this->folderPicture = $audio->getParent()->get('front.jpg'); |
||||||
776 | } elseif ($audio->getParent()->nodeExists('Front.jpg')) { |
||||||
777 | $this->folderPicture = $audio->getParent()->get('Front.jpg'); |
||||||
778 | } elseif ($audio->getParent()->nodeExists('front.jpeg')) { |
||||||
779 | $this->folderPicture = $audio->getParent()->get('front.jpeg'); |
||||||
780 | } elseif ($audio->getParent()->nodeExists('Front.jpeg')) { |
||||||
781 | $this->folderPicture = $audio->getParent()->get('Front.jpeg'); |
||||||
782 | } elseif ($audio->getParent()->nodeExists('front.png')) { |
||||||
783 | $this->folderPicture = $audio->getParent()->get('front.png'); |
||||||
784 | } elseif ($audio->getParent()->nodeExists('Front.png')) { |
||||||
785 | $this->folderPicture = $audio->getParent()->get('Front.png'); |
||||||
786 | } |
||||||
787 | |||||||
788 | if ($this->folderPicture) { |
||||||
789 | $output->writeln(" Alternative album art: " . $this->folderPicture->getInternalPath(), OutputInterface::VERBOSITY_VERY_VERBOSE); |
||||||
790 | $this->processImageString($iAlbumId, $this->folderPicture->getContent()); |
||||||
791 | } elseif (isset($this->ID3Tags['comments']['picture'])) { |
||||||
792 | $data = $this->ID3Tags['comments']['picture'][0]['data']; |
||||||
793 | $this->processImageString($iAlbumId, $data); |
||||||
794 | } |
||||||
795 | $this->parentIdPrevious = $parentId; |
||||||
796 | } |
||||||
797 | return true; |
||||||
798 | } |
||||||
799 | |||||||
800 | /** |
||||||
801 | * create image string from rawdata and store as album cover |
||||||
802 | * |
||||||
803 | * @param integer $iAlbumId |
||||||
804 | * @param $data |
||||||
805 | * @return boolean |
||||||
806 | */ |
||||||
807 | private function processImageString($iAlbumId, $data) |
||||||
808 | { |
||||||
809 | $image = new Image(); |
||||||
810 | if ($image->loadFromdata($data)) { |
||||||
811 | if (($image->width() <= 250 && $image->height() <= 250) || $image->centerCrop(250)) { |
||||||
812 | $imgString = $image->__toString(); |
||||||
813 | $this->DBController->writeCoverToAlbum($this->userId, $iAlbumId, $imgString); |
||||||
814 | } |
||||||
815 | } |
||||||
816 | return true; |
||||||
817 | } |
||||||
818 | |||||||
819 | /** |
||||||
820 | * truncates fiels do DB-field size |
||||||
821 | * |
||||||
822 | * @param $string |
||||||
823 | * @param $length |
||||||
824 | * @param $dots |
||||||
825 | * @return string |
||||||
826 | */ |
||||||
827 | private function truncateStrings($string, $length, $dots = "...") |
||||||
828 | { |
||||||
829 | return (strlen($string) > $length) ? mb_strcut($string, 0, $length - strlen($dots)) . $dots : $string; |
||||||
830 | } |
||||||
831 | |||||||
832 | /** |
||||||
833 | * validate unsigned int values |
||||||
834 | * |
||||||
835 | * @param string $value |
||||||
836 | * @return int value |
||||||
837 | */ |
||||||
838 | private function normalizeInteger($value) |
||||||
839 | { |
||||||
840 | // convert format '1/10' to '1' and '-1' to null |
||||||
841 | $tmp = explode('/', $value); |
||||||
842 | $tmp = explode('-', $tmp[0]); |
||||||
843 | $value = $tmp[0]; |
||||||
844 | if (is_numeric($value) && ((int)$value) > 0) { |
||||||
845 | $value = (int)$value; |
||||||
846 | } else { |
||||||
847 | $value = 0; |
||||||
848 | } |
||||||
849 | return $value; |
||||||
850 | } |
||||||
851 | |||||||
852 | /** |
||||||
853 | * set the timestamp of the last scan to derive changed files |
||||||
854 | * |
||||||
855 | */ |
||||||
856 | private function setScannerTimestamp() |
||||||
857 | { |
||||||
858 | $this->configManager->setUserValue($this->userId, $this->appName, 'scanner_timestamp', time()); |
||||||
859 | } |
||||||
860 | |||||||
861 | /** |
||||||
862 | * @NoAdminRequired |
||||||
863 | * |
||||||
864 | * @throws NotFoundException |
||||||
865 | */ |
||||||
866 | public function checkNewTracks() |
||||||
867 | { |
||||||
868 | // get only the relevant audio files |
||||||
869 | $output = new NullOutput(); |
||||||
870 | $this->getAudioObjects($output); |
||||||
871 | $this->getStreamObjects($output); |
||||||
872 | return ($this->numOfSongs !== 0); |
||||||
873 | } |
||||||
874 | } |
||||||
875 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"]
, you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths