This commit is contained in:
mike
2026-06-27 23:01:16 +02:00
parent 52ae51fef3
commit 2ada5fb559
8 changed files with 282 additions and 105 deletions

View File

@@ -2220,20 +2220,171 @@
// --- HYDRATION_START ---
const PRELOADED_IMAGES = [
"20260627_201629_7_20260627_201343_image.nobg.png",
"20260627_201629_7_20260627_201343_image.png",
"20260627_225051_mr_image.png",
"20260627_224340_mr_image.png",
"20260627_224013_mr_image.png",
"20260627_223316_image.png",
"20260627_223304_image.png",
"20260627_223252_image.png",
"20260627_223028_image.png",
"20260627_223017_image.png",
"20260627_223005_image.png",
"20260627_222926_image.png",
"20260627_222915_image.png",
"20260627_222904_image.png",
"20260627_222806_mr_image.png",
"20260627_222321_image.png",
"20260627_222310_image.png",
"20260627_222259_image.png",
"20260627_222112_mr_image.png",
"20260627_222047_mr_image.png",
"20260627_222015_mr_image.png",
"20260626_034949_pose_jb.nobg.png",
"cg_0ed9a15a_face.png",
"_turntable/cg_7c7b22c9/views/view_022_330deg.png",
"20260618_015124_20260618_010617_20260615_153426_img_12.nobg.png",
"_turntable/cg_5991f3f2/views/view_002_030deg.png",
"_turntable/cg_5991f3f2/views/view_022_330deg.png",
"_turntable/up_6ed4293c/views/view_021_315deg.png",
"_turntable/up_6ed4293c/views/view_020_300deg.png",
"20260627_213910_best_02_person_0.874_2026-06-27_12-18-49.png",
"20260627_213840_best_02_person_0.874_2026-06-27_12-18-49.png",
"20260627_213816_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_213756_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_213743_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_213727_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213711_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213626_best_02_person_0.874_2026-06-27_12-18-49.png",
"20260627_213613_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_213559_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213517_image.png",
"20260627_213504_image.png",
"20260627_213451_image.png",
"20260627_213241_12_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_213227_11_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"_turntable/cg_74544975/views/view_023_345deg.png",
"20260627_213215_10_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"_turntable/cg_74544975/views/view_022_330deg.png",
"_turntable/cg_74544975/views/view_021_315deg.png",
"_turntable/cg_74544975/views/view_020_300deg.png",
"_turntable/cg_74544975/views/view_019_285deg.png",
"_turntable/cg_74544975/views/view_018_270deg.png",
"20260627_213202_9_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_213149_8_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"_turntable/cg_74544975/views/view_004_060deg.png",
"_turntable/up_6ed4293c/views/view_019_285deg.png",
"_turntable/cg_74544975/views/view_001_015deg.png",
"_turntable/cg_74544975/views/view_000_000deg.png",
"20260627_213102_12_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213037_11_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_213013_10_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212949_9_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212937_3_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_212925_8_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212913_2_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_212901_7_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212848_1_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_212836_6_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212824_0_20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg.png",
"20260627_212814_best_02_person_0.874_2026-06-27_20-05-05.png",
"20260627_212814_best_02_person_0.874_2026-06-27_20-05-05.jpg",
"20260627_212814_best_01_person_0.874_2026-06-27_20-05-05.png",
"20260627_212814_best_00_person_0.874_2026-06-27_20-05-05.png",
"20260627_212814_best_00_person_0.874_2026-06-27_20-05-05.jpg",
"20260627_212812_5_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212803_best_01_person_0.874_2026-06-27_20-05-05.jpg",
"20260627_212800_4_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212748_3_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212735_2_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212726_best_02_person_0.874_2026-06-27_12-18-49.png",
"20260627_212726_best_01_person_0.874_2026-06-27_12-18-49.png",
"20260627_212726_best_01_person_0.874_2026-06-27_12-18-49.jpg",
"20260627_212726_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212726_best_00_person_0.874_2026-06-27_12-18-49.jpg",
"20260627_212723_1_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212710_0_20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"20260627_212658_best_00_person_0.874_2026-06-27_12-18-49.png",
"_turntable/up_6ed4293c/views/view_018_270deg.png",
"_turntable/up_6ed4293c/views/view_017_255deg.png",
"_turntable/up_6ed4293c/views/view_016_240deg.png",
"_turntable/up_6ed4293c/views/view_015_225deg.png",
"_turntable/up_6ed4293c/views/view_014_210deg.png",
"_turntable/up_6ed4293c/views/view_013_195deg.png",
"_turntable/up_6ed4293c/views/view_012_180deg.png",
"_turntable/up_6ed4293c/views/view_011_165deg.png",
"_turntable/up_6ed4293c/views/view_010_150deg.png",
"_turntable/up_6ed4293c/views/view_009_135deg.png",
"_turntable/up_6ed4293c/views/view_008_120deg.png",
"_turntable/up_6ed4293c/views/view_007_105deg.png",
"_turntable/up_6ed4293c/views/view_006_090deg.png",
"_turntable/up_6ed4293c/views/view_005_075deg.png",
"_turntable/up_6ed4293c/views/view_004_060deg.png",
"_turntable/up_6ed4293c/views/view_003_045deg.png",
"_turntable/up_6ed4293c/views/view_002_030deg.png",
"_turntable/up_6ed4293c/views/view_001_015deg.png",
"_turntable/up_6ed4293c/views/view_000_000deg.png",
"20260627_204815_image.png",
"20260627_204804_image.png",
"20260627_204756_image.png",
"_turntable/cg_f85e7ae1/views/view_023_345deg.png",
"_turntable/cg_f85e7ae1/views/view_013_195deg.png",
"_turntable/cg_f85e7ae1/views/view_012_180deg.png",
"_turntable/cg_f85e7ae1/views/view_010_150deg.png",
"_turntable/cg_f85e7ae1/views/view_001_015deg.png",
"_turntable/cg_f85e7ae1/views/view_000_000deg.png",
"_turntable/cg_75340e8e/views/view_017_255deg.png",
"_turntable/cg_75340e8e/views/view_016_240deg.png",
"_turntable/cg_75340e8e/views/view_014_210deg.png",
"_turntable/cg_75340e8e/views/view_013_195deg.png",
"_turntable/cg_75340e8e/views/view_012_180deg.png",
"_turntable/cg_75340e8e/views/view_011_165deg.png",
"_turntable/cg_75340e8e/views/view_010_150deg.png",
"_turntable/cg_75340e8e/views/view_009_135deg.png",
"_turntable/cg_75340e8e/views/view_008_120deg.png",
"_turntable/cg_75340e8e/views/view_007_105deg.png",
"_turntable/cg_75340e8e/views/view_023_345deg.png",
"_turntable/cg_75340e8e/views/view_001_015deg.png",
"_turntable/cg_75340e8e/views/view_000_000deg.png",
"20260627_203706_11_20260627_200330_image.png",
"up_7b6eaabb_face.png",
"20260627_203654_11_20260627_200330_image.png",
"20260627_203642_11_20260627_200330_image.png",
"20260627_203626_image.png",
"20260627_203607_image.png",
"20260627_203549_image.png",
"20260627_203531_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_203514_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_203459_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_203349_image.png",
"20260627_203337_image.png",
"20260627_203324_image.png",
"20260627_203312_image.png",
"20260627_203300_image.png",
"20260627_203247_image.png",
"up_c8be3aa7_face.png",
"20260627_203235_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_203223_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_203211_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_203127_image.png",
"20260627_203105_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_203054_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_203044_image.png",
"20260627_203032_image.png",
"_turntable/up_c8be3aa7/views/view_002_030deg.png",
"_turntable/up_c8be3aa7/views/view_003_045deg.png",
"20260627_201807_12_20260627_201343_image.png",
"20260627_201753_Screenshot_From_2026-06-27_12-32-39.png",
"20260627_201751_11_20260627_201343_image.png",
"20260627_201733_10_20260627_201343_image.png",
"20260627_201711_9_20260627_201343_image.png",
"20260627_201648_8_20260627_201343_image.png",
"20260627_201629_7_20260627_201343_image.png",
"20260627_201622_Screenshot_From_2026-06-27_20-04-55.png",
"20260627_201614_Screenshot_From_2026-06-27_20-04-11.png",
"20260627_201608_6_20260627_201343_image.png",
"20260627_201558_Screenshot_From_2026-06-27_19-59-43.png",
"20260627_201548_5_20260627_201343_image.png",
"20260627_201525_4_20260627_201343_image.png",
"20260627_201518_image.png",
"20260627_201500_3_20260627_201343_image.png",
"20260627_201439_2_20260627_201343_image.png",
@@ -2244,16 +2395,10 @@
"_turntable/up_c8be3aa7/views/view_006_090deg.png",
"_turntable/up_c8be3aa7/views/view_005_075deg.png",
"_turntable/up_c8be3aa7/views/view_004_060deg.png",
"_turntable/up_c8be3aa7/views/view_003_045deg.png",
"_turntable/up_c8be3aa7/views/view_002_030deg.png",
"20260627_200801_12_20260627_200330_image.png",
"_turntable/up_c8be3aa7/views/view_001_015deg.png",
"20260627_200711_11_20260627_200330_image.png",
"20260627_200632_9_20260627_200330_image.png",
"20260627_200534_6_20260627_200330_image.png",
"20260627_200506_image.png",
"20260627_200458_4_20260627_200330_image.png",
"20260627_200440_3_20260627_200330_image.png",
"20260627_200422_2_20260627_200330_image.png",
"20260627_200414_image.png",
"20260627_200405_1_20260627_200330_image.png",
@@ -2454,31 +2599,17 @@
"_turntable/cg_e964fb19/views/view_002_030deg.png",
"_turntable/cg_e964fb19/views/view_001_015deg.png",
"_turntable/cg_e964fb19/views/view_000_000deg.png",
"_turntable/cg_75340e8e/views/view_023_345deg.png",
"_turntable/cg_75340e8e/views/view_022_330deg.png",
"_turntable/cg_75340e8e/views/view_021_315deg.png",
"_turntable/cg_75340e8e/views/view_020_300deg.png",
"_turntable/cg_75340e8e/views/view_019_285deg.png",
"_turntable/cg_75340e8e/views/view_018_270deg.png",
"_turntable/cg_75340e8e/views/view_017_255deg.png",
"_turntable/cg_75340e8e/views/view_016_240deg.png",
"_turntable/cg_75340e8e/views/view_015_225deg.png",
"_turntable/cg_75340e8e/views/view_014_210deg.png",
"_turntable/cg_75340e8e/views/view_013_195deg.png",
"_turntable/cg_75340e8e/views/view_012_180deg.png",
"_turntable/cg_75340e8e/views/view_011_165deg.png",
"_turntable/cg_75340e8e/views/view_010_150deg.png",
"_turntable/cg_75340e8e/views/view_009_135deg.png",
"_turntable/cg_75340e8e/views/view_008_120deg.png",
"_turntable/cg_75340e8e/views/view_007_105deg.png",
"_turntable/cg_75340e8e/views/view_006_090deg.png",
"_turntable/cg_75340e8e/views/view_005_075deg.png",
"_turntable/cg_75340e8e/views/view_004_060deg.png",
"_turntable/cg_75340e8e/views/view_003_045deg.png",
"_turntable/cg_75340e8e/views/view_002_030deg.png",
"_turntable/cg_75340e8e/views/view_001_015deg.png",
"_turntable/cg_75340e8e/views/view_000_000deg.png",
"_turntable/cg_f85e7ae1/views/view_023_345deg.png",
"_turntable/cg_f85e7ae1/views/view_022_330deg.png",
"_turntable/cg_f85e7ae1/views/view_021_315deg.png",
"_turntable/cg_f85e7ae1/views/view_020_300deg.png",
@@ -2488,10 +2619,7 @@
"_turntable/cg_f85e7ae1/views/view_016_240deg.png",
"_turntable/cg_f85e7ae1/views/view_015_225deg.png",
"_turntable/cg_f85e7ae1/views/view_014_210deg.png",
"_turntable/cg_f85e7ae1/views/view_013_195deg.png",
"_turntable/cg_f85e7ae1/views/view_012_180deg.png",
"_turntable/cg_f85e7ae1/views/view_011_165deg.png",
"_turntable/cg_f85e7ae1/views/view_010_150deg.png",
"_turntable/cg_f85e7ae1/views/view_009_135deg.png",
"_turntable/cg_f85e7ae1/views/view_008_120deg.png",
"_turntable/cg_f85e7ae1/views/view_007_105deg.png",
@@ -2500,8 +2628,6 @@
"_turntable/cg_f85e7ae1/views/view_004_060deg.png",
"_turntable/cg_f85e7ae1/views/view_003_045deg.png",
"_turntable/cg_f85e7ae1/views/view_002_030deg.png",
"_turntable/cg_f85e7ae1/views/view_001_015deg.png",
"_turntable/cg_f85e7ae1/views/view_000_000deg.png",
"_turntable/up_c31bb439/views/view_023_345deg.png",
"_turntable/up_c31bb439/views/view_022_330deg.png",
"_turntable/up_c31bb439/views/view_021_315deg.png",
@@ -2550,12 +2676,6 @@
"_turntable/cg_4671b6c4/views/view_002_030deg.png",
"_turntable/cg_4671b6c4/views/view_001_015deg.png",
"_turntable/cg_4671b6c4/views/view_000_000deg.png",
"_turntable/cg_74544975/views/view_023_345deg.png",
"_turntable/cg_74544975/views/view_022_330deg.png",
"_turntable/cg_74544975/views/view_021_315deg.png",
"_turntable/cg_74544975/views/view_020_300deg.png",
"_turntable/cg_74544975/views/view_019_285deg.png",
"_turntable/cg_74544975/views/view_018_270deg.png",
"_turntable/cg_74544975/views/view_017_255deg.png",
"_turntable/cg_74544975/views/view_016_240deg.png",
"_turntable/cg_74544975/views/view_015_225deg.png",
@@ -2569,11 +2689,8 @@
"_turntable/cg_74544975/views/view_007_105deg.png",
"_turntable/cg_74544975/views/view_006_090deg.png",
"_turntable/cg_74544975/views/view_005_075deg.png",
"_turntable/cg_74544975/views/view_004_060deg.png",
"_turntable/cg_74544975/views/view_003_045deg.png",
"_turntable/cg_74544975/views/view_002_030deg.png",
"_turntable/cg_74544975/views/view_001_015deg.png",
"_turntable/cg_74544975/views/view_000_000deg.png",
"_turntable/cg_73e141fa/views/view_023_345deg.png",
"_turntable/cg_73e141fa/views/view_022_330deg.png",
"_turntable/cg_73e141fa/views/view_021_315deg.png",
@@ -3616,7 +3733,6 @@
"_turntable/cg_58c0891c/views/view_001_015deg.png",
"_turntable/cg_58c0891c/views/view_000_000deg.png",
"_turntable/cg_5991f3f2/views/view_023_345deg.png",
"_turntable/cg_5991f3f2/views/view_022_330deg.png",
"_turntable/cg_5991f3f2/views/view_021_315deg.png",
"_turntable/cg_5991f3f2/views/view_020_300deg.png",
"_turntable/cg_5991f3f2/views/view_019_285deg.png",
@@ -3636,7 +3752,6 @@
"_turntable/cg_5991f3f2/views/view_005_075deg.png",
"_turntable/cg_5991f3f2/views/view_004_060deg.png",
"_turntable/cg_5991f3f2/views/view_003_045deg.png",
"_turntable/cg_5991f3f2/views/view_002_030deg.png",
"_turntable/cg_5991f3f2/views/view_001_015deg.png",
"_turntable/cg_5991f3f2/views/view_000_000deg.png",
"_turntable/out4.png/views/view_023_345deg.png",
@@ -4032,9 +4147,7 @@
"_turntable/cg_2afca8fc/views/view_003_045deg.png",
"_turntable/cg_2afca8fc/views/view_002_030deg.png",
"_turntable/cg_2afca8fc/views/view_000_000deg.png",
"_turntable/cg_7c7b22c9/turntable.mp4",
"_turntable/cg_7c7b22c9/views/view_023_345deg.png",
"_turntable/cg_7c7b22c9/views/view_022_330deg.png",
"_turntable/cg_7c7b22c9/views/view_021_315deg.png",
"_turntable/cg_7c7b22c9/views/view_020_300deg.png",
"_turntable/cg_7c7b22c9/views/view_019_285deg.png",
@@ -4421,7 +4534,6 @@
"_turntable/cg_e79533a4/views/view_002_030deg.png",
"_turntable/cg_e79533a4/views/view_001_015deg.png",
"_turntable/cg_e79533a4/views/view_000_000deg.png",
"_turntable/b1.png/turntable.mp4",
"_turntable/b1.png/views/view_023_345deg.png",
"_turntable/b1.png/views/view_022_330deg.png",
"_turntable/b1.png/views/view_021_315deg.png",
@@ -4477,9 +4589,7 @@
"20260626_040655_sc_pad_20260626_034830_jb.nobg.png",
"20260626_040550_sc_pad_20260626_034830_jb.nobg.png",
"20260626_035131_pose_pad_20260626_034830_jb.nobg.png",
"cg_0ed9a15a_face.png",
"20260626_035101_pad_20260626_034830_jb.nobg.png",
"20260626_034949_pose_jb.nobg.png",
"20260626_034830_jb.nobg.png",
"20260626_034830_jb.png",
"20260626_034708_jb.png",
@@ -4488,7 +4598,6 @@
"20260626_031810_1_20260618_050846_img_4.nobg.png",
"20260618_050923_2_20260618_050846_img_4.nobg.png",
"20260626_030908_1_20260618_050846_img_4.nobg.png",
"20260626_031833_1_20260618_050846_img_4.png",
"20260626_031821_1_20260618_050846_img_4.png",
"20260626_031810_1_20260618_050846_img_4.png",
"20260626_031759_jb1.png",
@@ -4858,7 +4967,6 @@
"20260624_160124_1_20260619_040135_image.png",
"20260624_160113_1_20260619_040135_image.png",
"20260624_160102_1_20260619_040135_image.png",
"20260624_154905_img_72.png",
"20260624_154852_img_72.png",
"20260624_154840_img_72.png",
"20260624_154821_img_72.png",
@@ -4866,7 +4974,6 @@
"20260624_154746_img_72.png",
"20260624_154729_img_72.png",
"20260624_154712_img_72.png",
"20260624_154655_img_72.png",
"20260624_154639_img_72.png",
"20260624_154548_img_72.png",
"20260624_154536_img_72.png",
@@ -4879,13 +4986,10 @@
"cg_b7e71d34_face.png",
"20260624_154236_img_72.png",
"20260624_154125_img_72.png",
"20260624_154040_img_72.png",
"20260624_153940_img_72.png",
"20260624_153831_img_72.png",
"20260624_153614_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153433_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153417_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153400_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153344_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153311_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_153102_Screenshot_From_2026-06-17_07-41-27.png",
@@ -4957,7 +5061,6 @@
"20260624_140813_Screenshot_From_2026-06-17_07-43-19.png",
"20260624_140807_Screenshot_From_2026-06-17_07-41-27.png",
"20260624_140605_image.png",
"20260624_140549_image.png",
"20260624_140532_image.png",
"20260624_140221_image.png",
"20260624_140129_image.png",
@@ -5586,14 +5689,10 @@
"20260622_041306_image.png",
"20260622_041253_image.png",
"20260622_040911_b1.png",
"20260622_040858_b1.png",
"20260622_040846_b1.png",
"20260622_040727_b1.png",
"20260622_040702_b1.png",
"20260622_040649_b1.png",
"20260622_040636_b1.png",
"20260622_040347_b1.png",
"20260622_040141_b1.png",
"20260622_035945_b1.png",
"20260622_034529_b1.png",
"20260622_033840_b1.png",
@@ -5868,8 +5967,6 @@
"20260620_014646_image.png",
"20260620_014349_image.png",
"20260620_014239_img_77.png",
"20260627_145331_dup_20260618_011550_20260616_023209_img_51.png",
"20260627_145407_dup_20260618_011550_20260616_023209_img_51.png",
"20260620_003901_2_20260619_175210_image.png",
"20260620_003844_2_20260619_175210_image.png",
"20260620_003828_2_20260619_175210_image.png",
@@ -5920,10 +6017,8 @@
"20260619_224737_img_14.png",
"20260619_224557_img_81.png",
"20260619_224542_img_35.png",
"20260619_224219_img_12.png",
"20260619_224133_img_87.png",
"20260619_224007_img_31.png",
"20260619_223940_img_75.png",
"20260619_223856_img_37.png",
"20260619_223812_img_57.png",
"20260619_223757_img_82.png",
@@ -6114,7 +6209,6 @@
"20260619_041555_1_20260619_040135_image.png",
"20260619_041544_1_20260619_040135_image.png",
"20260619_041533_1_20260619_040135_image.png",
"20260619_041522_1_20260619_040135_image.png",
"20260619_041511_1_20260619_040135_image.png",
"20260619_041500_1_20260619_040135_image.png",
"20260619_041449_1_20260619_040135_image.png",
@@ -6372,7 +6466,6 @@
"20260618_125809_1_20260618_125748_image.png",
"20260618_125758_0_20260618_125748_image.png",
"20260618_125748_image.png",
"20260618_125415_6_20260618_125217_image.png",
"20260618_125358_5_20260618_125217_image.png",
"20260618_125340_4_20260618_125217_image.png",
"20260618_125323_3_20260618_125217_image.png",
@@ -6431,7 +6524,6 @@
"20260618_052548_1_20260618_052526_image.png",
"20260618_052537_0_20260618_052526_image.png",
"20260618_052526_image.png",
"20260618_051040_8_20260618_050846_img_4.png",
"20260618_051029_7_20260618_050846_img_4.png",
"20260618_051006_5_20260618_050846_img_4.png",
"20260618_050923_2_20260618_050846_img_4.png",
@@ -6442,18 +6534,14 @@
"20260618_015156_20260618_010700_Pasted image (4).png",
"20260618_015145_20260618_010627_jb3.png",
"20260618_015135_20260618_011424_20260618_004356_bb_01.png",
"20260618_015124_20260618_010617_20260615_153426_img_12.png",
"20260618_015113_20260618_004952_jb.png",
"20260618_015030_20260618_004858_p12.png",
"20260618_015019_20260618_010638_b1.png",
"20260618_015008_20260618_011445_20260618_004450_20260617_074413_img_73.png",
"20260618_013512_Pasted image (9).png",
"20260618_013502_kk563t.png",
"20260618_011633_t159zr-1.png",
"20260618_011612_20260616_003803_img_14.png",
"20260618_011528_20260617_074613_img_75.png",
"20260618_011517_20260618_002014_20260616_020035_img_36.png",
"20260618_011507_20260617_134615_img_86.png",
"20260618_011456_20260618_004439_20260617_005512_img_60.png",
"20260618_011445_20260618_004450_20260617_074413_img_73.png",
"20260618_011434_20260618_004847_20260615_150812_img_19_2.png",
@@ -6462,7 +6550,6 @@
"20260618_010710_p12-2.png",
"20260618_010700_Pasted image (4).png",
"20260618_010627_jb3.png",
"20260618_010617_20260615_153426_img_12.png",
"20260618_004952_jb.png",
"20260618_004941_out7.png",
"20260618_004930_20260617_134041_img_84.png",
@@ -6498,7 +6585,6 @@
"20260617_133411_img_79.png",
"20260617_133154_img_78.png",
"20260617_133129_img_77.png",
"20260617_074613_img_75.png",
"20260617_074413_img_73.png",
"20260617_074223_img_72.png",
"20260617_005512_img_60.png",

View File

@@ -112,6 +112,7 @@ def migrate_schema():
"ALTER TABLE person ADD COLUMN IF NOT EXISTS faceswap_source_video TEXT",
"ALTER TABLE person ADD COLUMN IF NOT EXISTS archived BOOLEAN DEFAULT FALSE",
"ALTER TABLE person ADD COLUMN IF NOT EXISTS face_embedding vector(512)",
"ALTER TABLE person ADD COLUMN IF NOT EXISTS is_source BOOLEAN DEFAULT FALSE",
]:
cur.execute(sql)
conn.commit()
@@ -124,7 +125,7 @@ def upsert_person(filename, filepath=None, name=None, group_id=None, tags=None,
sort_order=None, group_name=None, hidden=None,
has_background=None, source_refs=None, has_clothing=None,
content_type=None, faceswap_source_video=None, archived=None,
face_embedding=None):
face_embedding=None, is_source=None):
conn = get_db_connection()
cur = conn.cursor()
face_embedding_str = ("[" + ",".join(map(str, face_embedding)) + "]") if face_embedding is not None else None
@@ -133,8 +134,8 @@ def upsert_person(filename, filepath=None, name=None, group_id=None, tags=None,
INSERT INTO person (filename, filepath, name, group_id, tags, embedding,
clip_description, prompt, pose, sort_order, group_name, hidden,
has_background, source_refs, has_clothing,
content_type, faceswap_source_video, archived, face_embedding)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
content_type, faceswap_source_video, archived, face_embedding, is_source)
VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s)
ON CONFLICT (filename) DO UPDATE
SET filepath = COALESCE(EXCLUDED.filepath, person.filepath),
name = COALESCE(EXCLUDED.name, person.name),
@@ -153,12 +154,13 @@ def upsert_person(filename, filepath=None, name=None, group_id=None, tags=None,
content_type = COALESCE(EXCLUDED.content_type, person.content_type),
faceswap_source_video = COALESCE(EXCLUDED.faceswap_source_video, person.faceswap_source_video),
archived = COALESCE(EXCLUDED.archived, person.archived),
face_embedding = COALESCE(EXCLUDED.face_embedding, person.face_embedding);
face_embedding = COALESCE(EXCLUDED.face_embedding, person.face_embedding),
is_source = COALESCE(EXCLUDED.is_source, person.is_source);
""", (filename, filepath, name, group_id,
json.dumps(tags) if tags else None,
embedding, clip_description, prompt, pose, sort_order, group_name, hidden,
has_background, source_refs, has_clothing,
content_type, faceswap_source_video, archived, face_embedding_str))
content_type, faceswap_source_video, archived, face_embedding_str, is_source))
conn.commit()
finally:
cur.close()
@@ -206,7 +208,7 @@ def get_person(filename):
cur.execute("""
SELECT name, group_id, tags, embedding, clip_description, filepath,
prompt, pose, sort_order, group_name, hidden, has_background, source_refs,
has_clothing
has_clothing, is_source
FROM person WHERE filename = %s
""", (filename,))
return cur.fetchone()
@@ -222,7 +224,7 @@ def list_persons(include_archived=False):
cur.execute(f"""
SELECT filename, name, group_id, clip_description,
prompt, pose, sort_order, group_name, hidden, has_background, source_refs,
has_clothing, content_type, faceswap_source_video, archived
has_clothing, content_type, faceswap_source_video, archived, is_source
FROM person
{where}
""")

View File

@@ -210,13 +210,21 @@ def _run_consistency_check():
persons = database.list_persons(include_archived=True)
missing_files = []
archived_items = []
missing_group = []
for p in persons:
filename = p[0]
group_id = p[2]
if not group_id:
missing_group.append({
"filename": filename,
"name": p[1]
})
is_archived = bool(p[14]) if p[14] else False
if is_archived:
archived_items.append({
"filename": filename,
"group_id": p[2],
"group_id": group_id,
"name": p[1]
})
@@ -224,7 +232,7 @@ def _run_consistency_check():
if not os.path.exists(fpath):
missing_files.append({
"filename": filename,
"group_id": p[2],
"group_id": group_id,
"name": p[1]
})
@@ -244,10 +252,11 @@ def _run_consistency_check():
"timestamp": time.time(),
"missing_files": missing_files,
"untracked_files": untracked_files,
"archived_items": archived_items
"archived_items": archived_items,
"missing_group": missing_group
}
_write_json(os.path.join(data_dir, "inconsistencies.json"), report)
print(f"[consistency] check complete: {len(missing_files)} missing, {len(untracked_files)} untracked, {len(archived_items)} archived")
print(f"[consistency] check complete: {len(missing_files)} missing, {len(untracked_files)} untracked, {len(archived_items)} archived, {len(missing_group)} missing group")
return report
except Exception as e:
print(f"[consistency] check failed: {e}")
@@ -1305,6 +1314,7 @@ def _write_all_static() -> None:
"content_type": p[12] or "image",
"faceswap_source_video": p[13],
"archived": is_archived,
"is_source": bool(p[15]) if p[15] else False,
})
print(f"[static] write_all: {len(db_images)} total images, {archived_count} archived")
try:
@@ -1674,8 +1684,9 @@ class GroupArchiveRequest(BaseModel):
filenames: list[str]
class RepairRequest(BaseModel):
action: str # "delete_record", "import_file", "restore", "delete_permanently"
action: str # "delete_record", "import_file", "restore", "delete_permanently", "assign_group"
filename: str
group_id: str | None = None
class BatchRequest(BaseModel):
filenames: list[str]
@@ -2377,10 +2388,17 @@ def db_repair(req: RepairRequest):
if not os.path.exists(fpath):
raise HTTPException(404, "File not found on disk")
# Basic import: just register it in DB
database.upsert_person(req.filename, filepath=fpath, group_id=naming.get_base_name(req.filename))
database.upsert_person(req.filename, filepath=fpath, group_id=naming.get_base_name(req.filename), is_source=True)
_invalidate_static()
_run_consistency_check()
return {"status": "imported", "filename": req.filename}
elif req.action == "assign_group":
# Assign a group_id (default to base name if not provided)
gid = req.group_id or naming.get_base_name(req.filename)
database.upsert_person(req.filename, group_id=gid)
_invalidate_static()
_run_consistency_check()
return {"status": "assigned", "filename": req.filename, "group_id": gid}
elif req.action == "restore":
database.set_archived(req.filename, False)
_invalidate_static()
@@ -2516,6 +2534,7 @@ def _process_upload(file_path: str, filename: str, prompts: list[str], name: str
filename, filepath=file_path, name=auto_name,
clip_description=clip_desc, tags=tags, embedding=embedding,
group_id=group_id, sort_order=0, has_clothing=has_clothing,
is_source=True,
)
# Surface the new group with its base image right away — the pose/base-prompt
# generation below can take a while, and the user shouldn't wait for it to
@@ -2549,6 +2568,7 @@ def _process_upload(file_path: str, filename: str, prompts: list[str], name: str
clip_description=clip_desc, embedding=out_embedding,
group_id=group_id, sort_order=next_order,
prompt=prompt, pose=out_pose,
source_refs=json.dumps([filename]),
)
except Exception as e:
print(f"Error processing prompt '{prompt}' for {filename}: {e}")
@@ -2590,7 +2610,7 @@ def upload_image(
if group_id and skip_poses:
sort_order = database.get_next_sort_order(group_id)
database.upsert_person(filename, filepath=file_path, group_id=group_id,
sort_order=sort_order)
sort_order=sort_order, is_source=True)
_invalidate_static()
return {"status": "added", "filename": filename, "group_id": group_id}
@@ -2677,7 +2697,11 @@ def set_image_preferred(filename: str):
raise HTTPException(404, "Image not found")
group_id = person[1]
if not group_id:
raise HTTPException(400, "Image has no group assigned")
# Auto-assign group_id if missing (legacy/orphan)
group_id = naming.get_base_name(filename)
database.upsert_person(filename, group_id=group_id)
print(f"[fix] Auto-assigned group_id={group_id} to orphan {filename} during set-preferred")
rows = database.get_group_order(group_id)
others = [r[0] for r in rows if r[0] != filename]
database.set_group_order(group_id, [filename] + others)
@@ -3440,7 +3464,8 @@ def remove_background_sam(filename: str):
# Register sidecar in DB so it appears in the same group
group_id = person[1]
database.upsert_person(nobg_filename, filepath=nobg_path,
group_id=group_id, has_background=False)
group_id=group_id, has_background=False,
source_refs=json.dumps([filename]))
used_sam2 = _sam2_predictor is not False and _sam2_predictor is not None
return {

View File

@@ -2,29 +2,39 @@ import torch
import open_clip
from PIL import Image
import os
import threading
_model = None
_preprocess = None
_device = None
_lock = threading.Lock()
def get_model():
global _model, _preprocess, _device
if _model is None:
_device = "cuda" if torch.cuda.is_available() else "cpu"
# ViT-H-14 is 1024-dim
_model, _, _preprocess = open_clip.create_model_and_transforms('ViT-H-14', pretrained='laion2b_s32b_b79k')
_model = _model.to(_device)
_model.eval()
with _lock:
if _model is None:
dev = "cuda" if torch.cuda.is_available() else "cpu"
# ViT-H-14 is 1024-dim
model, _, preprocess = open_clip.create_model_and_transforms('ViT-H-14', pretrained='laion2b_s32b_b79k')
model = model.to(dev)
model.eval()
# Set globals only when fully ready to avoid race conditions
_preprocess = preprocess
_device = dev
_model = model
return _model, _preprocess, _device
def generate_embedding(image_path):
model, preprocess, device = get_model()
try:
image = preprocess(Image.open(image_path)).unsqueeze(0).to(device)
with torch.no_grad():
image_features = model.encode_image(image)
image_features /= image_features.norm(dim=-1, keepdim=True)
return image_features.cpu().numpy()[0].tolist()
with Image.open(image_path) as img:
image = preprocess(img.convert("RGB")).unsqueeze(0).to(device)
with torch.no_grad():
image_features = model.encode_image(image)
image_features /= image_features.norm(dim=-1, keepdim=True)
return image_features.cpu().numpy()[0].tolist()
except Exception as e:
print(f"Error generating embedding for {image_path}: {e}")
return None

View File

@@ -1,8 +1,17 @@
# Upscale HQ
Masterpiece.
high quality.
detailed.
Anatomically precise, hyperrealistic, high detail, keep the characteristics of the reference image.
detailed. detailed skin.
Anatomically precise, photo realistic, high detail, keep the characteristics of the reference image.
# Upscale HQ (18)
Masterpiece.
high quality.
detailed. detailed skin.
teenage female.
Anatomically precise, photo realistic, high detail, keep the characteristics of the reference image.
# BG Remove
@@ -47,13 +56,18 @@ Keep full characteristics of reference image.
# Three-quarter (18)
You are in a black empty void.
high quality, masterpiece, detailed, detailed skin, Head-on a full-body three-quarter detailed full-nude-body, female teenage portrait, realistic, transparent background.
high quality, masterpiece, detailed, detailed skin.
Head-on a right-front detailed full-nude-body. Top-to-toe photo.
female teenage, photorealistic, sharp focus, transparent background.
Identical person from reference image.
Keep characteristics of reference image.
# Three-quarter
You are in a black empty void.
high quality, masterpiece, detailed, detailed skin, Head-on a full-body three-quarter detailed full-nude-body, female portrait, realistic, transparent background.
high quality, masterpiece, detailed, detailed skin.
Head-on a right-front view. Top-to-toe.
detailed full-nude-body, female portrait, photorealistic, transparent background.
Keep characteristics of reference image.
# Head-on undress (18)
@@ -71,13 +85,13 @@ Keep characteristics of reference image.
# Head-on straight-on (18)
You are in a black empty void.
Head-on straight-on full-body portrait, teenage female, realistic, black background.
Head-on straight-on full-body portrait, teenage female, photo realistic, black background.
Keep characteristics of reference image.
# Head-on straight-on
You are in a black empty void.
Head-on straight-on full-body female portrait, realistic, black background.
Head-on straight-on full-body female portrait, photo realistic, black background.
Keep characteristics of reference image.
# Looking viewer (18)
@@ -106,17 +120,26 @@ high quality, full-nude-body, female, masterpiece, realistic, photo, cinematic l
transparent background.
Keep characteristics of reference image.
# Merge (18)x3
masterpiece, you are in a black void, high quality, detailed, undress, combine the characteristics from reference images.
detailed skin, detailed full-nude-body. teenage female.
Photo-realistic.
Anatomically precise, keep the posture and gesture from the base image.
# Merge (18)
masterpiece, you are in a black void, high quality, detailed, undress, combine the characteristics from reference images.
detailed skin, detailed full-nude-body. teenage female.
hyper realistic. keep the posture and gesture from the base image.
hyper realistic.
Anatomically precise, keep the posture and gesture from the base image.
# Merge
masterpiece, you are in a black void, high quality, detailed, undress, combine the characteristics from reference images.
detailed skin, detailed full-nude-body. female.
hyper realistic. keep the posture and gesture from the base image.
hyper realistic.
Anatomically precise, keep the posture and gesture from the base image.
# Jewelery

View File

@@ -80,6 +80,11 @@
<div id="archivedList">No archived items found.</div>
</div>
<div class="section">
<h2>Missing Group IDs <span class="info">(Legacy or orphaned images with no group assigned)</span></h2>
<div id="orphansList">No images with missing groups found.</div>
</div>
<div class="section">
<h2>Orphaned Records <span class="info">(In DB, but file missing on disk)</span></h2>
<div id="missingList">No orphaned records found.</div>
@@ -118,6 +123,7 @@
else if (d.status === 'imported') msg = 'File imported';
else if (d.status === 'restored') msg = 'Item restored';
else if (d.status === 'deleted_permanently') msg = 'Permanently deleted';
else if (d.status === 'assigned') msg = 'Group assigned';
showToast(msg);
loadInconsistencies();
@@ -137,6 +143,7 @@
renderArchived(d.archived_items || []);
renderMissing(d.missing_files || []);
renderUntracked(d.untracked_files || []);
renderOrphans(d.missing_group || []);
if (d.timestamp) {
const date = new Date(d.timestamp * 1000);
@@ -150,6 +157,23 @@
}
}
function renderOrphans(files) {
const container = document.getElementById('orphansList');
if (files.length === 0) {
container.innerHTML = 'No images with missing groups found.';
return;
}
container.innerHTML = files.map(f => `
<div class="item">
<div>
<div class="filename">${f.filename}</div>
<div class="info">Name: ${f.name || 'none'}</div>
</div>
<button class="btn success" onclick="repair('${f.filename}', 'assign_group')">Auto-assign Group</button>
</div>
`).join('');
}
function renderArchived(files) {
const container = document.getElementById('archivedList');
if (files.length === 0) {

View File

@@ -189,7 +189,7 @@ def process_image(filename):
try:
embedding = embeddings.generate_embedding(output_path)
gid = filename
database.upsert_person(output_filename, filepath=output_path, embedding=embedding, group_id=gid)
database.upsert_person(output_filename, filepath=output_path, embedding=embedding, group_id=gid, is_source=True)
# Also trigger tagging to get auto-name and clip description
tag_url = CONF["api_url"].replace("/edit", "/tag")