Speed up tag thumb load

cache
Varun Patil 2022-10-07 17:57:48 -07:00
parent 6760e7d7e9
commit ff502b5068
5 changed files with 91 additions and 31 deletions

View File

@ -319,6 +319,14 @@ class ApiController extends Controller {
$list = $this->timelineQuery->getTags(
$folder,
);
// Preload all tag previews
foreach ($list as &$tag) {
$tag["previews"] = $this->timelineQuery->getTagPreviews(
$folder, $tag["id"],
);
}
return new JSONResponse($list, Http::STATUS_OK);
}
@ -349,12 +357,19 @@ class ApiController extends Controller {
$list = $this->timelineQuery->getFaces(
$folder,
);
// Preload all face previews
foreach ($list as &$face) {
$face["previews"] = $this->timelineQuery->getFacePreviews(
$folder, $face["id"],
);
}
return new JSONResponse($list, Http::STATUS_OK);
}
/**
* @NoAdminRequired
* @NoCSRFRequired
*
* Get preview objects for a face ID
* @return JSONResponse

View File

@ -44,6 +44,7 @@ trait TimelineQueryFaces {
// Post process
foreach($faces as &$row) {
$row['id'] = intval($row['id']);
$row["name"] = $row["title"];
unset($row["title"]);
$row["count"] = intval($row["count"]);

View File

@ -37,7 +37,7 @@ trait TimelineQueryTags {
// SELECT visible tag name and count of photos
$count = $query->func()->count($query->createFunction('DISTINCT m.fileid'), 'count');
$query->select('st.name', $count)->from('systemtag', 'st')->where(
$query->select('st.id', 'st.name', $count)->from('systemtag', 'st')->where(
$query->expr()->eq('visibility', $query->createNamedParameter(1)),
);
@ -62,9 +62,39 @@ trait TimelineQueryTags {
// Post process
foreach($tags as &$row) {
$row["id"] = intval($row["id"]);
$row["count"] = intval($row["count"]);
}
return $tags;
}
public function getTagPreviews(Folder $folder, int $tagId) {
$query = $this->connection->getQueryBuilder();
// SELECT all photos with this tag
$query->select('f.fileid', 'f.etag')->from('systemtag_object_mapping', 'stom')->where($query->expr()->andX(
$query->expr()->eq('stom.objecttype', $query->createNamedParameter("files")),
$query->expr()->eq('stom.systemtagid', $query->createNamedParameter($tagId, IQueryBuilder::PARAM_INT)),
));
// WHERE these items are memories indexed photos
$query->innerJoin('stom', 'memories', 'm', $query->expr()->eq('m.fileid', 'stom.objectid'));
// WHERE these photos are in the user's requested folder recursively
$query->innerJoin('m', 'filecache', 'f', $this->getFilecacheJoinQuery($query, $folder, true, false));
// MAX 4 results
$query->setMaxResults(4);
// FETCH all previews
$previews = $query->executeQuery()->fetchAll();
// Post-process
foreach($previews as &$row) {
$row["fileid"] = intval($row["fileid"]);
}
return $previews;
}
}

View File

@ -91,46 +91,53 @@ export default class Tag extends Mixins(GlobalMixin) {
// Look for cache
if (this.data.previews) {
this.previews = this.data.previews;
this.error = this.previews.length === 0;
this.processPreviews();
return;
}
if (this.isFace) {
await this.refreshPreviewsFace();
} else {
await this.refreshPreviewsTag();
try {
if (this.isFace) {
await this.refreshPreviewsFace();
} else {
await this.refreshPreviewsTag();
}
this.processPreviews();
} catch (e) {
console.error(e);
this.error = true;
}
}
/** Refresh previews for tag */
async refreshPreviewsTag() {
const url = `/apps/memories/api/days/*?limit=4&tag=${this.data.name}`;
try {
const res = await axios.get<IPhoto[]>(generateUrl(url));
if (res.data.length < 4) {
res.data = res.data.slice(0, 1);
}
res.data.forEach((p) => p.flag = 0);
this.previews = this.data.previews = res.data;
} catch (e) {
this.error = true;
console.error(e);
}
const res = await axios.get<IPhoto[]>(generateUrl(url));
this.data.previews = res.data;
}
/** Refresh previews for face */
async refreshPreviewsFace() {
const url = `/apps/memories/api/face-previews/${this.data.faceid}`;
try {
const res = await axios.get<IFaceDetection[]>(generateUrl(url));
res.data.forEach((p) => p.flag = 0);
const face = this.chooseFaceDetection(res.data);
this.previews = this.data.previews = [face];
} catch (e) {
this.error = true;
console.error(e);
const res = await axios.get<IFaceDetection[]>(generateUrl(url));
this.data.previews = res.data;
}
/** Process previews */
processPreviews() {
this.data.previews.forEach((p) => p.flag = 0);
if (this.isFace) {
const face = this.chooseFaceDetection(this.data.previews as IFaceDetection[]);
this.previews = [face];
} else {
let data = this.data.previews;
if (data.length < 4) {
data = data.slice(0, 1);
}
this.previews = data;
}
this.error = this.previews.length === 0;
}
/** Open tag */

View File

@ -433,8 +433,10 @@ export async function getOnThisDayData(): Promise<IDay[]> {
export async function getTagsData(): Promise<IDay[]> {
// Query for photos
let data: {
id: number;
count: number;
name: string;
previews: IPhoto[];
}[] = [];
try {
const res = await axios.get<typeof data>(generateUrl('/apps/memories/api/tags'));
@ -443,13 +445,15 @@ export async function getTagsData(): Promise<IDay[]> {
throw e;
}
// Add flag to previews
data.forEach(t => t.previews?.forEach((preview) => preview.flag = 0));
// Convert to days response
return [{
dayid: constants.TagDayID.TAGS,
count: data.length,
detail: data.map((tag) => ({
name: tag.name,
count: tag.count,
...tag,
fileid: hashCode(tag.name),
flag: constants.c.FLAG_IS_TAG,
istag: true,
@ -466,6 +470,7 @@ export async function getTagsData(): Promise<IDay[]> {
id: number;
count: number;
name: string;
previews: IPhoto[];
}[] = [];
try {
const res = await axios.get<typeof data>(generateUrl('/apps/memories/api/faces'));
@ -474,13 +479,15 @@ export async function getTagsData(): Promise<IDay[]> {
throw e;
}
// Add flag to previews
data.forEach(t => t.previews?.forEach((preview) => preview.flag = 0));
// Convert to days response
return [{
dayid: constants.TagDayID.FACES,
count: data.length,
detail: data.map((face) => ({
name: face.name,
count: face.count,
...face,
fileid: hashCode(face.name),
faceid: face.id,
istag: true,