fix(gallery): Rescan Output Folder drops the server listing cache and rewalks
The button only re-requested the listing, which the server answers from a 30-second in-memory cache, so a rescan showed exactly what was already on screen. - POST /prompt_manager/gallery/rescan invalidates the gallery cache, rewalks every output root and returns the file and root counts - the button calls it, closes the settings modal, reloads the folder tree and the first page, and reports what it found
This commit is contained in:
@@ -397,6 +397,11 @@ class ImageRoutesMixin:
|
||||
async def get_gallery_subfolders_route(request):
|
||||
return await self.get_gallery_subfolders(request)
|
||||
|
||||
# POST: drops the server-side listing cache and rewalks the output roots.
|
||||
@routes.post("/prompt_manager/gallery/rescan")
|
||||
async def rescan_gallery_route(request):
|
||||
return await self.rescan_gallery(request)
|
||||
|
||||
def _present_images(self, images):
|
||||
"""Image dicts ready for a response: urls added, server paths hidden."""
|
||||
self._enrich_images(images)
|
||||
@@ -736,6 +741,27 @@ class ImageRoutesMixin:
|
||||
{"success": False, "error": _safe_error(e)}, status=500
|
||||
)
|
||||
|
||||
async def rescan_gallery(self, request):
|
||||
"""Forget the cached listing and rewalk every output root now.
|
||||
|
||||
The listing is cached for ``_gallery_cache_ttl`` seconds; the gallery's
|
||||
Rescan button needs files added or removed on disk to show up at once.
|
||||
"""
|
||||
try:
|
||||
self.invalidate_gallery_cache()
|
||||
output_dirs = list(self._get_all_output_dirs())
|
||||
total = 0
|
||||
for output_path in output_dirs:
|
||||
total += len(await self._get_gallery_files(output_path))
|
||||
return web.json_response(
|
||||
{"success": True, "total": total, "roots": len(output_dirs)}
|
||||
)
|
||||
except Exception:
|
||||
self.logger.exception("Gallery rescan error")
|
||||
return web.json_response(
|
||||
{"success": False, "error": "Failed to rescan the gallery"}, status=500
|
||||
)
|
||||
|
||||
async def get_gallery_subfolders(self, request):
|
||||
"""Get distinct subfolders from gallery output directories."""
|
||||
try:
|
||||
|
||||
@@ -1717,6 +1717,46 @@ if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
||||
|
||||
class TestGalleryRescan(ImageAPITestCase):
|
||||
"""POST /prompt_manager/gallery/rescan drops the listing cache and rewalks."""
|
||||
|
||||
URL = "/prompt_manager/images/output"
|
||||
|
||||
async def _json(self, method, path, **kwargs):
|
||||
resp = await self.client.request(method, path, **kwargs)
|
||||
return resp.status, await resp.json()
|
||||
|
||||
async def test_rescan_makes_new_files_visible_before_the_cache_expires(self):
|
||||
self.api._gallery_cache_ttl = 3600 # the cache alone would hide the new file
|
||||
make_png(self.output_dir / "a.png")
|
||||
_, first = await self._json("GET", self.URL)
|
||||
self.assertEqual(first["total"], 1)
|
||||
|
||||
make_png(self.output_dir / "b.png")
|
||||
_, stale = await self._json("GET", self.URL)
|
||||
self.assertEqual(stale["total"], 1)
|
||||
|
||||
status, data = await self._json("POST", "/prompt_manager/gallery/rescan")
|
||||
_, fresh = await self._json("GET", self.URL)
|
||||
|
||||
self.assertEqual(status, 200)
|
||||
self.assertTrue(data["success"])
|
||||
self.assertEqual(data["total"], 2)
|
||||
self.assertEqual(data["roots"], 1)
|
||||
self.assertEqual(fresh["total"], 2)
|
||||
|
||||
async def test_rescan_is_post_only(self):
|
||||
resp = await self.client.request("GET", "/prompt_manager/gallery/rescan")
|
||||
self.assertEqual(resp.status, 405)
|
||||
|
||||
async def test_rescan_reports_internal_failure(self):
|
||||
self.api._scan_gallery_files_sync = _raise
|
||||
status, data = await self._json("POST", "/prompt_manager/gallery/rescan")
|
||||
self.assertEqual(status, 500)
|
||||
self.assertFalse(data["success"])
|
||||
self.assertNotIn("boom", json.dumps(data))
|
||||
|
||||
|
||||
class TestOutputScanHelpers(ImageAPITestCase):
|
||||
"""Stable ids for filesystem entries, no symlink reads, stop on disconnect."""
|
||||
|
||||
|
||||
+6
-3
@@ -2123,9 +2123,12 @@ Seed: ${this.currentMetadata.seed || 'Unknown'}`;
|
||||
btn.textContent = 'Scanning...';
|
||||
|
||||
try {
|
||||
// Force reload images
|
||||
await this.loadImages();
|
||||
this.showNotification('Folder rescanned successfully!', 'success');
|
||||
// The listing is cached on the server; ask it to rewalk the folders first
|
||||
const result = await this.api.post('/prompt_manager/gallery/rescan', {});
|
||||
this.hideSettings();
|
||||
await Promise.all([this.loadFolderTree(), this.loadImages(1)]);
|
||||
const where = result.roots === 1 ? 'the output folder' : `${result.roots} folders`;
|
||||
this.showNotification(`Rescanned ${where}: ${result.total} files`, 'success');
|
||||
} catch (error) {
|
||||
console.error('Rescan error:', error);
|
||||
this.showNotification('Failed to rescan folder', 'error');
|
||||
|
||||
Reference in New Issue
Block a user