diff --git a/app/Http/Controllers/Api/Volumes/Filters/FilenameController.php b/app/Http/Controllers/Api/Volumes/Filters/FilenameController.php
index 87b1f60da..84ff1576b 100644
--- a/app/Http/Controllers/Api/Volumes/Filters/FilenameController.php
+++ b/app/Http/Controllers/Api/Volumes/Filters/FilenameController.php
@@ -33,6 +33,19 @@ public function index($id, $pattern)
// Escape trailing backslashes, else there would be an error with ilike.
$pattern = preg_replace('/\\\\$/', '\\\\\\\\', $pattern);
+ $files = explode(',', $pattern);
+ if (count($files) > 1) {
+ $files = collect($files)->map(
+ function ($f) {
+ $filename = trim($f);
+ return strlen($filename) > 0 ? $filename : null;
+ }
+ )->whereNotNull();
+
+ return $files->chunk(1000)->flatMap(fn ($chunk)
+ => $volume->files()->whereIn('filename', $chunk)->pluck('id'));
+ }
+
return $volume->files()
->where('filename', 'ilike', str_replace('*', '%', $pattern))
->pluck('id');
diff --git a/resources/views/volumes/clone.blade.php b/resources/views/volumes/clone.blade.php
index d21c1aecc..8b6abbcb9 100644
--- a/resources/views/volumes/clone.blade.php
+++ b/resources/views/volumes/clone.blade.php
@@ -74,7 +74,7 @@
v-on:keydown.enter="loadFilesMatchingPattern">
@endif
- Filter by using a pattern that matches specific file names. A pattern may contain the wildcard character * that matches any string of zero or more characters
+ Filter by using a list of comma-separated file names or a pattern that matches specific file names. A pattern may contain the wildcard character * that matches any string of zero or more characters
diff --git a/tests/php/Http/Controllers/Api/Volumes/Filters/FilenameControllerTest.php b/tests/php/Http/Controllers/Api/Volumes/Filters/FilenameControllerTest.php
index 0b1d70eaa..b437f8a74 100644
--- a/tests/php/Http/Controllers/Api/Volumes/Filters/FilenameControllerTest.php
+++ b/tests/php/Http/Controllers/Api/Volumes/Filters/FilenameControllerTest.php
@@ -114,4 +114,55 @@ public function testIndexVideo()
->assertSimilarJson([$video->id, $video2->id, $video3->id]);
$response->assertStatus(200);
}
+
+ public function testIndexCommaSeparatedImageFilenames()
+ {
+ $img = $this->volume()->id;
+
+ $image = ImageTest::create([
+ 'volume_id' => $img,
+ 'filename' => 'a.jpg',
+ ]);
+ $image2 = ImageTest::create([
+ 'volume_id' => $img,
+ 'filename' => 'b.jpg',
+ ]);
+
+ $this->beGuest();
+ $response = $this->json('GET', "/api/v1/volumes/{$img}/files/filter/filename/a.jpg")
+ ->assertExactJson([$image->id]);
+ $response->assertStatus(200);
+
+ $response = $this->json('GET', "/api/v1/volumes/{$img}/files/filter/filename/a.jpg%2Cb.jpg")
+ ->assertExactJson([$image->id, $image2->id]);
+ $response->assertStatus(200);
+
+ $response = $this->json('GET', "/api/v1/volumes/{$img}/files/filter/filename/%2C%2C%20%20a.jpg%2Cb.jpg%20")
+ ->assertExactJson([$image->id, $image2->id]);
+ $response->assertStatus(200);
+ }
+
+ public function testIndexCommaSeparatedVideoFilenames()
+ {
+ $vid = $this->volume(['media_type_id' => MediaType::videoId()])->id;
+
+ $video = VideoTest::create([
+ 'volume_id' => $vid,
+ 'filename' => 'a.mp4',
+ ]);
+ $video2 = VideoTest::create([
+ 'volume_id' => $vid,
+ 'filename' => 'b.mp4',
+ ]);
+
+ $this->beGuest();
+
+ $response = $this->json('GET', "/api/v1/volumes/{$vid}/files/filter/filename/a.mp4%2Cb.mp4")
+ ->assertExactJson([$video->id, $video2->id]);
+ $response->assertStatus(200);
+
+ $response = $this->json('GET', "/api/v1/volumes/{$vid}/files/filter/filename/%2C%2C%20%20a.mp4%2Cb.mp4%20")
+ ->assertExactJson([$video->id, $video2->id]);
+ $response->assertStatus(200);
+ }
}