Skip to content

Commit 5e38a7a

Browse files
committed
fix: logic for matching new files to existing metadata is ambiguous
1 parent f206ada commit 5e38a7a

1 file changed

Lines changed: 66 additions & 21 deletions

File tree

app/Jobs/IndexFiles.php

Lines changed: 66 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -137,10 +137,10 @@ public function generateData() {
137137
}
138138

139139
foreach ($seriesEntries as $seriesChange) { // log series additions
140-
$folderID = $seriesChange['folder_id'];
141-
$compositeID = $seriesChange['composite_id'];
140+
$folderId = $seriesChange['folder_id'];
141+
$compositeId = $seriesChange['composite_id'];
142142

143-
$dbOut .= "INSERT INTO [series] VALUES ({$folderID}, {$compositeID});\n\n"; // insert
143+
$dbOut .= "INSERT INTO [series] VALUES ({$folderId}, {$compositeId});\n\n"; // insert
144144

145145
array_push($seriesTransactions, $seriesChange);
146146
}
@@ -167,15 +167,15 @@ public function generateData() {
167167
}
168168

169169
foreach ($metaDataEntries as $metadataChange) { // log metadata additions
170-
$videoID = $metadataChange['video_id'];
171-
$compositeID = $metadataChange['composite_id'];
170+
$videoId = $metadataChange['video_id'];
171+
$compositeId = $metadataChange['composite_id'];
172172
$uuid = $metadataChange['uuid'];
173173
$file_size = $metadataChange['file_size'];
174174
$duration = $metadataChange['duration'];
175175
$date_scanned = $metadataChange['date_scanned'];
176176
$date_uploaded = $metadataChange['date_uploaded'];
177177

178-
$dbOut .= "UPSERT INTO [metadata] VALUES ({$videoID}, {$compositeID}, {$uuid}, {$file_size}, {$duration}, {$date_scanned}, {$date_uploaded});\n\n"; // upsert
178+
$dbOut .= "UPSERT INTO [metadata] VALUES ({$videoId}, {$compositeId}, {$uuid}, {$file_size}, {$duration}, {$date_scanned}, {$date_uploaded});\n\n"; // upsert
179179

180180
array_push($metadataTransactions, $metadataChange);
181181
}
@@ -227,7 +227,7 @@ private function generateCategories($path) {
227227
$data = Storage::json('categories.json') ?? ['next_ID' => 1, 'categoryStructure' => []]; // array("anime"=>1,"tv"=>2,"yogscast"=>3); // read from json
228228
$scanned = array_filter(
229229
scandir($path),
230-
fn ($item) => $item !== '.' &&
230+
fn($item) => $item !== '.' &&
231231
$item !== '..' &&
232232
is_dir($path . DIRECTORY_SEPARATOR . $item)
233233
); // read folder structure
@@ -455,18 +455,12 @@ private function generateVideos($path, $folderStructure) {
455455
continue;
456456
}
457457

458-
$uuid = $fileMetaData['tags']['uuid'] ?? $fileMetaData['tags']['uid'] ?? null;
459-
$embeddingUuid = false;
460-
if (! $uuid || ! Uuid::isValid($uuid)) {
461-
$embeddingUuid = true;
462-
} else {
463-
// Check for an existing file (not deleted) with the scanned uuid only if a uuid was found on the video. Usually this means the user copied the previously scanned video to a new folder.
464-
$existingData = Metadata::where('uuid', $uuid)->first();
465-
$embeddingUuid = $existingData && File::exists(public_path("storage/media/$existingData->composite_id"));
466-
}
458+
$embeddedUuid = $fileMetaData['tags']['uuid'] ?? null;
459+
$compositeId = "$folder/$name";
460+
461+
['uuid' => $uuid, 'willEmbedUuid' => $willEmbedUuid] = $this->ResolveExistingUuid($embeddedUuid, $compositeId);
467462

468-
if ($embeddingUuid) {
469-
$uuid = Str::uuid()->toString();
463+
if ($willEmbedUuid) {
470464
$this->embedChain[] = new EmbedUidInMetadata($absolutePath, $uuid, $this->taskId, $currentID); // TODO: Make tagging user configurable, probably by library but always use a uuid
471465
}
472466

@@ -478,8 +472,8 @@ private function generateVideos($path, $folderStructure) {
478472
$rawDuration = $fileMetaData['format']['duration'] ?? $fileMetaData['streams'][0]['duration'] ?? null;
479473
$duration = is_numeric($rawDuration) ? floor($rawDuration) : null;
480474

481-
$generated = ['id' => $currentID, 'uuid' => $embeddingUuid ? null : $uuid, 'name' => $cleanName, 'path' => $key, 'folder_id' => $folderStructure[$folder]['id'], 'date' => date('Y-m-d h:i A', $mtime < $ctime ? $mtime : $ctime), 'action' => 'INSERT'];
482-
$metadata = ['video_id' => $currentID, 'composite_id' => "$folder/$name", 'uuid' => $uuid, 'file_size' => filesize($rawFile), 'duration' => $duration, 'mime_type' => $mime_type ?? null, 'media_type' => $media_type, 'date_scanned' => date('Y-m-d h:i:s A'), 'date_uploaded' => date('Y-m-d h:i A', $mtime < $ctime ? $mtime : $ctime)];
475+
$generated = ['id' => $currentID, 'uuid' => $willEmbedUuid ? null : $uuid, 'name' => $cleanName, 'path' => $key, 'folder_id' => $folderStructure[$folder]['id'], 'date' => date('Y-m-d h:i A', $mtime < $ctime ? $mtime : $ctime), 'action' => 'INSERT'];
476+
$metadata = ['video_id' => $currentID, 'composite_id' => $compositeId, 'uuid' => $uuid, 'file_size' => filesize($rawFile), 'duration' => $duration, 'mime_type' => $mime_type ?? null, 'media_type' => $media_type, 'date_scanned' => date('Y-m-d h:i:s A'), 'date_uploaded' => date('Y-m-d h:i A', $mtime < $ctime ? $mtime : $ctime)];
483477
$current[$key] = $currentID; // add to current
484478
array_push($changes, $generated); // add to new (insert)
485479
array_push($metadataChanges, $metadata); // create metadata (insert)
@@ -543,5 +537,56 @@ public function upsertMetadata($data) {
543537
private function generatedChangesText($count, $type) {
544538
return 'Generated ' . $count . ' ' . $type . ' Changes';
545539
}
540+
541+
private function ResolveExistingUuid(?string $embeddedUuid, string $compositeId): array {
542+
// sanitise input
543+
$embeddedUuid = $embeddedUuid && Uuid::isValid($embeddedUuid) ? $embeddedUuid : null;
544+
$logicalCompositeId = pathinfo($compositeId, PATHINFO_DIRNAME) . '/' . pathinfo($compositeId, PATHINFO_FILENAME);
545+
546+
/**
547+
* Scenario 1:
548+
* the file has a uuid embedded, and there is an existing metadata with the same uuid without an existing video
549+
* -> dont embed, use the embedded uuid and dont embed but update the metadata composite id
550+
*/
551+
if ($embeddedUuid && $metadata = Metadata::where('uuid', $embeddedUuid)->first()) {
552+
if ($metadata->video_id === null) {
553+
return [
554+
'uuid' => $metadata->uuid,
555+
'willEmbedUuid' => false,
556+
];
557+
} else {
558+
// the file was explicitly duplicated (copied from previously scanned library) -> force new uuid
559+
return [
560+
'uuid' => Str::uuid()->toString(),
561+
'willEmbedUuid' => true,
562+
];
563+
}
564+
}
565+
566+
/**
567+
* Scenario 2:
568+
* the file has no uuid, but its composite id matches an existing metadata also without an existing video
569+
* -> embed the existing metadata uuid into the file
570+
*/
571+
if (! $embeddedUuid && $metadata = Metadata::where('composite_id', 'LIKE', $logicalCompositeId . '.%')->orderBy('updated_at', 'desc')->first()) {
572+
if ($metadata->video_id === null) {
573+
return [
574+
'uuid' => $metadata->uuid,
575+
'willEmbedUuid' => true,
576+
];
577+
}
578+
}
579+
580+
/**
581+
* Scenario 3:
582+
* the file has no uuid and matches no metadata
583+
* -> generate new uuid and upsert new metadata
584+
*/
585+
return [
586+
'uuid' => Str::uuid()->toString(),
587+
'willEmbedUuid' => true,
588+
];
589+
}
590+
}
591+
class BatchCancelledException extends \Exception {
546592
}
547-
class BatchCancelledException extends \Exception {}

0 commit comments

Comments
 (0)