gallery optimizations

This commit is contained in:
Vladimir Mandic
2024-03-26 09:02:30 -04:00
parent a35e8002d9
commit db11bc59d1
3 changed files with 54 additions and 43 deletions
+17 -13
View File
@@ -108,12 +108,12 @@ async function delayFetchThumb(fn) {
}
class GalleryFile extends HTMLElement {
constructor({ folder, file, size, mtime }) {
constructor(folder, file) {
super();
this.folder = decodeURI(folder);
this.name = decodeURI(file);
this.size = size;
this.mtime = new Date(1000 * mtime);
this.size = 0;
this.mtime = 0;
this.hash = undefined;
this.exif = '';
this.width = 0;
@@ -163,6 +163,8 @@ class GalleryFile extends HTMLElement {
this.exif = cache.exif;
this.width = cache.width;
this.height = cache.height;
this.size = cache.size;
this.mtime = new Date(1000 * cache.mtime);
} else {
try {
const json = await delayFetchThumb(this.src);
@@ -173,6 +175,8 @@ class GalleryFile extends HTMLElement {
this.exif = json.exif;
this.width = json.width;
this.height = json.height;
this.size = json.size;
this.mtime = new Date(1000 * json.mtime);
await idbAdd({
hash: this.hash,
folder: this.folder,
@@ -324,37 +328,37 @@ async function fetchFiles(evt) { // fetch file-by-file list over websockets
if (ws && ws.readyState === WebSocket.OPEN) ws.close(); // abort previous request
ws = new WebSocket(`${url}/sdapi/v1/browser/files`);
await wsConnect(ws);
let numFiles = 0;
el.status.innerText = `Folder | ${evt.target.name}`;
const t0 = performance.now();
let numFiles = 0;
let t1 = performance.now();
let lastDir;
let fragment = document.createDocumentFragment();
ws.onmessage = (event) => { // time is 20% list 80% create item
ws.onmessage = (event) => {
numFiles++;
t1 = performance.now();
if (event.data === '#END#') {
const data = event.data.split('##F##');
if (data[0] === '#END#') {
ws.close();
} else {
const json = JSON.parse(event.data);
const file = new GalleryFile(json);
const file = new GalleryFile(data[0], data[1]);
fragment.appendChild(file);
if (numFiles % 100 === 0) {
el.status.innerText = `Folder | ${evt.target.name} | ${numFiles.toLocaleString()} images | ${Math.floor(t1 - t0).toLocaleString()}ms`;
el.files.appendChild(fragment);
fragment = document.createDocumentFragment();
}
addSeparators();
el.status.innerText = `Folder | ${evt.target.name} | ${numFiles.toLocaleString()} images | ${Math.floor(t1 - t0).toLocaleString()}ms`;
}
};
ws.onclose = (event) => {
el.files.appendChild(fragment);
// log('gallery ws file enum', event);
log(`gallery: folder=${evt.target.name} num=${numFiles} time=${Math.floor(t1 - t0)}ms`);
el.status.innerText = `Folder | ${evt.target.name} | ${numFiles.toLocaleString()} images | ${Math.floor(t1 - t0).toLocaleString()}ms`;
addSeparators();
};
ws.onerror = (event) => {
log('gallery ws error', event);
};
ws.send(evt.target.name);
ws.send(encodeURI(evt.target.name));
}
async function pruneImages() {
+36 -29
View File
@@ -76,6 +76,7 @@ def register_api(app: FastAPI): # register api
def get_video_thumbnail(filepath):
from modules.ui_control_helpers import get_video_params
try:
stat = os.stat(filepath)
frames, fps, duration, width, height, codec, frame = get_video_params(filepath, capture=True)
h = shared.opts.extra_networks_card_size
w = shared.opts.extra_networks_card_size if shared.opts.browser_fixed_width else width * h // height
@@ -90,12 +91,41 @@ def register_api(app: FastAPI): # register api
'data': data_url,
'width': width,
'height': height,
'size': stat.st_size,
'mtime': stat.st_mtime,
}
return content
except Exception as e:
shared.log.error(f'Gallery video: file="{filepath}" {e}')
return {}
def get_image_thumbnail(filepath):
try:
stat = os.stat(filepath)
image = Image.open(filepath)
geninfo, _items = images.read_info_from_image(image)
h = shared.opts.extra_networks_card_size
w = shared.opts.extra_networks_card_size if shared.opts.browser_fixed_width else image.width * h // image.height
width, height = image.width, image.height
image = image.convert('RGB')
image.thumbnail((w, h), Image.Resampling.HAMMING)
buffered = io.BytesIO()
image.save(buffered, format='jpeg')
data_url = f'data:image/jpeg;base64,{base64.b64encode(buffered.getvalue()).decode("ascii")}'
image.close()
content = {
'exif': geninfo,
'data': data_url,
'width': width,
'height': height,
'size': stat.st_size,
'mtime': stat.st_mtime,
}
return content
except Exception as e:
shared.log.error(f'Gallery image: file="{filepath}" {e}')
return {}
@app.get('/sdapi/v1/browser/folders', response_model=List[str])
def get_folders():
folders = [shared.opts.data.get(f, '') for f in OPTS_FOLDERS]
@@ -114,29 +144,11 @@ def register_api(app: FastAPI): # register api
@app.get("/sdapi/v1/browser/thumb", response_model=dict)
async def get_thumb(file: str):
try:
decoded = unquote(file)
decoded = unquote(file).replace('%3A', ':')
if decoded.lower().endswith('.mp4'):
content = get_video_thumbnail(decoded)
return JSONResponse(content=content)
return JSONResponse(content=get_video_thumbnail(decoded))
else:
image = Image.open(decoded)
geninfo, _items = images.read_info_from_image(image)
h = shared.opts.extra_networks_card_size
w = shared.opts.extra_networks_card_size if shared.opts.browser_fixed_width else image.width * h // image.height
width, height = image.width, image.height
image = image.convert('RGB')
image.thumbnail((w, h), Image.Resampling.HAMMING)
buffered = io.BytesIO()
image.save(buffered, format='jpeg')
data_url = f'data:image/jpeg;base64,{base64.b64encode(buffered.getvalue()).decode("ascii")}'
image.close()
content = {
'exif': geninfo,
'data': data_url,
'width': width,
'height': height,
}
return JSONResponse(content=content)
return JSONResponse(content=get_image_thumbnail(decoded))
except Exception as e:
shared.log.error(f'Gallery: {file} {e}')
content = { 'error': str(e) }
@@ -147,19 +159,14 @@ def register_api(app: FastAPI): # register api
try:
await manager.connect(ws)
folder = await ws.receive_text()
folder = unquote(folder).replace('%3A', ':')
t0 = time.time()
numFiles = 0
for f in files_cache.directory_files(folder, recursive=True):
numFiles += 1
file = os.path.relpath(f, folder)
stat = os.stat(f)
dct = {
'folder': quote(folder),
'file': quote(file),
'size': stat.st_size,
'mtime': stat.st_mtime,
}
await manager.send(ws, dct)
msg = quote(folder) + '##F##' + quote(file)
await manager.send(ws, msg)
await manager.send(ws, '#END#')
t1 = time.time()
shared.log.debug(f'Gallery: folder="{folder}" files={numFiles} time={t1-t0:.3f}')
+1 -1
Submodule wiki updated: 1dabbb0192...108b183962