Speed up tag thumb load
parent
6760e7d7e9
commit
ff502b5068
|
@ -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
|
||||
|
|
|
@ -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"]);
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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 */
|
||||
|
|
|
@ -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,
|
||||
|
|
Loading…
Reference in New Issue