diff --git a/Galleries/20251106_2236_Angel Rai_Chicka Bomb_All_Over_30_starring_Angel_Rai__Chicka_Bomb_Nude_Photos/metadata.json b/Galleries/20251106_2236_Angel Rai_Chicka Bomb_All_Over_30_starring_Angel_Rai__Chicka_Bomb_Nude_Photos/metadata.json
new file mode 100644
index 0000000..324313a
--- /dev/null
+++ b/Galleries/20251106_2236_Angel Rai_Chicka Bomb_All_Over_30_starring_Angel_Rai__Chicka_Bomb_Nude_Photos/metadata.json
@@ -0,0 +1,92 @@
+{
+ "id": "20251106_2236",
+ "title": "All Over 30 starring Angel Rai, Chicka Bomb Nude Photos",
+ "models": [
+ "Angel Rai",
+ "Chicka Bomb"
+ ],
+ "categories": [
+ "Tribbing",
+ "Babe",
+ "Ukrainian",
+ "Sexy",
+ "Pussy",
+ "Beautiful",
+ "Ass",
+ "Petite",
+ "Redhead",
+ "Amateur",
+ "Hot Naked Women",
+ "Lesbian Facesitting",
+ "Lesbian Scissoring",
+ "Nice Pussy",
+ "Redhead Lesbian",
+ "Wet Teen Pussy",
+ "Ukraine Pussy",
+ "Beautiful Pussy"
+ ],
+ "tags": [
+ "Amateur",
+ "Ass",
+ "Beautiful",
+ "Beautiful Pussy",
+ "Hot Naked Women",
+ "Lesbian",
+ "Lesbian Facesitting",
+ "Lesbian Scissoring",
+ "Nice Pussy",
+ "Petite",
+ "Pussy",
+ "Redhead",
+ "Redhead Lesbian",
+ "Teen",
+ "Ukraine Pussy",
+ "Ukrainian",
+ "Wet Teen Pussy"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_013_115e.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_019_30f5.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_035_6bb6.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_042_3626.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_054_63b8.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_062_e707.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_072_65a3.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_080_5e41.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_103_293d.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_107_c2a5.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_129_3362.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_139_e8cc.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_147_f649.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_165_3b97.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_168_af3d.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_179_273f.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_194_f9c4.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_211_c635.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_218_b3b7.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_236_dbb4.jpg",
+ "https://cdni.pornpics.com/1280/7/571/66224044/66224044_245_7298.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-06T22:36:16.505880+00:00",
+ "source_url": "https://www.pornpics.com/galleries/all-over-30-starring-angel-rai-chicka-bomb-nude-photos-66224044/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Angel Rai_Chicka Bomb_All_Over_30_starring_Angel_Rai__Chicka_Bomb_Nude_Photos",
+ "inferred_tags": [
+ "Amateur",
+ "Ass",
+ "Beautiful",
+ "Lesbian",
+ "Petite",
+ "Pussy",
+ "Redhead",
+ "Teen",
+ "Ukrainian"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2236_Kama Oxi_Tom Holland_Porn_Megaload_featuring_Kama_Oxi__Tom_Holland_Sex_Pictures/metadata.json b/Galleries/20251106_2236_Kama Oxi_Tom Holland_Porn_Megaload_featuring_Kama_Oxi__Tom_Holland_Sex_Pictures/metadata.json
new file mode 100644
index 0000000..766c22c
--- /dev/null
+++ b/Galleries/20251106_2236_Kama Oxi_Tom Holland_Porn_Megaload_featuring_Kama_Oxi__Tom_Holland_Sex_Pictures/metadata.json
@@ -0,0 +1,87 @@
+{
+ "id": "20251106_2236",
+ "title": "Porn Megaload featuring Kama Oxi, Tom Holland Sex Pictures",
+ "models": [
+ "Kama Oxi",
+ "Tom Holland"
+ ],
+ "categories": [
+ "Schoolgirl",
+ "Old Young",
+ "Teacher",
+ "Mom",
+ "Pussy",
+ "Teen",
+ "Blowjob",
+ "Spreading",
+ "Feet",
+ "Non Nude",
+ "Teen Schoolgirl",
+ "Mom Son",
+ "Friends Mom",
+ "Mom Boy",
+ "Beautiful Blowjob",
+ "Brunette Teen",
+ "Mom Pussy",
+ "Fit"
+ ],
+ "tags": [
+ "Beautiful",
+ "Beautiful Blowjob",
+ "Blowjob",
+ "Brunette",
+ "Brunette Teen",
+ "Fit",
+ "Friends Mom",
+ "Fucking",
+ "Mom Boy",
+ "Mom Pussy",
+ "Mom Son",
+ "Pussy",
+ "Teen",
+ "Teen Schoolgirl"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_005_16e0.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_011_f0a3.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_015_2ec0.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_025_5c5c.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_029_d79e.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_036_d660.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_042_5241.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_044_f051.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_045_c636.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_053_ca8e.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_061_9769.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_065_92fe.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_068_9824.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_078_5051.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_081_eee1.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_089_f0c7.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_094_12b1.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_101_be1e.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_104_1129.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_111_da8f.jpg",
+ "https://cdni.pornpics.com/1280/7/740/76288217/76288217_120_228c.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-06T22:36:26.070601+00:00",
+ "source_url": "https://www.pornpics.com/galleries/porn-megaload-featuring-kama-oxi-tom-holland-sex-pictures-76288217/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Kama Oxi_Tom Holland_Porn_Megaload_featuring_Kama_Oxi__Tom_Holland_Sex_Pictures",
+ "inferred_tags": [
+ "Beautiful",
+ "Blowjob",
+ "Brunette",
+ "Fit",
+ "Fucking",
+ "Pussy",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2236_Markus Dupree_Ramon Nomar_Riley Reid_Curvy_brunette_Riley_Reid_gets_a_DP_in_a_steamy_threesome_with_hung_studs/metadata.json b/Galleries/20251106_2236_Markus Dupree_Ramon Nomar_Riley Reid_Curvy_brunette_Riley_Reid_gets_a_DP_in_a_steamy_threesome_with_hung_studs/metadata.json
new file mode 100644
index 0000000..4207ebf
--- /dev/null
+++ b/Galleries/20251106_2236_Markus Dupree_Ramon Nomar_Riley Reid_Curvy_brunette_Riley_Reid_gets_a_DP_in_a_steamy_threesome_with_hung_studs/metadata.json
@@ -0,0 +1,108 @@
+{
+ "id": "20251106_2236",
+ "title": "Curvy brunette Riley Reid gets a DP in a steamy threesome with hung studs",
+ "models": [
+ "Markus Dupree",
+ "Ramon Nomar",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Threesome",
+ "Fetish",
+ "PAWG",
+ "Upskirt",
+ "Latex",
+ "Double Penetration",
+ "High Heels",
+ "Pornstar",
+ "Hairy",
+ "Facial",
+ "Short Skirt No Panties",
+ "Tight Dress",
+ "Upskirt No Panties",
+ "Hairy Upskirt",
+ "Short Skirt High Heels",
+ "Double Anal",
+ "Sexy Dress",
+ "Brunette Hairy Pussy"
+ ],
+ "tags": [
+ "Anal",
+ "Anal Fetish",
+ "Brunette",
+ "Brunette Hairy Pussy",
+ "Curvy",
+ "Double Anal",
+ "Dress",
+ "Facial",
+ "Fetish",
+ "Hairy",
+ "Hairy Upskirt",
+ "High Heels",
+ "Latex",
+ "Latex Fetish",
+ "Panties",
+ "Penetration",
+ "Pornstar",
+ "Pussy",
+ "Sexy Dress",
+ "Short Skirt High Heels",
+ "Short Skirt No Panties",
+ "Skirt",
+ "Threesome",
+ "Tight Dress",
+ "Upskirt No Panties"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_004_3073.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_006_00dd.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_015_8bfe.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_016_b0db.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_021_27fb.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_030_0ef2.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_035_1935.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_037_93bb.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_042_ca5b.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_046_39cd.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_052_30d7.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_057_f3ff.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_064_5913.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_069_ef9c.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_072_ab1a.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_080_c483.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_084_a452.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_088_65a2.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_089_6bfb.jpg",
+ "https://cdni.pornpics.com/1280/7/550/31077441/31077441_096_6a83.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:36:52.785931+00:00",
+ "source_url": "https://www.pornpics.com/galleries/curvy-brunette-riley-reid-gets-a-dp-in-a-steamy-threesome-with-hung-studs-31077441/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Markus Dupree_Ramon Nomar_Riley Reid_Curvy_brunette_Riley_Reid_gets_a_DP_in_a_steamy_threesome_with_hung_studs",
+ "inferred_tags": [
+ "Anal",
+ "Anal Fetish",
+ "Brunette",
+ "Curvy",
+ "Dress",
+ "Facial",
+ "Fetish",
+ "Hairy",
+ "High Heels",
+ "Latex",
+ "Latex Fetish",
+ "Panties",
+ "Penetration",
+ "Pornstar",
+ "Pussy",
+ "Skirt",
+ "Threesome"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2236_Riley Reid_Skinny_coed_with_trimmed_muff_Riley_Reid_gives_shows_her_spread_love_holes/metadata.json b/Galleries/20251106_2236_Riley Reid_Skinny_coed_with_trimmed_muff_Riley_Reid_gives_shows_her_spread_love_holes/metadata.json
new file mode 100644
index 0000000..f4aa093
--- /dev/null
+++ b/Galleries/20251106_2236_Riley Reid_Skinny_coed_with_trimmed_muff_Riley_Reid_gives_shows_her_spread_love_holes/metadata.json
@@ -0,0 +1,82 @@
+{
+ "id": "20251106_2236",
+ "title": "Skinny coed with trimmed muff Riley Reid gives shows her spread love holes",
+ "models": [
+ "Riley Reid"
+ ],
+ "categories": [
+ "Ass",
+ "Close Up",
+ "Pornstar",
+ "Tattoo",
+ "Asshole",
+ "Pussy",
+ "Solo",
+ "Hairy",
+ "Beautiful",
+ "Skinny",
+ "Bent Over Ass",
+ "Nude",
+ "Hot Naked Women",
+ "Bent Over",
+ "Sexy Ass",
+ "PAWG Solo",
+ "Ass Spread",
+ "Wet Pussy Close Up"
+ ],
+ "tags": [
+ "Ass",
+ "Ass Spread",
+ "Beautiful",
+ "Bent Over",
+ "Bent Over Ass",
+ "Hairy",
+ "Hot Naked Women",
+ "Nude",
+ "PAWG Solo",
+ "Pornstar",
+ "Pussy",
+ "Sexy Ass",
+ "Skinny",
+ "Solo",
+ "Wet Pussy Close Up"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_001_9bc3.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_006_67f2.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_009_31eb.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_011_5c64.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_013_cb52.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_017_a5f4.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_019_0134.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_024_2eff.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_027_a24e.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_030_622c.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_032_e6ea.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_036_4f11.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_037_a09d.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_042_5a76.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_045_337c.jpg",
+ "https://cdni.pornpics.com/1280/7/268/56770461/56770461_046_00ad.jpg"
+ ],
+ "image_count": 16,
+ "date_scraped": "2025-11-06T22:36:56.876114+00:00",
+ "source_url": "https://www.pornpics.com/galleries/skinny-coed-with-trimmed-muff-riley-reid-gives-shows-her-spread-love-holes-56770461/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Riley Reid_Skinny_coed_with_trimmed_muff_Riley_Reid_gives_shows_her_spread_love_holes",
+ "inferred_tags": [
+ "Ass",
+ "Beautiful",
+ "Hairy",
+ "Pornstar",
+ "Pussy",
+ "Skinny",
+ "Solo"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2236_Susanna Glam_Deny Lou_Amateur_mom_Susanna_Glam_gets_stripped_and_fucked_by_her_personal_trainer/metadata.json b/Galleries/20251106_2236_Susanna Glam_Deny Lou_Amateur_mom_Susanna_Glam_gets_stripped_and_fucked_by_her_personal_trainer/metadata.json
new file mode 100644
index 0000000..386110e
--- /dev/null
+++ b/Galleries/20251106_2236_Susanna Glam_Deny Lou_Amateur_mom_Susanna_Glam_gets_stripped_and_fucked_by_her_personal_trainer/metadata.json
@@ -0,0 +1,87 @@
+{
+ "id": "20251106_2236",
+ "title": "Amateur mom Susanna Glam gets stripped and fucked by her personal trainer",
+ "models": [
+ "Susanna Glam",
+ "Deny Lou"
+ ],
+ "categories": [
+ "Mom",
+ "Mature",
+ "Old Young",
+ "Granny",
+ "Amateur",
+ "Teen",
+ "Pussy",
+ "Blowjob",
+ "Sexy",
+ "Handjob",
+ "Mom Boy",
+ "GILF",
+ "Beautiful Granny",
+ "Mom Son",
+ "Granny Handjob",
+ "Sexy GILF",
+ "Granny Slut",
+ "Mature Boy"
+ ],
+ "tags": [
+ "Amateur",
+ "Beautiful",
+ "Beautiful Granny",
+ "Blowjob",
+ "GILF",
+ "Granny Handjob",
+ "Granny Slut",
+ "Handjob",
+ "Mature",
+ "Mature Boy",
+ "Mom Boy",
+ "Mom Son",
+ "Pussy",
+ "Sexy GILF",
+ "Teen"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_002_7573.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_005_f878.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_009_df36.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_015_c13c.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_019_4754.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_024_adf4.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_027_cfb4.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_032_7cd9.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_033_7cd9.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_038_6940.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_044_11a0.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_046_a4af.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_051_8b7b.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_053_5e7c.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_056_2107.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_061_5103.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_063_39d8.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_066_ec1b.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_069_f21c.jpg",
+ "https://cdni.pornpics.com/1280/7/739/54709783/54709783_071_99a1.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:36:11.000270+00:00",
+ "source_url": "https://www.pornpics.com/galleries/amateur-mom-susanna-glam-gets-stripped-and-fucked-by-her-personal-trainer-54709783/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Susanna Glam_Deny Lou_Amateur_mom_Susanna_Glam_gets_stripped_and_fucked_by_her_personal_trainer",
+ "inferred_tags": [
+ "Amateur",
+ "Beautiful",
+ "Blowjob",
+ "Handjob",
+ "Mature",
+ "Pussy",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2236_Taissia Shanti_Adorable_little_teen_Elen_rides_her_boyfriend_s_dong_and_gets_a_facial/metadata.json b/Galleries/20251106_2236_Taissia Shanti_Adorable_little_teen_Elen_rides_her_boyfriend_s_dong_and_gets_a_facial/metadata.json
new file mode 100644
index 0000000..16d9b56
--- /dev/null
+++ b/Galleries/20251106_2236_Taissia Shanti_Adorable_little_teen_Elen_rides_her_boyfriend_s_dong_and_gets_a_facial/metadata.json
@@ -0,0 +1,96 @@
+{
+ "id": "20251106_2236",
+ "title": "Adorable little teen Elen rides her boyfriend's dong and gets a facial",
+ "models": [
+ "Taissia Shanti"
+ ],
+ "categories": [
+ "Tiny Tits",
+ "Teen",
+ "Hardcore",
+ "Cumshot",
+ "Russian",
+ "Facesitting",
+ "Shorts",
+ "Pussy",
+ "Ass",
+ "Big Cock",
+ "Teen Fuck",
+ "Small Tits Fuck",
+ "Skinny Teen Fuck",
+ "Russian Teen",
+ "Teen Hardcore",
+ "Clothed Fuck",
+ "Teen Facesitting",
+ "Teen Cum"
+ ],
+ "tags": [
+ "Ass",
+ "Big Cock",
+ "Big Tits",
+ "Clothed Fuck",
+ "Cumshot",
+ "Facial",
+ "Fucking",
+ "Hardcore",
+ "Pussy",
+ "Russian",
+ "Russian Teen",
+ "Shorts",
+ "Skinny",
+ "Skinny Teen Fuck",
+ "Small Tits Fuck",
+ "Teen",
+ "Teen Cum",
+ "Teen Facesitting",
+ "Teen Fuck",
+ "Teen Hardcore"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_003_372f.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_009_298a.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_017_8d10.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_024_7b2e.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_029_b569.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_036_6e16.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_045_f904.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_054_0602.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_060_82aa.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_064_6db2.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_073_2f60.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_084_ebe8.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_087_d26c.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_094_09f6.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_099_2151.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_107_4012.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_112_b91c.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_121_4098.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_122_47ba.jpg",
+ "https://cdni.pornpics.com/1280/7/131/73470783/73470783_129_c960.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:36:21.117480+00:00",
+ "source_url": "https://www.pornpics.com/galleries/adorable-little-teen-elen-rides-her-boyfriends-dong-and-gets-a-facial-73470783/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Taissia Shanti_Adorable_little_teen_Elen_rides_her_boyfriend_s_dong_and_gets_a_facial",
+ "inferred_tags": [
+ "Ass",
+ "Big Cock",
+ "Big Tits",
+ "Cumshot",
+ "Facial",
+ "Fucking",
+ "Hardcore",
+ "Pussy",
+ "Russian",
+ "Shorts",
+ "Skinny",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2236_jorden kennedy_Pretty_brunette_teen_Jorden_Kennedy_exposes_her_sweet_body_in_a_hot_striptease/metadata.json b/Galleries/20251106_2236_jorden kennedy_Pretty_brunette_teen_Jorden_Kennedy_exposes_her_sweet_body_in_a_hot_striptease/metadata.json
new file mode 100644
index 0000000..40f0f45
--- /dev/null
+++ b/Galleries/20251106_2236_jorden kennedy_Pretty_brunette_teen_Jorden_Kennedy_exposes_her_sweet_body_in_a_hot_striptease/metadata.json
@@ -0,0 +1,82 @@
+{
+ "id": "20251106_2236",
+ "title": "Pretty brunette teen Jorden Kennedy exposes her sweet body in a hot striptease",
+ "models": [
+ "jorden kennedy"
+ ],
+ "categories": [
+ "Amateur",
+ "Hairy",
+ "Outdoor",
+ "Non Nude",
+ "Spreading",
+ "Pussy",
+ "Natural Hairy",
+ "Big Hairy Pussy",
+ "Amateur Hairy Pussy",
+ "Beautiful Hairy",
+ "Hairy Bush",
+ "Extremely Hairy Pussy"
+ ],
+ "tags": [
+ "Amateur",
+ "Amateur Hairy Pussy",
+ "Beautiful",
+ "Beautiful Hairy",
+ "Big Hairy Pussy",
+ "Brunette",
+ "Extremely Hairy Pussy",
+ "Hairy",
+ "Hairy Bush",
+ "Natural",
+ "Natural Hairy",
+ "Natural Look",
+ "Outdoor",
+ "Pussy",
+ "Teen"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_002_1613.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_005_e681.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_009_5b7d.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_013_6a51.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_016_19ed.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_019_968e.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_022_8643.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_023_b4f5.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_028_7fee.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_029_993c.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_034_12fc.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_037_a107.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_039_fc1c.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_041_dfda.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_045_dc8d.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_049_74d9.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_052_4d0c.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_054_602a.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_058_a8f3.jpg",
+ "https://cdni.pornpics.com/1280/7/652/47702961/47702961_061_8c3b.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:36:35.305079+00:00",
+ "source_url": "https://www.pornpics.com/galleries/pretty-brunette-teen-jorden-kennedy-exposes-her-sweet-body-in-a-hot-striptease-47702961/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_jorden kennedy_Pretty_brunette_teen_Jorden_Kennedy_exposes_her_sweet_body_in_a_hot_striptease",
+ "inferred_tags": [
+ "Amateur",
+ "Beautiful",
+ "Brunette",
+ "Hairy",
+ "Natural",
+ "Natural Look",
+ "Outdoor",
+ "Pussy",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Damon Dice_Eva Lovia_Riley Reid_Attractive_Eva_Lovia___Riley_Reid_fuck_a_handsome_businessman_in_a_3some/metadata.json b/Galleries/20251106_2237_Damon Dice_Eva Lovia_Riley Reid_Attractive_Eva_Lovia___Riley_Reid_fuck_a_handsome_businessman_in_a_3some/metadata.json
new file mode 100644
index 0000000..9e018e7
--- /dev/null
+++ b/Galleries/20251106_2237_Damon Dice_Eva Lovia_Riley Reid_Attractive_Eva_Lovia___Riley_Reid_fuck_a_handsome_businessman_in_a_3some/metadata.json
@@ -0,0 +1,86 @@
+{
+ "id": "20251106_2237",
+ "title": "Attractive Eva Lovia & Riley Reid fuck a handsome businessman in a 3some",
+ "models": [
+ "Damon Dice",
+ "Eva Lovia",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Threesome",
+ "Groupsex",
+ "Facesitting",
+ "Pornstar",
+ "Cowgirl",
+ "Petite",
+ "Blowjob",
+ "Pussy",
+ "Tiny Tits",
+ "Natural Tits",
+ "Reverse Cowgirl",
+ "Trimmed Pussy",
+ "Skinny Small Tits",
+ "Brunette Natural Tits"
+ ],
+ "tags": [
+ "Big Tits",
+ "Blowjob",
+ "Brunette",
+ "Brunette Natural Tits",
+ "Cowgirl",
+ "Fucking",
+ "Natural",
+ "Natural Look",
+ "Petite",
+ "Pornstar",
+ "Pussy",
+ "Reverse Cowgirl",
+ "Skinny",
+ "Skinny Small Tits",
+ "Threesome",
+ "Trimmed Pussy"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_001_d09c.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_002_25ed.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_003_2ba2.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_004_4a0e.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_005_4a0e.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_006_b96a.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_007_e464.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_008_f9fb.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_009_76b4.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_010_6604.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_011_a111.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_012_4b4b.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_013_fa16.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_014_3342.jpg",
+ "https://cdni.pornpics.com/1280/7/496/56531264/56531264_015_e76b.jpg"
+ ],
+ "image_count": 15,
+ "date_scraped": "2025-11-06T22:37:29.826327+00:00",
+ "source_url": "https://www.pornpics.com/galleries/attractive-eva-lovia-riley-reid-fuck-a-handsome-businessman-in-a-3some-56531264/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Damon Dice_Eva Lovia_Riley Reid_Attractive_Eva_Lovia___Riley_Reid_fuck_a_handsome_businessman_in_a_3some",
+ "inferred_tags": [
+ "Big Tits",
+ "Blowjob",
+ "Brunette",
+ "Cowgirl",
+ "Fucking",
+ "Natural",
+ "Natural Look",
+ "Petite",
+ "Pornstar",
+ "Pussy",
+ "Reverse Cowgirl",
+ "Skinny",
+ "Threesome"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Dredd_Riley Reid_Cute_brunette_with_a_petite_figure_Riley_Reid_gets_ass_railed_by_a_BBC/metadata.json b/Galleries/20251106_2237_Dredd_Riley Reid_Cute_brunette_with_a_petite_figure_Riley_Reid_gets_ass_railed_by_a_BBC/metadata.json
new file mode 100644
index 0000000..8fd1559
--- /dev/null
+++ b/Galleries/20251106_2237_Dredd_Riley Reid_Cute_brunette_with_a_petite_figure_Riley_Reid_gets_ass_railed_by_a_BBC/metadata.json
@@ -0,0 +1,98 @@
+{
+ "id": "20251106_2237",
+ "title": "Cute brunette with a petite figure Riley Reid gets ass railed by a BBC",
+ "models": [
+ "Dredd",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Ass Fucking",
+ "Big Cock",
+ "Anal",
+ "Interracial",
+ "BBC",
+ "Sexy",
+ "Pool",
+ "Petite",
+ "Wet",
+ "Blowjob",
+ "Interracial Anal",
+ "Big Dick Anal",
+ "BBC Anal",
+ "Big Black Cock",
+ "Doggystyle Anal",
+ "Big Cock Blowjob",
+ "Monster Cock",
+ "Big Black Dick"
+ ],
+ "tags": [
+ "Anal",
+ "Anal Fetish",
+ "Ass",
+ "BBC",
+ "BBC Anal",
+ "Big Black Cock",
+ "Big Black Dick",
+ "Big Cock",
+ "Big Cock Blowjob",
+ "Big Dick Anal",
+ "Blowjob",
+ "Brunette",
+ "Doggystyle",
+ "Doggystyle Anal",
+ "Fucking",
+ "Interracial",
+ "Interracial Anal",
+ "Monster Cock",
+ "Petite",
+ "Pool"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_009_fe06.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_020_0ebc.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_023_9a4d.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_038_3d9c.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_048_6187.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_052_813c.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_063_3c05.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_073_dc2e.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_087_1ffa.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_089_fc27.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_102_6a67.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_115_e7d5.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_119_df38.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_126_2514.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_134_5dd6.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_151_ea2b.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_160_1707.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_165_c775.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_176_3b45.jpg",
+ "https://cdni.pornpics.com/1280/7/177/60016759/60016759_187_63fb.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:37:01.679280+00:00",
+ "source_url": "https://www.pornpics.com/galleries/cute-brunette-with-a-petite-figure-riley-reid-gets-ass-railed-by-a-bbc-60016759/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Dredd_Riley Reid_Cute_brunette_with_a_petite_figure_Riley_Reid_gets_ass_railed_by_a_BBC",
+ "inferred_tags": [
+ "Anal",
+ "Anal Fetish",
+ "Ass",
+ "BBC",
+ "Big Cock",
+ "Blowjob",
+ "Brunette",
+ "Doggystyle",
+ "Fetish",
+ "Fucking",
+ "Interracial",
+ "Petite",
+ "Pool"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Lea Lexis_Riley Reid_Petite_Riley_Reid___busty_Lea_Lexis_tease_with_tits___flash_hot_panty_upskirts/metadata.json b/Galleries/20251106_2237_Lea Lexis_Riley Reid_Petite_Riley_Reid___busty_Lea_Lexis_tease_with_tits___flash_hot_panty_upskirts/metadata.json
new file mode 100644
index 0000000..966f84d
--- /dev/null
+++ b/Galleries/20251106_2237_Lea Lexis_Riley Reid_Petite_Riley_Reid___busty_Lea_Lexis_tease_with_tits___flash_hot_panty_upskirts/metadata.json
@@ -0,0 +1,93 @@
+{
+ "id": "20251106_2237",
+ "title": "Petite Riley Reid & busty Lea Lexis tease with tits & flash hot panty upskirts",
+ "models": [
+ "Lea Lexis",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Panties",
+ "Upskirt",
+ "Sexy",
+ "Ass",
+ "Lesbian",
+ "Reality",
+ "Dress",
+ "Clothed",
+ "Natural Tits",
+ "Hairy",
+ "Romanian",
+ "Summer Dress",
+ "Hairy Armpits",
+ "Upskirt Panties",
+ "Tight Dress",
+ "Hairy Brunette",
+ "Hairy Panties"
+ ],
+ "tags": [
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Busty",
+ "Dress",
+ "Hairy",
+ "Hairy Armpits",
+ "Hairy Brunette",
+ "Hairy Panties",
+ "Lesbian",
+ "Natural",
+ "Natural Look",
+ "Panties",
+ "Petite",
+ "Romanian",
+ "Summer Dress",
+ "Tight Dress",
+ "Upskirt Panties"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_002_2f55.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_005_a701.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_007_bcff.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_010_5544.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_014_8cd7.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_018_8a7a.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_021_b42d.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_023_99f5.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_027_5ea7.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_029_cc0d.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_031_4fa7.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_033_94df.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_035_2392.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_037_3874.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_039_8ab2.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_042_1340.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_043_28a5.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_045_045c.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_047_5ecb.jpg",
+ "https://cdni.pornpics.com/1280/7/54/89239818/89239818_050_f980.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:37:58.188655+00:00",
+ "source_url": "https://www.pornpics.com/galleries/petite-riley-reid-busty-lea-lexis-tease-with-tits-flash-hot-panty-upskirts-89239818/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Lea Lexis_Riley Reid_Petite_Riley_Reid___busty_Lea_Lexis_tease_with_tits___flash_hot_panty_upskirts",
+ "inferred_tags": [
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Busty",
+ "Dress",
+ "Hairy",
+ "Lesbian",
+ "Natural",
+ "Natural Look",
+ "Panties",
+ "Petite"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Mike Adriano_Riley Reid_Tiny_brunette_Riley_Reid_shows_her_sexy_holes_and_fucks_a_huge_dick_in_POV/metadata.json b/Galleries/20251106_2237_Mike Adriano_Riley Reid_Tiny_brunette_Riley_Reid_shows_her_sexy_holes_and_fucks_a_huge_dick_in_POV/metadata.json
new file mode 100644
index 0000000..cf67241
--- /dev/null
+++ b/Galleries/20251106_2237_Mike Adriano_Riley Reid_Tiny_brunette_Riley_Reid_shows_her_sexy_holes_and_fucks_a_huge_dick_in_POV/metadata.json
@@ -0,0 +1,104 @@
+{
+ "id": "20251106_2237",
+ "title": "Tiny brunette Riley Reid shows her sexy holes and fucks a huge dick in POV",
+ "models": [
+ "Mike Adriano",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Pussy",
+ "Hardcore",
+ "Asshole",
+ "Perfect",
+ "MILF",
+ "Hairy",
+ "Amateur",
+ "Tiny Tits",
+ "Ass",
+ "Doggy Style",
+ "Pussy Spreading",
+ "Pussy Fuck",
+ "Skinny Girl Fat Pussy",
+ "MILF Fuck",
+ "Hairy Asshole",
+ "Gaping Pussy",
+ "Hairy Pussy Fuck",
+ "Hairy MILF Fuck"
+ ],
+ "tags": [
+ "Amateur",
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Doggystyle",
+ "Fucking",
+ "Gaping Pussy",
+ "Hairy",
+ "Hairy Asshole",
+ "Hairy MILF Fuck",
+ "Hairy Pussy Fuck",
+ "Hardcore",
+ "MILF",
+ "MILF Fuck",
+ "Mature",
+ "POV",
+ "Perfect",
+ "Perfect Body",
+ "Pussy",
+ "Pussy Fuck",
+ "Pussy Spreading",
+ "Skinny",
+ "Skinny Girl Fat Pussy"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_020_9b4d.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_031_b7c3.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_047_b65a.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_070_75b2.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_099_4f96.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_126_bfbe.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_148_754b.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_157_5e4c.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_185_dd3c.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_204_3b33.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_223_dc40.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_240_0910.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_258_21ad.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_272_caa6.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_287_08ee.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_325_8a21.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_331_fe5f.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_364_fa51.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_372_b912.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_400_aee8.jpg",
+ "https://cdni.pornpics.com/1280/7/433/56734787/56734787_414_0d67.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-06T22:37:44.327840+00:00",
+ "source_url": "https://www.pornpics.com/galleries/tiny-brunette-riley-reid-shows-her-sexy-holes-and-fucks-a-huge-dick-in-pov-56734787/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Mike Adriano_Riley Reid_Tiny_brunette_Riley_Reid_shows_her_sexy_holes_and_fucks_a_huge_dick_in_POV",
+ "inferred_tags": [
+ "Amateur",
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Doggystyle",
+ "Fucking",
+ "Hairy",
+ "Hardcore",
+ "MILF",
+ "Mature",
+ "POV",
+ "Perfect",
+ "Perfect Body",
+ "Pussy",
+ "Skinny"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Preston Parker_Riley Reid_Petite_babysitter_Riley_Reid_enjoys_a_cheating_husband_s_big_dick/metadata.json b/Galleries/20251106_2237_Preston Parker_Riley Reid_Petite_babysitter_Riley_Reid_enjoys_a_cheating_husband_s_big_dick/metadata.json
new file mode 100644
index 0000000..16d2a56
--- /dev/null
+++ b/Galleries/20251106_2237_Preston Parker_Riley Reid_Petite_babysitter_Riley_Reid_enjoys_a_cheating_husband_s_big_dick/metadata.json
@@ -0,0 +1,95 @@
+{
+ "id": "20251106_2237",
+ "title": "Petite babysitter Riley Reid enjoys a cheating husband's big dick",
+ "models": [
+ "Preston Parker",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Skirt",
+ "Dress",
+ "Babysitter",
+ "Clothed",
+ "Hardcore",
+ "Blowjob",
+ "Pussy",
+ "High Heels",
+ "Tiny Tits",
+ "Lingerie",
+ "Summer Dress",
+ "Beautiful Blowjob",
+ "Sexy Blowjob",
+ "Short Skirt High Heels",
+ "Underwear",
+ "Tight Dress",
+ "High Heels Fuck",
+ "Pussy Fuck"
+ ],
+ "tags": [
+ "Beautiful",
+ "Beautiful Blowjob",
+ "Big Tits",
+ "Blowjob",
+ "Dress",
+ "Fucking",
+ "Hardcore",
+ "High Heels",
+ "High Heels Fuck",
+ "Lingerie",
+ "Petite",
+ "Pussy",
+ "Pussy Fuck",
+ "Sexy Blowjob",
+ "Short Skirt High Heels",
+ "Skirt",
+ "Summer Dress",
+ "Tight Dress",
+ "Underwear"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_005_e834.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_034_16f7.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_057_da13.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_083_fe33.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_116_9b68.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_134_4a4c.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_164_1925.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_177_1d52.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_194_4738.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_230_1fc8.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_253_35da.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_271_0ed1.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_305_b66e.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_321_5e0a.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_340_e441.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_362_4211.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_391_798b.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_424_7ea7.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_447_82dc.jpg",
+ "https://cdni.pornpics.com/1280/7/277/90908574/90908574_449_1303.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:37:36.547337+00:00",
+ "source_url": "https://www.pornpics.com/galleries/petite-babysitter-riley-reid-enjoys-a-cheating-husbands-big-dick-90908574/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Preston Parker_Riley Reid_Petite_babysitter_Riley_Reid_enjoys_a_cheating_husband_s_big_dick",
+ "inferred_tags": [
+ "Beautiful",
+ "Big Tits",
+ "Blowjob",
+ "Dress",
+ "Fucking",
+ "Hardcore",
+ "High Heels",
+ "Lingerie",
+ "Petite",
+ "Pussy",
+ "Skirt"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos/metadata.json b/Galleries/20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos/metadata.json
new file mode 100644
index 0000000..d8ec29e
--- /dev/null
+++ b/Galleries/20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos/metadata.json
@@ -0,0 +1,78 @@
+{
+ "id": "20251106_2237",
+ "title": "Mr POV featuring Riley Reid Nude Photos",
+ "models": [
+ "Riley Reid"
+ ],
+ "categories": [
+ "Blowjob",
+ "Cum On Face",
+ "Facial",
+ "Family",
+ "Feet",
+ "Handjob",
+ "POV",
+ "POV Handjob",
+ "Petite",
+ "Petite Facial",
+ "Pussy",
+ "Reality",
+ "Spreading"
+ ],
+ "tags": [
+ "Blowjob",
+ "Cum On Face",
+ "Cumshot",
+ "Facial",
+ "Handjob",
+ "POV",
+ "POV Handjob",
+ "Petite",
+ "Petite Facial",
+ "Pussy"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_006_de48.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_011_4123.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_017_c831.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_026_1280.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_032_9df3.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_039_5e55.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_045_710e.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_055_05a8.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_059_2b01.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_069_27ad.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_076_eed7.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_079_b476.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_090_a1f1.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_095_c3c5.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_104_cba0.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_109_3974.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_114_605b.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_121_ea4a.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_123_bcdb.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_125_9073.jpg",
+ "https://cdni.pornpics.com/1280/7/813/58732399/58732399_134_1d3e.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-06T22:37:48.823848+00:00",
+ "source_url": "https://www.pornpics.com/galleries/mr-pov-featuring-riley-reid-nude-photos-58732399/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos",
+ "last_refreshed": "2025-11-06T22:57:58.301040+00:00",
+ "inferred_tags": [
+ "Blowjob",
+ "Cumshot",
+ "Facial",
+ "Handjob",
+ "POV",
+ "Petite",
+ "Pussy"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos/metadata_update_log.json b/Galleries/20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos/metadata_update_log.json
new file mode 100644
index 0000000..9c709de
--- /dev/null
+++ b/Galleries/20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos/metadata_update_log.json
@@ -0,0 +1,7 @@
+{
+ "timestamp": "2025-11-06T22:57:58.301158+00:00",
+ "changes": {
+ "categories": "merged",
+ "source": "updated"
+ }
+}
diff --git a/Galleries/20251106_2237_Riley Reid_Mr_POV_starring_Riley_Reid_Naked_Images/metadata.json b/Galleries/20251106_2237_Riley Reid_Mr_POV_starring_Riley_Reid_Naked_Images/metadata.json
new file mode 100644
index 0000000..73a8486
--- /dev/null
+++ b/Galleries/20251106_2237_Riley Reid_Mr_POV_starring_Riley_Reid_Naked_Images/metadata.json
@@ -0,0 +1,75 @@
+{
+ "id": "20251106_2237",
+ "title": "Mr POV starring Riley Reid Naked Images",
+ "models": [
+ "Riley Reid"
+ ],
+ "categories": [
+ "POV",
+ "Petite",
+ "Handjob",
+ "Glasses",
+ "Reality",
+ "Outdoor",
+ "Non Nude",
+ "Cumshot",
+ "Pornstar",
+ "Brunette",
+ "POV Handjob",
+ "Money"
+ ],
+ "tags": [
+ "Brunette",
+ "Cumshot",
+ "Handjob",
+ "Money",
+ "Outdoor",
+ "POV",
+ "POV Handjob",
+ "Petite",
+ "Pornstar"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_007_65d0.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_015_6fcb.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_019_418a.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_029_e81d.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_042_e5e1.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_046_e962.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_058_c185.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_065_f96e.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_073_4e66.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_076_f2b6.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_081_f5d7.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_090_f2a5.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_095_d2fc.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_107_0fcb.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_118_f8ce.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_121_8ab1.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_131_ae49.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_135_22a6.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_150_8e01.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_151_6349.jpg",
+ "https://cdni.pornpics.com/1280/7/812/39106284/39106284_162_d06d.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-06T22:37:09.633343+00:00",
+ "source_url": "https://www.pornpics.com/galleries/mr-pov-starring-riley-reid-naked-images-39106284/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Mr_POV_starring_Riley_Reid_Naked_Images",
+ "inferred_tags": [
+ "Brunette",
+ "Cumshot",
+ "Handjob",
+ "Outdoor",
+ "POV",
+ "Petite",
+ "Pornstar"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Riley Reid_Nerdy_American_schoolgirl_with_tiny_tits_Riley_Reid_showing_off/metadata.json b/Galleries/20251106_2237_Riley Reid_Nerdy_American_schoolgirl_with_tiny_tits_Riley_Reid_showing_off/metadata.json
new file mode 100644
index 0000000..da8350b
--- /dev/null
+++ b/Galleries/20251106_2237_Riley Reid_Nerdy_American_schoolgirl_with_tiny_tits_Riley_Reid_showing_off/metadata.json
@@ -0,0 +1,73 @@
+{
+ "id": "20251106_2237",
+ "title": "Nerdy American schoolgirl with tiny tits Riley Reid showing off",
+ "models": [
+ "Riley Reid"
+ ],
+ "categories": [
+ "Schoolgirl",
+ "College",
+ "Brunette",
+ "Glasses",
+ "Pussy",
+ "Big Clit",
+ "Spreading",
+ "Classroom",
+ "College Pussy",
+ "School Uniform"
+ ],
+ "tags": [
+ "Big Tits",
+ "Brunette",
+ "Classroom",
+ "College Pussy",
+ "English",
+ "Pussy",
+ "School Uniform",
+ "Uniform",
+ "Uniform Fetish"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_006_f6c4.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_022_83dd.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_029_aa7c.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_048_7ef1.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_053_1acc.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_058_f385.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_067_0f03.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_084_246b.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_103_389d.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_106_8469.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_130_d3a1.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_132_a567.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_146_e23a.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_165_5d01.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_180_c999.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_192_c835.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_200_fb60.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_215_903a.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_230_8499.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_244_3fe1.jpg",
+ "https://cdni.pornpics.com/1280/7/292/24451045/24451045_261_68f5.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-06T22:37:20.020823+00:00",
+ "source_url": "https://www.pornpics.com/galleries/nerdy-american-schoolgirl-with-tiny-tits-riley-reid-showing-off-24451045/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Nerdy_American_schoolgirl_with_tiny_tits_Riley_Reid_showing_off",
+ "inferred_tags": [
+ "Big Tits",
+ "Brunette",
+ "English",
+ "Fetish",
+ "Pussy",
+ "Uniform",
+ "Uniform Fetish"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Riley Reid_Petite_female_Riley_Reid_rips_off_her_prison_jumper_to_model_in_the_nude/metadata.json b/Galleries/20251106_2237_Riley Reid_Petite_female_Riley_Reid_rips_off_her_prison_jumper_to_model_in_the_nude/metadata.json
new file mode 100644
index 0000000..8b63067
--- /dev/null
+++ b/Galleries/20251106_2237_Riley Reid_Petite_female_Riley_Reid_rips_off_her_prison_jumper_to_model_in_the_nude/metadata.json
@@ -0,0 +1,80 @@
+{
+ "id": "20251106_2237",
+ "title": "Petite female Riley Reid rips off her prison jumper to model in the nude",
+ "models": [
+ "Riley Reid"
+ ],
+ "categories": [
+ "Pornstar",
+ "Mature",
+ "Undressing",
+ "Pussy",
+ "Brunette",
+ "Spreading",
+ "Short Hair",
+ "Legs",
+ "Older Women",
+ "Mature Older Women",
+ "Sexy Older Women",
+ "Beautiful Mature",
+ "Over 50",
+ "Mature Pussy",
+ "Mature Undressing",
+ "Mature Spreading"
+ ],
+ "tags": [
+ "Beautiful",
+ "Beautiful Mature",
+ "Brunette",
+ "Mature",
+ "Mature Older Women",
+ "Mature Pussy",
+ "Mature Spreading",
+ "Mature Undressing",
+ "Model",
+ "Older Women",
+ "Over 50",
+ "Petite",
+ "Pornstar",
+ "Pussy",
+ "Sexy Older Women"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_004_b0f6.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_008_ec67.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_017_7c72.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_021_345b.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_028_7fe7.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_035_1f6c.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_041_3c6b.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_045_c794.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_055_09ce.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_059_b117.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_062_fbf2.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_069_de43.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_074_79ab.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_083_3d4e.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_088_63db.jpg",
+ "https://cdni.pornpics.com/1280/7/41/12420368/12420368_095_32b2.jpg"
+ ],
+ "image_count": 16,
+ "date_scraped": "2025-11-06T22:37:24.611918+00:00",
+ "source_url": "https://www.pornpics.com/galleries/petite-female-riley-reid-rips-off-her-prison-jumper-to-model-in-the-nude-12420368/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Petite_female_Riley_Reid_rips_off_her_prison_jumper_to_model_in_the_nude",
+ "inferred_tags": [
+ "Beautiful",
+ "Brunette",
+ "Mature",
+ "Model",
+ "Petite",
+ "Pornstar",
+ "Pussy"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Riley Reid_Smiley_teenage_hottie_with_tattoos_revealing_her_perky_titties_and_neat_ass/metadata.json b/Galleries/20251106_2237_Riley Reid_Smiley_teenage_hottie_with_tattoos_revealing_her_perky_titties_and_neat_ass/metadata.json
new file mode 100644
index 0000000..40fe97c
--- /dev/null
+++ b/Galleries/20251106_2237_Riley Reid_Smiley_teenage_hottie_with_tattoos_revealing_her_perky_titties_and_neat_ass/metadata.json
@@ -0,0 +1,84 @@
+{
+ "id": "20251106_2237",
+ "title": "Smiley teenage hottie with tattoos revealing her perky titties and neat ass",
+ "models": [
+ "Riley Reid"
+ ],
+ "categories": [
+ "Pussy",
+ "Face",
+ "Hairy",
+ "Teen",
+ "Brunette",
+ "Babe",
+ "Ass",
+ "Tattoo",
+ "Natural Tits",
+ "Clothed",
+ "Hairy Teen Pussy",
+ "Brunette Hairy Pussy",
+ "Hot Naked Women",
+ "Tight Ass",
+ "Hairy Erotica",
+ "Cute Face",
+ "Brunette Ass",
+ "Cute Hairy"
+ ],
+ "tags": [
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Brunette Ass",
+ "Brunette Hairy Pussy",
+ "Cute Face",
+ "Cute Hairy",
+ "Hairy",
+ "Hairy Erotica",
+ "Hairy Teen Pussy",
+ "Hot Naked Women",
+ "Natural",
+ "Natural Look",
+ "Pussy",
+ "Teen",
+ "Tight Ass"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_001_5b3e.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_002_458a.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_003_12e1.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_004_6823.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_005_035b.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_006_b8ff.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_007_3f6f.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_008_8a46.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_009_33f7.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_010_382c.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_011_b2de.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_012_b2de.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_013_ffb5.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_014_90d4.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_015_3fcf.jpg",
+ "https://cdni.pornpics.com/1280/5/102/63010314/63010314_016_f5c6.jpg"
+ ],
+ "image_count": 16,
+ "date_scraped": "2025-11-06T22:37:14.542771+00:00",
+ "source_url": "https://www.pornpics.com/galleries/smiley-teenage-hottie-with-tattoos-revealing-her-perky-titties-and-neat-ass-63010314/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Smiley_teenage_hottie_with_tattoos_revealing_her_perky_titties_and_neat_ass",
+ "inferred_tags": [
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Hairy",
+ "Natural",
+ "Natural Look",
+ "Pussy",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2237_Riley Reid_Xavier Miller_Kinky_nympho_Riley_Reid_hikes_up_her_red_dress_and_gets_blacked_hardcore/metadata.json b/Galleries/20251106_2237_Riley Reid_Xavier Miller_Kinky_nympho_Riley_Reid_hikes_up_her_red_dress_and_gets_blacked_hardcore/metadata.json
new file mode 100644
index 0000000..424df14
--- /dev/null
+++ b/Galleries/20251106_2237_Riley Reid_Xavier Miller_Kinky_nympho_Riley_Reid_hikes_up_her_red_dress_and_gets_blacked_hardcore/metadata.json
@@ -0,0 +1,93 @@
+{
+ "id": "20251106_2237",
+ "title": "Kinky nympho Riley Reid hikes up her red dress and gets blacked hardcore",
+ "models": [
+ "Riley Reid",
+ "Xavier Miller"
+ ],
+ "categories": [
+ "Interracial",
+ "Caught",
+ "Reality",
+ "Hardcore",
+ "BBC",
+ "Big Cock",
+ "Ass",
+ "Pornstar",
+ "Tattoo",
+ "Upskirt",
+ "Skinny Interracial",
+ "Big Black Cock",
+ "Upskirt No Panties",
+ "Skinny BBC",
+ "Caught Masturbating",
+ "Monster Cock",
+ "Skinny Small Tits",
+ "Dick"
+ ],
+ "tags": [
+ "Ass",
+ "BBC",
+ "Big Black Cock",
+ "Big Cock",
+ "Big Tits",
+ "Caught Masturbating",
+ "Dick",
+ "Dress",
+ "Hardcore",
+ "Interracial",
+ "Monster Cock",
+ "Panties",
+ "Pornstar",
+ "Skinny",
+ "Skinny BBC",
+ "Skinny Interracial",
+ "Skinny Small Tits",
+ "Upskirt No Panties"
+ ],
+ "source": {
+ "network": "Blacked",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_005_5103.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_013_be67.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_027_a7b2.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_037_a0d5.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_048_5e98.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_052_bc4b.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_068_e22e.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_071_6777.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_082_16c1.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_095_5ccf.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_105_7062.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_119_fb32.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_125_724c.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_140_4884.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_144_0aa4.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_151_34a5.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_170_7ca6.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_177_2541.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_182_aefd.jpg",
+ "https://cdni.pornpics.com/1280/7/107/75565937/75565937_196_cf6d.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:37:53.310419+00:00",
+ "source_url": "https://www.pornpics.com/galleries/kinky-nympho-riley-reid-hikes-up-her-red-dress-and-gets-blacked-hardcore-75565937/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Xavier Miller_Kinky_nympho_Riley_Reid_hikes_up_her_red_dress_and_gets_blacked_hardcore",
+ "inferred_tags": [
+ "Ass",
+ "BBC",
+ "Big Cock",
+ "Big Tits",
+ "Dress",
+ "Hardcore",
+ "Interracial",
+ "Panties",
+ "Pornstar",
+ "Skinny"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2238_Damon Dice_Riley Reid_Petite_teen_girl_Riley_Reid_gives_her_guy_cake_and_a_fuck_for_his_birthday/metadata.json b/Galleries/20251106_2238_Damon Dice_Riley Reid_Petite_teen_girl_Riley_Reid_gives_her_guy_cake_and_a_fuck_for_his_birthday/metadata.json
new file mode 100644
index 0000000..a9ce247
--- /dev/null
+++ b/Galleries/20251106_2238_Damon Dice_Riley Reid_Petite_teen_girl_Riley_Reid_gives_her_guy_cake_and_a_fuck_for_his_birthday/metadata.json
@@ -0,0 +1,89 @@
+{
+ "id": "20251106_2238",
+ "title": "Petite teen girl Riley Reid gives her guy cake and a fuck for his birthday",
+ "models": [
+ "Damon Dice",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Teen",
+ "Hardcore",
+ "Hairy",
+ "Pussy",
+ "Close Up",
+ "Ass",
+ "Handjob",
+ "Cowgirl",
+ "Spreading",
+ "Pussy Licking",
+ "Teen Handjob",
+ "Hairy Teen Spreading",
+ "Hairy Pussy Fuck",
+ "Brunette Teen",
+ "Juicy Pussy",
+ "Hairy Teen Pussy",
+ "Close Up Fuck",
+ "Meaty Pussy"
+ ],
+ "tags": [
+ "Ass",
+ "Brunette",
+ "Brunette Teen",
+ "Close Up Fuck",
+ "Cowgirl",
+ "Fucking",
+ "Hairy",
+ "Hairy Pussy Fuck",
+ "Hairy Teen Pussy",
+ "Hairy Teen Spreading",
+ "Handjob",
+ "Hardcore",
+ "Juicy Pussy",
+ "Meaty Pussy",
+ "Petite",
+ "Pussy",
+ "Teen",
+ "Teen Handjob"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_001_e4e1.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_002_f711.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_003_7326.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_004_3a3b.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_005_6dc5.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_006_9390.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_007_c676.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_008_c676.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_009_6473.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_010_e5bd.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_011_54d3.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_012_d832.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_013_d832.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_014_c8a9.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_015_74fc.jpg",
+ "https://cdni.pornpics.com/1280/1/173/43223033/43223033_016_0b22.jpg"
+ ],
+ "image_count": 16,
+ "date_scraped": "2025-11-06T22:38:20.128109+00:00",
+ "source_url": "https://www.pornpics.com/galleries/petite-teen-girl-riley-reid-gives-her-guy-cake-and-a-fuck-for-his-birthday-43223033/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2238_Damon Dice_Riley Reid_Petite_teen_girl_Riley_Reid_gives_her_guy_cake_and_a_fuck_for_his_birthday",
+ "inferred_tags": [
+ "Ass",
+ "Brunette",
+ "Cowgirl",
+ "Fucking",
+ "Hairy",
+ "Handjob",
+ "Hardcore",
+ "Petite",
+ "Pussy",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2238_Ramon Nomar_Riley Reid_Petite_babe_Riley_Reid_spreads_legs_for_her_lover___fucks_in_front_of_husband/metadata.json b/Galleries/20251106_2238_Ramon Nomar_Riley Reid_Petite_babe_Riley_Reid_spreads_legs_for_her_lover___fucks_in_front_of_husband/metadata.json
new file mode 100644
index 0000000..e00a1f6
--- /dev/null
+++ b/Galleries/20251106_2238_Ramon Nomar_Riley Reid_Petite_babe_Riley_Reid_spreads_legs_for_her_lover___fucks_in_front_of_husband/metadata.json
@@ -0,0 +1,88 @@
+{
+ "id": "20251106_2238",
+ "title": "Petite babe Riley Reid spreads legs for her lover & fucks in front of husband",
+ "models": [
+ "Ramon Nomar",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Wife",
+ "Bikini",
+ "Cheating",
+ "Blowjob",
+ "MILF",
+ "Stockings",
+ "Petite",
+ "Feet",
+ "Pussy",
+ "Cowgirl",
+ "Cheating Wife",
+ "Wife Blowjob",
+ "Bikini Blowjob",
+ "Petite Stockings",
+ "Sexy MILF",
+ "All Over 40",
+ "MILF Stockings",
+ "MILF Bikini"
+ ],
+ "tags": [
+ "All Over 40",
+ "Bikini Blowjob",
+ "Blowjob",
+ "Cheating Wife",
+ "Cowgirl",
+ "MILF",
+ "MILF Bikini",
+ "MILF Stockings",
+ "Mature",
+ "Petite",
+ "Petite Stockings",
+ "Pussy",
+ "Sexy MILF",
+ "Stockings",
+ "Wife Blowjob"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_002_7f7b.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_026_1096.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_039_b754.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_053_3d45.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_064_fb80.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_083_278e.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_085_4b8c.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_098_e866.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_119_da42.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_127_843f.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_151_93ba.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_155_530e.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_170_20d5.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_188_e5e1.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_208_7b58.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_217_980f.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_241_c563.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_247_d655.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_271_5042.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_279_775d.jpg",
+ "https://cdni.pornpics.com/1280/7/44/51353894/51353894_289_99e2.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-06T22:38:15.767635+00:00",
+ "source_url": "https://www.pornpics.com/galleries/petite-babe-riley-reid-spreads-legs-for-her-lover-fucks-in-front-of-husband-51353894/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2238_Ramon Nomar_Riley Reid_Petite_babe_Riley_Reid_spreads_legs_for_her_lover___fucks_in_front_of_husband",
+ "inferred_tags": [
+ "Blowjob",
+ "Cowgirl",
+ "MILF",
+ "Mature",
+ "Petite",
+ "Pussy",
+ "Stockings"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2238_Riley Reid_Leggy_white_chick_Riley_Reid_strips_to_black_stockings_with_her_glasses_on/metadata.json b/Galleries/20251106_2238_Riley Reid_Leggy_white_chick_Riley_Reid_strips_to_black_stockings_with_her_glasses_on/metadata.json
new file mode 100644
index 0000000..6bca0eb
--- /dev/null
+++ b/Galleries/20251106_2238_Riley Reid_Leggy_white_chick_Riley_Reid_strips_to_black_stockings_with_her_glasses_on/metadata.json
@@ -0,0 +1,77 @@
+{
+ "id": "20251106_2238",
+ "title": "Leggy white chick Riley Reid strips to black stockings with her glasses on",
+ "models": [
+ "Riley Reid"
+ ],
+ "categories": [
+ "Glasses",
+ "Uniform",
+ "Stockings",
+ "Office",
+ "Pornstar",
+ "Pussy",
+ "Short Hair",
+ "Spreading",
+ "Big Tits",
+ "Natural Tits",
+ "Stockings Spread"
+ ],
+ "tags": [
+ "Big Tits",
+ "Natural",
+ "Natural Look",
+ "Office",
+ "Pornstar",
+ "Pussy",
+ "Stockings",
+ "Stockings Spread",
+ "Uniform",
+ "Uniform Fetish"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_003_f8d5.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_013_5b29.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_020_1951.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_021_b190.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_033_3599.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_041_bcbe.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_052_43c8.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_064_2fec.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_070_fe71.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_082_69a9.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_095_7596.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_099_b267.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_112_0a1d.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_123_186e.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_129_9ccd.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_138_8b8a.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_146_9f2f.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_158_84f5.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_167_8107.jpg",
+ "https://cdni.pornpics.com/1280/7/40/56822993/56822993_177_2bfb.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:38:03.922937+00:00",
+ "source_url": "https://www.pornpics.com/galleries/leggy-white-chick-riley-reid-strips-to-black-stockings-with-her-glasses-on-56822993/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2238_Riley Reid_Leggy_white_chick_Riley_Reid_strips_to_black_stockings_with_her_glasses_on",
+ "inferred_tags": [
+ "Big Tits",
+ "Fetish",
+ "Natural",
+ "Natural Look",
+ "Office",
+ "Pornstar",
+ "Pussy",
+ "Stockings",
+ "Uniform",
+ "Uniform Fetish"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2258_Adriana Chechik_Aj Applegate_Anikka Albrite_Keisha Grey_Kleio Valentien_Riley Reid_Vicki Chase_Elegant_Angel_Adriana_Chechik__Aj_Applegate__Anikka_Albrite__Keisha_Grey__Kleio/metadata.json b/Galleries/20251106_2258_Adriana Chechik_Aj Applegate_Anikka Albrite_Keisha Grey_Kleio Valentien_Riley Reid_Vicki Chase_Elegant_Angel_Adriana_Chechik__Aj_Applegate__Anikka_Albrite__Keisha_Grey__Kleio/metadata.json
new file mode 100644
index 0000000..c7f74f0
--- /dev/null
+++ b/Galleries/20251106_2258_Adriana Chechik_Aj Applegate_Anikka Albrite_Keisha Grey_Kleio Valentien_Riley Reid_Vicki Chase_Elegant_Angel_Adriana_Chechik__Aj_Applegate__Anikka_Albrite__Keisha_Grey__Kleio/metadata.json
@@ -0,0 +1,103 @@
+{
+ "id": "20251106_2258",
+ "title": "Elegant Angel Adriana Chechik, Aj Applegate, Anikka Albrite, Keisha Grey, Kleio",
+ "models": [
+ "Adriana Chechik",
+ "Aj Applegate",
+ "Anikka Albrite",
+ "Keisha Grey",
+ "Kleio Valentien",
+ "Riley Reid",
+ "Vicki Chase"
+ ],
+ "categories": [
+ "Ass Fucking",
+ "Anal",
+ "Groupsex",
+ "Double Penetration",
+ "MILF",
+ "Doggy Style",
+ "Petite",
+ "Latina",
+ "Teen",
+ "Lingerie",
+ "MILF Anal",
+ "Doggystyle Anal",
+ "Latina Anal",
+ "Petite Anal",
+ "MILF DP",
+ "Sexy Anal",
+ "Interracial Anal",
+ "Teen Anal"
+ ],
+ "tags": [
+ "Anal",
+ "Anal Fetish",
+ "Ass",
+ "Doggystyle",
+ "Doggystyle Anal",
+ "Fucking",
+ "Interracial",
+ "Interracial Anal",
+ "Latina Anal",
+ "Lingerie",
+ "MILF",
+ "MILF Anal",
+ "MILF DP",
+ "Mature",
+ "Penetration",
+ "Petite",
+ "Petite Anal",
+ "Sexy Anal",
+ "Teen",
+ "Teen Anal"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_001_bf0b.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_007_85cb.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_010_89d2.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_013_adb0.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_016_8635.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_018_cbfc.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_020_c2f1.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_024_6da9.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_026_4ad5.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_031_09eb.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_032_a2c5.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_036_4500.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_038_b79d.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_042_8ff3.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_044_bc81.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_047_e9b6.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_052_352d.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_053_e6d7.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_058_6355.jpg",
+ "https://cdni.pornpics.com/1280/7/620/85123161/85123161_060_75ff.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:58:04.155758+00:00",
+ "source_url": "https://www.pornpics.com/galleries/elegant-angel-adriana-chechik-aj-applegate-anikka-albrite-keisha-grey-kleio-85123161/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Adriana Chechik_Aj Applegate_Anikka Albrite_Keisha Grey_Kleio Valentien_Riley Reid_Vicki Chase_Elegant_Angel_Adriana_Chechik__Aj_Applegate__Anikka_Albrite__Keisha_Grey__Kleio",
+ "inferred_tags": [
+ "Anal",
+ "Anal Fetish",
+ "Ass",
+ "Doggystyle",
+ "Fetish",
+ "Fucking",
+ "Interracial",
+ "Lingerie",
+ "MILF",
+ "Mature",
+ "Penetration",
+ "Petite",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2258_Aubrey Kate_Riley Reid_Sebastian Keys_Sluts_Riley_Reid___Aubrey_Kate_show_off_their_big_butts___give_a_double_BJ/metadata.json b/Galleries/20251106_2258_Aubrey Kate_Riley Reid_Sebastian Keys_Sluts_Riley_Reid___Aubrey_Kate_show_off_their_big_butts___give_a_double_BJ/metadata.json
new file mode 100644
index 0000000..d09397f
--- /dev/null
+++ b/Galleries/20251106_2258_Aubrey Kate_Riley Reid_Sebastian Keys_Sluts_Riley_Reid___Aubrey_Kate_show_off_their_big_butts___give_a_double_BJ/metadata.json
@@ -0,0 +1,75 @@
+{
+ "id": "20251106_2258",
+ "title": "Sluts Riley Reid & Aubrey Kate show off their big butts & give a double BJ",
+ "models": [
+ "Aubrey Kate",
+ "Riley Reid",
+ "Sebastian Keys"
+ ],
+ "categories": [
+ "Shemale",
+ "Shemale On Female",
+ "Shemale Fucks Girl",
+ "Shemale Threesome",
+ "Shemale Fucks Female",
+ "Shemale Pantyhose",
+ "Shemale Lesbian",
+ "Shemale Ass",
+ "Blonde Shemale"
+ ],
+ "tags": [
+ "Ass",
+ "Blonde",
+ "Blonde Shemale",
+ "Blowjob",
+ "Lesbian",
+ "Shemale Ass",
+ "Shemale Fucks Female",
+ "Shemale Fucks Girl",
+ "Shemale Lesbian",
+ "Shemale On Female",
+ "Shemale Pantyhose",
+ "Shemale Threesome",
+ "Threesome"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_001_d411.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_003_308a.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_005_4650.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_007_5fa7.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_009_b70a.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_011_7af7.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_013_e7a1.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_015_ae2c.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_017_d1d7.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_020_d390.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_022_af6c.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_023_e19e.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_026_07cd.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_027_8090.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_030_a082.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_031_8624.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_033_ec88.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_036_7392.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_037_a4c6.jpg",
+ "https://cdni.pornpics.com/1280/7/550/76348062/76348062_038_dd29.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:58:13.317125+00:00",
+ "source_url": "https://www.pornpics.com/galleries/sluts-riley-reid-aubrey-kate-show-off-their-big-butts-give-a-double-bj-76348062/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Aubrey Kate_Riley Reid_Sebastian Keys_Sluts_Riley_Reid___Aubrey_Kate_show_off_their_big_butts___give_a_double_BJ",
+ "inferred_tags": [
+ "Ass",
+ "Blonde",
+ "Blowjob",
+ "Lesbian",
+ "Threesome"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2258_Erik Everhard_Riley Reid_Cheerleader_Riley_Reid_shows_her_tiny_tits_before_riding_a_pussy-wrecking_dick/metadata.json b/Galleries/20251106_2258_Erik Everhard_Riley Reid_Cheerleader_Riley_Reid_shows_her_tiny_tits_before_riding_a_pussy-wrecking_dick/metadata.json
new file mode 100644
index 0000000..b4794e2
--- /dev/null
+++ b/Galleries/20251106_2258_Erik Everhard_Riley Reid_Cheerleader_Riley_Reid_shows_her_tiny_tits_before_riding_a_pussy-wrecking_dick/metadata.json
@@ -0,0 +1,86 @@
+{
+ "id": "20251106_2258",
+ "title": "Cheerleader Riley Reid shows her tiny tits before riding a pussy-wrecking dick",
+ "models": [
+ "Erik Everhard",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Hardcore",
+ "Cheerleader",
+ "Cowgirl",
+ "Schoolgirl",
+ "Blowjob",
+ "Pornstar",
+ "White",
+ "Pussy",
+ "Horny",
+ "Pussy Fuck",
+ "Sneakers",
+ "Slut",
+ "School Uniform"
+ ],
+ "tags": [
+ "Big Tits",
+ "Blowjob",
+ "Cowgirl",
+ "Fucking",
+ "Hardcore",
+ "Horny",
+ "Pornstar",
+ "Pussy",
+ "Pussy Fuck",
+ "Riding",
+ "School Uniform",
+ "Slut",
+ "Sneakers",
+ "Uniform",
+ "Uniform Fetish"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_003_4edb.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_005_bcc2.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_009_4e16.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_011_994c.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_015_d8e0.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_018_a049.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_019_7ad3.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_023_fb66.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_026_1b93.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_030_a9f9.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_033_0eee.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_035_e348.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_039_db0b.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_040_a2eb.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_043_d278.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_047_5afa.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_050_33c5.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_052_c1d0.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_053_f8f1.jpg",
+ "https://cdni.pornpics.com/1280/7/371/41471787/41471787_056_d6ea.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-06T22:58:21.023626+00:00",
+ "source_url": "https://www.pornpics.com/galleries/cheerleader-riley-reid-shows-her-tiny-tits-before-riding-a-pussywrecking-dick-41471787/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Erik Everhard_Riley Reid_Cheerleader_Riley_Reid_shows_her_tiny_tits_before_riding_a_pussy-wrecking_dick",
+ "inferred_tags": [
+ "Big Tits",
+ "Blowjob",
+ "Cowgirl",
+ "Fetish",
+ "Fucking",
+ "Hardcore",
+ "Pornstar",
+ "Pussy",
+ "Riding",
+ "Uniform",
+ "Uniform Fetish"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2258_Melissa Moore_Riley Reid_Lesbian_girls_Riley_Reid_and_Melissa_Moore_lick_and_finger_fuck_each_other/metadata.json b/Galleries/20251106_2258_Melissa Moore_Riley Reid_Lesbian_girls_Riley_Reid_and_Melissa_Moore_lick_and_finger_fuck_each_other/metadata.json
new file mode 100644
index 0000000..1a766fd
--- /dev/null
+++ b/Galleries/20251106_2258_Melissa Moore_Riley Reid_Lesbian_girls_Riley_Reid_and_Melissa_Moore_lick_and_finger_fuck_each_other/metadata.json
@@ -0,0 +1,74 @@
+{
+ "id": "20251106_2258",
+ "title": "Lesbian girls Riley Reid and Melissa Moore lick and finger fuck each other",
+ "models": [
+ "Melissa Moore",
+ "Riley Reid"
+ ],
+ "categories": [
+ "Lesbian",
+ "Latina",
+ "Pornstar",
+ "Step Sister",
+ "Teen",
+ "Brunette",
+ "Cute",
+ "Spreading",
+ "Hairy",
+ "Pussy",
+ "Teen Lesbian",
+ "Sexy Latina"
+ ],
+ "tags": [
+ "Brunette",
+ "Fucking",
+ "Hairy",
+ "Lesbian",
+ "Oral",
+ "Pornstar",
+ "Pussy",
+ "Sexy Latina",
+ "Teen",
+ "Teen Lesbian"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_002_aab6.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_007_4ebe.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_014_ee0b.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_018_6677.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_020_6317.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_026_9dc6.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_030_989b.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_033_5890.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_039_0a27.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_045_8539.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_047_441f.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_053_5632.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_059_4a22.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_060_f5d2.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_061_fc3f.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_067_9e8b.jpg",
+ "https://cdni.pornpics.com/1280/7/222/13944363/13944363_071_616a.jpg"
+ ],
+ "image_count": 17,
+ "date_scraped": "2025-11-06T22:58:26.176526+00:00",
+ "source_url": "https://www.pornpics.com/galleries/lesbian-girls-riley-reid-and-melissa-moore-lick-and-finger-fuck-each-other-13944363/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Melissa Moore_Riley Reid_Lesbian_girls_Riley_Reid_and_Melissa_Moore_lick_and_finger_fuck_each_other",
+ "inferred_tags": [
+ "Brunette",
+ "Fucking",
+ "Hairy",
+ "Lesbian",
+ "Oral",
+ "Pornstar",
+ "Pussy",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2258_Riley Reid_Naked_blonde_chick_fist_fucks_herself_to_strong_orgasmic_contractions/metadata.json b/Galleries/20251106_2258_Riley Reid_Naked_blonde_chick_fist_fucks_herself_to_strong_orgasmic_contractions/metadata.json
new file mode 100644
index 0000000..a988691
--- /dev/null
+++ b/Galleries/20251106_2258_Riley Reid_Naked_blonde_chick_fist_fucks_herself_to_strong_orgasmic_contractions/metadata.json
@@ -0,0 +1,68 @@
+{
+ "id": "20251106_2258",
+ "title": "Naked blonde chick fist fucks herself to strong orgasmic contractions",
+ "models": [
+ "Riley Reid"
+ ],
+ "categories": [
+ "Pretty",
+ "Amateur",
+ "Sexy",
+ "Babe",
+ "Glamour",
+ "Model",
+ "Beautiful",
+ "Solo",
+ "Big Clit",
+ "Pussy",
+ "Hot Naked Women"
+ ],
+ "tags": [
+ "Amateur",
+ "Beautiful",
+ "Blonde",
+ "Glamour",
+ "Hot Naked Women",
+ "Model",
+ "Pussy",
+ "Solo"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_003_66b3.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_006_ad49.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_010_9c71.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_012_673d.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_017_1542.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_022_d487.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_027_e985.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_028_e09e.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_034_1458.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_035_2dd7.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_041_197a.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_044_27ab.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_050_675b.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_054_e5e1.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_057_e964.jpg",
+ "https://cdni.pornpics.com/1280/7/159/17634641/17634641_062_98f4.jpg"
+ ],
+ "image_count": 16,
+ "date_scraped": "2025-11-06T22:58:37.951805+00:00",
+ "source_url": "https://www.pornpics.com/galleries/naked-blonde-chick-fist-fucks-herself-to-strong-orgasmic-contractions-17634641/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Riley Reid_Naked_blonde_chick_fist_fucks_herself_to_strong_orgasmic_contractions",
+ "inferred_tags": [
+ "Amateur",
+ "Beautiful",
+ "Blonde",
+ "Glamour",
+ "Model",
+ "Pussy",
+ "Solo"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking/metadata.json b/Galleries/20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking/metadata.json
new file mode 100644
index 0000000..b80f4c4
--- /dev/null
+++ b/Galleries/20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking/metadata.json
@@ -0,0 +1,95 @@
+{
+ "id": "20251106_2258",
+ "title": "Erotic teen beauty Riley Reid takes a hard cock in sexy doggystyle fucking",
+ "models": [
+ "Riley Reid",
+ "Van Wylde"
+ ],
+ "categories": [
+ "Ass Fucking",
+ "Best Pussy",
+ "Blindfold",
+ "Blindfold Surprise",
+ "Cum In Pussy",
+ "Cum On Pussy",
+ "Cum On Stockings",
+ "Footjob",
+ "Hairy",
+ "Hardcore",
+ "Pussy",
+ "Stockings",
+ "Teen",
+ "Teen Footjob",
+ "Teen Natural Tits",
+ "Teen Stockings",
+ "Tight Ass",
+ "Tiny Tits"
+ ],
+ "tags": [
+ "Ass",
+ "Best Pussy",
+ "Big Tits",
+ "Blindfold Surprise",
+ "Cum On Pussy",
+ "Cum On Stockings",
+ "Cumshot",
+ "Doggystyle",
+ "Footjob",
+ "Fucking",
+ "Hairy",
+ "Hardcore",
+ "Natural",
+ "Natural Look",
+ "Pussy",
+ "Stockings",
+ "Teen",
+ "Teen Footjob",
+ "Teen Natural Tits",
+ "Teen Stockings",
+ "Tight Ass"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_001_5d2f.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_002_4060.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_003_34f2.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_004_2989.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_005_2989.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_006_03b3.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_007_bf97.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_008_b49d.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_009_1574.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_010_809d.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_011_48df.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_012_a653.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_013_a4ca.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_014_477e.jpg",
+ "https://cdni.pornpics.com/1280/1/63/29035213/29035213_015_0684.jpg"
+ ],
+ "image_count": 15,
+ "date_scraped": "2025-11-06T22:58:16.191548+00:00",
+ "source_url": "https://www.pornpics.com/galleries/erotic-teen-beauty-riley-reid-takes-a-hard-cock-in-sexy-doggystyle-fucking-29035213/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking",
+ "last_refreshed": "2025-11-06T22:58:31.374501+00:00",
+ "inferred_tags": [
+ "Ass",
+ "Big Tits",
+ "Cumshot",
+ "Doggystyle",
+ "Footjob",
+ "Fucking",
+ "Hairy",
+ "Hardcore",
+ "Natural",
+ "Natural Look",
+ "Pussy",
+ "Stockings",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking/metadata_update_log.json b/Galleries/20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking/metadata_update_log.json
new file mode 100644
index 0000000..a81734d
--- /dev/null
+++ b/Galleries/20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking/metadata_update_log.json
@@ -0,0 +1,7 @@
+{
+ "timestamp": "2025-11-06T22:58:31.374598+00:00",
+ "changes": {
+ "categories": "merged",
+ "source": "updated"
+ }
+}
diff --git a/Galleries/20251106_2335_Paige Owens_Steve Holmes_MILFed_starring_Paige_Owens__Steve_Holmes_Hot_Porn_Pics/metadata.json b/Galleries/20251106_2335_Paige Owens_Steve Holmes_MILFed_starring_Paige_Owens__Steve_Holmes_Hot_Porn_Pics/metadata.json
new file mode 100644
index 0000000..1f51ea9
--- /dev/null
+++ b/Galleries/20251106_2335_Paige Owens_Steve Holmes_MILFed_starring_Paige_Owens__Steve_Holmes_Hot_Porn_Pics/metadata.json
@@ -0,0 +1,84 @@
+{
+ "id": "20251106_2335",
+ "title": "MILFed starring Paige Owens, Steve Holmes Hot Porn Pics",
+ "models": [
+ "Paige Owens",
+ "Steve Holmes"
+ ],
+ "categories": [
+ "Wedding",
+ "Cheating",
+ "Family",
+ "MILF",
+ "Fetish",
+ "Teen",
+ "Pussy",
+ "Feet",
+ "Brunette",
+ "Spreading",
+ "Cheating Wife",
+ "Bride",
+ "Teen Stepdaughter",
+ "Beautiful MILF",
+ "Sucking Cock",
+ "MILF Pussy"
+ ],
+ "tags": [
+ "Beautiful",
+ "Beautiful MILF",
+ "Bride",
+ "Brunette",
+ "Cheating Wife",
+ "Fetish",
+ "MILF",
+ "MILF Pussy",
+ "Mature",
+ "Pussy",
+ "Sucking Cock",
+ "Teen",
+ "Teen Stepdaughter"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_006_a8b1.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_020_f560.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_025_3add.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_037_d961.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_046_3ca7.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_052_a172.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_065_1f59.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_072_3093.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_089_b862.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_099_de98.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_108_3e00.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_120_8bef.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_129_386d.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_135_4e4a.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_142_7984.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_152_12e4.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_159_527e.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_164_7971.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_173_e83a.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_188_18b6.jpg",
+ "https://cdni.pornpics.com/1280/7/734/65759020/65759020_195_ef9d.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-06T23:35:19.445466+00:00",
+ "source_url": "https://www.pornpics.com/galleries/milfed-starring-paige-owens-steve-holmes-hot-porn-pics-65759020/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2335_Paige Owens_Steve Holmes_MILFed_starring_Paige_Owens__Steve_Holmes_Hot_Porn_Pics",
+ "inferred_tags": [
+ "Beautiful",
+ "Brunette",
+ "Fetish",
+ "MILF",
+ "Mature",
+ "Pussy",
+ "Teen"
+ ]
+}
\ No newline at end of file
diff --git a/Galleries/20251107_2029_Alex Tanner_Young_redhead_Alex_Tanner_shows_her_petite_body_while_completely_naked/metadata.json b/Galleries/20251107_2029_Alex Tanner_Young_redhead_Alex_Tanner_shows_her_petite_body_while_completely_naked/metadata.json
new file mode 100644
index 0000000..fa6711f
--- /dev/null
+++ b/Galleries/20251107_2029_Alex Tanner_Young_redhead_Alex_Tanner_shows_her_petite_body_while_completely_naked/metadata.json
@@ -0,0 +1,77 @@
+{
+ "id": "20251107_2029",
+ "title": "Young redhead Alex Tanner shows her petite body while completely naked",
+ "models": [
+ "Alex Tanner"
+ ],
+ "categories": [
+ "College",
+ "Redhead",
+ "Amateur",
+ "Teen",
+ "Centerfold",
+ "Spreading",
+ "Pussy",
+ "Feet",
+ "Legs",
+ "Cute",
+ "Redhead Teen",
+ "Natural Redhead",
+ "Redhead Freckles",
+ "Ginger Teen",
+ "Cute Redhead",
+ "Kinky",
+ "Amateur College",
+ "Pale Redhead"
+ ],
+ "tags": [
+ "Amateur",
+ "Amateur College",
+ "Cute Redhead",
+ "Ginger Teen",
+ "Kinky",
+ "Natural",
+ "Natural Look",
+ "Natural Redhead",
+ "Pale Redhead",
+ "Petite",
+ "Pussy",
+ "Redhead",
+ "Redhead Freckles",
+ "Redhead Teen",
+ "Teen"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_006_b0f0.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_011_6901.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_016_d06f.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_021_7e7a.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_024_2965.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_033_c960.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_034_50c0.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_041_d780.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_048_8ac3.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_053_a11c.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_055_a262.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_061_e5b9.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_064_b9d5.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_071_bf17.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_074_9f85.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_079_4c9d.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_088_a17b.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_089_0ea8.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_097_9abc.jpg",
+ "https://cdni.pornpics.com/1280/7/738/63489082/63489082_101_4a8f.jpg"
+ ],
+ "image_count": 20,
+ "date_scraped": "2025-11-07T20:29:27.087119+00:00",
+ "source_url": "https://www.pornpics.com/galleries/young-redhead-alex-tanner-shows-her-petite-body-while-completely-naked-63489082/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2029_Alex Tanner_Young_redhead_Alex_Tanner_shows_her_petite_body_while_completely_naked"
+}
\ No newline at end of file
diff --git a/Galleries/20251107_2031_Alex Tanner_Mr_POV_performed_by_Alex_Tanner_XXX_Photos/metadata.json b/Galleries/20251107_2031_Alex Tanner_Mr_POV_performed_by_Alex_Tanner_XXX_Photos/metadata.json
new file mode 100644
index 0000000..a17810d
--- /dev/null
+++ b/Galleries/20251107_2031_Alex Tanner_Mr_POV_performed_by_Alex_Tanner_XXX_Photos/metadata.json
@@ -0,0 +1,78 @@
+{
+ "id": "20251107_2031",
+ "title": "Mr POV performed by Alex Tanner XXX Photos",
+ "models": [
+ "Alex Tanner"
+ ],
+ "categories": [
+ "Petite",
+ "Natural Tits",
+ "POV",
+ "Reality",
+ "Missionary",
+ "Pornstar",
+ "Big Tits",
+ "Handjob",
+ "Pussy",
+ "Big Clit",
+ "Curvy Petite",
+ "Legs Up Missionary",
+ "POV Blowjob",
+ "Slut",
+ "Big Pussy",
+ "Sucking Cock"
+ ],
+ "tags": [
+ "Big Pussy",
+ "Big Tits",
+ "Blowjob",
+ "Curvy",
+ "Curvy Petite",
+ "Handjob",
+ "Legs Up Missionary",
+ "Missionary",
+ "Natural",
+ "Natural Look",
+ "POV",
+ "POV Blowjob",
+ "Petite",
+ "Pornstar",
+ "Pussy",
+ "Slut",
+ "Sucking Cock"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_001_bbcc.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_013_d5e4.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_018_8f84.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_027_fcc8.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_033_2c77.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_041_b4aa.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_043_e791.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_053_8fb3.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_063_0661.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_070_22c6.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_076_d369.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_082_5d2d.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_088_5474.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_092_115b.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_099_2ac4.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_100_4b51.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_108_452c.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_116_6394.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_118_7efc.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_124_8627.jpg",
+ "https://cdni.pornpics.com/1280/7/812/99243967/99243967_129_bf89.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-07T20:31:48.239211+00:00",
+ "source_url": "https://www.pornpics.com/galleries/mr-pov-performed-by-alex-tanner-xxx-photos-99243967/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2031_Alex Tanner_Mr_POV_performed_by_Alex_Tanner_XXX_Photos"
+}
\ No newline at end of file
diff --git a/Galleries/20251107_2031_Alex Tanner_Young_redhead_Alex_Tanner_demonstrating_her_perfectly_smooth_pussy/metadata.json b/Galleries/20251107_2031_Alex Tanner_Young_redhead_Alex_Tanner_demonstrating_her_perfectly_smooth_pussy/metadata.json
new file mode 100644
index 0000000..0a58aa4
--- /dev/null
+++ b/Galleries/20251107_2031_Alex Tanner_Young_redhead_Alex_Tanner_demonstrating_her_perfectly_smooth_pussy/metadata.json
@@ -0,0 +1,68 @@
+{
+ "id": "20251107_2031",
+ "title": "Young redhead Alex Tanner demonstrating her perfectly smooth pussy",
+ "models": [
+ "Alex Tanner"
+ ],
+ "categories": [
+ "Redhead",
+ "Teen",
+ "Shorts",
+ "Close Up",
+ "Shaved",
+ "Legs",
+ "High Heels",
+ "Tiny Tits",
+ "Panties",
+ "Nipples",
+ "Tight Shorts",
+ "Sexy Redhead",
+ "Redhead Teen",
+ "Big Ass Redhead",
+ "Redhead Ass"
+ ],
+ "tags": [
+ "Ass",
+ "Big Ass Redhead",
+ "Big Tits",
+ "High Heels",
+ "Panties",
+ "Pussy",
+ "Redhead",
+ "Redhead Ass",
+ "Redhead Teen",
+ "Sexy Redhead",
+ "Shaved",
+ "Shorts",
+ "Teen",
+ "Tight Shorts"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_001_0927.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_002_9917.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_003_097e.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_004_f08d.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_005_551c.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_006_551c.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_007_1bee.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_008_5d3b.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_009_fa92.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_010_113c.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_011_113c.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_012_6673.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_013_719d.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_014_4229.jpg",
+ "https://cdni.pornpics.com/1280/5/241/26775799/26775799_015_d831.jpg"
+ ],
+ "image_count": 15,
+ "date_scraped": "2025-11-07T20:31:21.604057+00:00",
+ "source_url": "https://www.pornpics.com/galleries/young-redhead-alex-tanner-demonstrating-her-perfectly-smooth-pussy-26775799/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2031_Alex Tanner_Young_redhead_Alex_Tanner_demonstrating_her_perfectly_smooth_pussy"
+}
\ No newline at end of file
diff --git a/Galleries/20251107_2031_Esmi Lee_Brooke Wylde_Gianna Nicole_Tiffany Taylor_Nikki Lima_Sasha Summers_Alex Tanner_J Mac_Sabrina Banks_Dani Desire_Blonde_party_girl_flashes_nude_upskirt___gets_cum_on_face_in_hot_orgy/metadata.json b/Galleries/20251107_2031_Esmi Lee_Brooke Wylde_Gianna Nicole_Tiffany Taylor_Nikki Lima_Sasha Summers_Alex Tanner_J Mac_Sabrina Banks_Dani Desire_Blonde_party_girl_flashes_nude_upskirt___gets_cum_on_face_in_hot_orgy/metadata.json
new file mode 100644
index 0000000..fe5dca0
--- /dev/null
+++ b/Galleries/20251107_2031_Esmi Lee_Brooke Wylde_Gianna Nicole_Tiffany Taylor_Nikki Lima_Sasha Summers_Alex Tanner_J Mac_Sabrina Banks_Dani Desire_Blonde_party_girl_flashes_nude_upskirt___gets_cum_on_face_in_hot_orgy/metadata.json
@@ -0,0 +1,84 @@
+{
+ "id": "20251107_2031",
+ "title": "Blonde party girl flashes nude upskirt & gets cum on face in hot orgy",
+ "models": [
+ "Esmi Lee",
+ "Brooke Wylde",
+ "Gianna Nicole",
+ "Tiffany Taylor",
+ "Nikki Lima",
+ "Sasha Summers",
+ "Alex Tanner",
+ "J Mac",
+ "Sabrina Banks",
+ "Dani Desire"
+ ],
+ "categories": [
+ "Party",
+ "Ass Fucking",
+ "MILF",
+ "Hardcore",
+ "Orgy",
+ "Groupsex",
+ "Indian",
+ "Ass",
+ "Teen",
+ "Mature",
+ "Redhead Fuck",
+ "Redhead Doggystyle",
+ "Redhead MILF",
+ "Teen Orgy",
+ "Skinny Mature Fuck",
+ "Indian Fuck",
+ "Mature Orgy",
+ "MILF Hardcore"
+ ],
+ "tags": [
+ "Ass",
+ "Blonde",
+ "Cumshot",
+ "Doggystyle",
+ "Fucking",
+ "Hardcore",
+ "Indian Fuck",
+ "MILF",
+ "MILF Hardcore",
+ "Mature",
+ "Mature Orgy",
+ "Orgy",
+ "Party",
+ "Redhead",
+ "Redhead Doggystyle",
+ "Redhead Fuck",
+ "Redhead MILF",
+ "Skinny",
+ "Skinny Mature Fuck",
+ "Teen",
+ "Teen Orgy"
+ ],
+ "source": {
+ "network": "PornPics",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_001_19d8.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_002_e511.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_003_6717.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_004_cc4b.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_005_f15c.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_006_7891.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_007_9652.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_008_b304.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_009_4816.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_010_8e32.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_011_2354.jpg",
+ "https://cdni.pornpics.com/1280/1/306/17122410/17122410_012_4d90.jpg"
+ ],
+ "image_count": 12,
+ "date_scraped": "2025-11-07T20:31:35.064524+00:00",
+ "source_url": "https://www.pornpics.com/galleries/blonde-party-girl-flashes-nude-upskirt-gets-cum-on-face-in-hot-orgy-17122410/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2031_Esmi Lee_Brooke Wylde_Gianna Nicole_Tiffany Taylor_Nikki Lima_Sasha Summers_Alex Tanner_J Mac_Sabrina Banks_Dani Desire_Blonde_party_girl_flashes_nude_upskirt___gets_cum_on_face_in_hot_orgy"
+}
\ No newline at end of file
diff --git a/Galleries/20251107_2037_Jayden Lee_Marcus London_Hot_babe_in_a_sinful_bikini_Jayden_Lee_blows_a_big_rod___gets_fucked_on_a_sofa/metadata.json b/Galleries/20251107_2037_Jayden Lee_Marcus London_Hot_babe_in_a_sinful_bikini_Jayden_Lee_blows_a_big_rod___gets_fucked_on_a_sofa/metadata.json
new file mode 100644
index 0000000..1dee94b
--- /dev/null
+++ b/Galleries/20251107_2037_Jayden Lee_Marcus London_Hot_babe_in_a_sinful_bikini_Jayden_Lee_blows_a_big_rod___gets_fucked_on_a_sofa/metadata.json
@@ -0,0 +1,83 @@
+{
+ "id": "20251107_2037",
+ "title": "Hot babe in a sinful bikini Jayden Lee blows a big rod & gets fucked on a sofa",
+ "models": [
+ "Jayden Lee",
+ "Marcus London"
+ ],
+ "categories": [
+ "Asian",
+ "Skinny",
+ "Teen",
+ "Cumshot",
+ "Panties",
+ "Blowjob",
+ "Pussy",
+ "Brunette",
+ "Hardcore",
+ "Tiny Tits",
+ "Asian Model",
+ "Asian Blowjob",
+ "Asian Hardcore",
+ "Asian Fuck",
+ "Model Fuck",
+ "Asian Lingerie",
+ "Asian Cumshot"
+ ],
+ "tags": [
+ "Asian Blowjob",
+ "Asian Cumshot",
+ "Asian Fuck",
+ "Asian Hardcore",
+ "Asian Lingerie",
+ "Asian Model",
+ "Big Tits",
+ "Blowjob",
+ "Brunette",
+ "Couch",
+ "Cumshot",
+ "Fucking",
+ "Hardcore",
+ "Lingerie",
+ "Model",
+ "Model Fuck",
+ "Panties",
+ "Pussy",
+ "Skinny",
+ "Teen"
+ ],
+ "source": {
+ "network": "Nubile Films",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_003_233d.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_007_8a98.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_009_c3f0.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_014_e011.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_020_9e99.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_023_e9ab.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_024_a6cd.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_027_8af2.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_032_b8f5.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_033_4921.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_037_8b53.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_041_c64f.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_044_d0bc.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_047_ca32.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_050_44bf.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_052_dd1f.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_055_69d4.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_059_7f1a.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_063_c12b.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_064_f23f.jpg",
+ "https://cdni.pornpics.com/1280/7/271/16020943/16020943_068_d3d9.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-07T20:37:31.031921+00:00",
+ "source_url": "https://www.pornpics.com/galleries/hot-babe-in-a-sinful-bikini-jayden-lee-blows-a-big-rod-gets-fucked-on-a-sofa-16020943/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2037_Jayden Lee_Marcus London_Hot_babe_in_a_sinful_bikini_Jayden_Lee_blows_a_big_rod___gets_fucked_on_a_sofa"
+}
\ No newline at end of file
diff --git a/Galleries/20251107_2037_Mia Split_Aaron Rock_Alexa Flexy_Evil_Angel_featuring_Aaron_Rock__Alexa_Flexy__Mia_Split_Naked_Images/metadata.json b/Galleries/20251107_2037_Mia Split_Aaron Rock_Alexa Flexy_Evil_Angel_featuring_Aaron_Rock__Alexa_Flexy__Mia_Split_Naked_Images/metadata.json
new file mode 100644
index 0000000..06a9cd2
--- /dev/null
+++ b/Galleries/20251107_2037_Mia Split_Aaron Rock_Alexa Flexy_Evil_Angel_featuring_Aaron_Rock__Alexa_Flexy__Mia_Split_Naked_Images/metadata.json
@@ -0,0 +1,77 @@
+{
+ "id": "20251107_2037",
+ "title": "Evil Angel featuring Aaron Rock, Alexa Flexy, Mia Split Naked Images",
+ "models": [
+ "Mia Split",
+ "Aaron Rock",
+ "Alexa Flexy"
+ ],
+ "categories": [
+ "Interracial",
+ "Threesome",
+ "Natural Tits",
+ "Ass",
+ "Pussy",
+ "Anal",
+ "Petite",
+ "Teen",
+ "Flexible",
+ "Amateur",
+ "Hot Naked Women",
+ "Interracial Anal",
+ "Interracial Threesome",
+ "Black And White"
+ ],
+ "tags": [
+ "Amateur",
+ "Anal",
+ "Anal Fetish",
+ "Ass",
+ "Big Tits",
+ "Black And White",
+ "Hot Naked Women",
+ "Interracial",
+ "Interracial Anal",
+ "Interracial Threesome",
+ "Natural",
+ "Natural Look",
+ "Petite",
+ "Pussy",
+ "Teen",
+ "Threesome"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_006_4bed.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_014_28ac.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_017_2467.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_026_bacd.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_040_2694.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_047_264b.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_051_75fc.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_060_544d.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_068_bbe3.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_077_3ac7.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_081_058f.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_082_6dbf.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_094_6869.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_099_c46c.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_107_8129.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_114_c628.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_120_0530.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_126_8c61.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_130_f167.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_143_6cfb.jpg",
+ "https://cdni.pornpics.com/1280/7/789/71699035/71699035_146_fcd7.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-07T20:37:59.865361+00:00",
+ "source_url": "https://www.pornpics.com/galleries/evil-angel-featuring-aaron-rock-alexa-flexy-mia-split-naked-images-71699035/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2037_Mia Split_Aaron Rock_Alexa Flexy_Evil_Angel_featuring_Aaron_Rock__Alexa_Flexy__Mia_Split_Naked_Images"
+}
\ No newline at end of file
diff --git a/Galleries/20251107_2037_Unknown_Model_OnlyFans_Luv_Hanna_Zuki_Luv_Hanna_Zuki/metadata.json b/Galleries/20251107_2037_Unknown_Model_OnlyFans_Luv_Hanna_Zuki_Luv_Hanna_Zuki/metadata.json
new file mode 100644
index 0000000..8731292
--- /dev/null
+++ b/Galleries/20251107_2037_Unknown_Model_OnlyFans_Luv_Hanna_Zuki_Luv_Hanna_Zuki/metadata.json
@@ -0,0 +1,67 @@
+{
+ "id": "20251107_2037",
+ "title": "OnlyFans Luv Hanna Zuki Luv Hanna Zuki",
+ "models": [],
+ "categories": [
+ "Asian",
+ "Selfie",
+ "Amateur",
+ "Lingerie",
+ "Ass",
+ "Feet",
+ "Close Up",
+ "Asshole",
+ "Babe",
+ "Beautiful",
+ "Asian Model",
+ "Asian Teen",
+ "Perfect Teen Body",
+ "Perfect Ass",
+ "Asian Lingerie",
+ "Beautiful Asian",
+ "Big Ass Teen",
+ "Brunette Teen"
+ ],
+ "tags": [
+ "Amateur",
+ "Asian Lingerie",
+ "Asian Model",
+ "Asian Teen",
+ "Ass",
+ "Beautiful",
+ "Beautiful Asian",
+ "Big Ass Teen",
+ "Brunette",
+ "Brunette Teen",
+ "Lingerie",
+ "Model",
+ "Perfect",
+ "Perfect Ass",
+ "Perfect Body",
+ "Perfect Teen Body",
+ "Teen"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_001_98e1.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_002_6402.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_003_906f.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_004_2519.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_005_2519.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_006_3d1f.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_007_c7d9.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_008_c7d9.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_009_6952.jpg",
+ "https://cdni.pornpics.com/1280/3/15/52529080/52529080_010_9f3d.jpg"
+ ],
+ "image_count": 10,
+ "date_scraped": "2025-11-07T20:37:13.826670+00:00",
+ "source_url": "https://www.pornpics.com/galleries/onlyfans-luv-hanna-zuki-luv-hanna-zuki-52529080/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2037_Unknown_Model_OnlyFans_Luv_Hanna_Zuki_Luv_Hanna_Zuki"
+}
\ No newline at end of file
diff --git a/Galleries/20251107_2319_Alora Jaymes_Sexy_mature_with_big_tits_Alora_Jaymes_gives_head_and_gets_rammed/metadata.json b/Galleries/20251107_2319_Alora Jaymes_Sexy_mature_with_big_tits_Alora_Jaymes_gives_head_and_gets_rammed/metadata.json
new file mode 100644
index 0000000..38cb0d4
--- /dev/null
+++ b/Galleries/20251107_2319_Alora Jaymes_Sexy_mature_with_big_tits_Alora_Jaymes_gives_head_and_gets_rammed/metadata.json
@@ -0,0 +1,85 @@
+{
+ "id": "20251107_2319",
+ "title": "Sexy mature with big tits Alora Jaymes gives head and gets rammed",
+ "models": [
+ "Alora Jaymes"
+ ],
+ "categories": [
+ "Deepthroat",
+ "MILF",
+ "Fingering",
+ "Blowjob",
+ "Amateur",
+ "Undressing",
+ "Ass",
+ "Spreading",
+ "Natural Tits",
+ "Close Up",
+ "MILF Sucking Cock",
+ "Amateur Deepthroat",
+ "Amateur Blowjob",
+ "MILF Deepthroat",
+ "Skinny MILF Fuck",
+ "Fingering Panties",
+ "Beautiful MILF",
+ "Brunette MILF"
+ ],
+ "tags": [
+ "Amateur",
+ "Amateur Blowjob",
+ "Amateur Deepthroat",
+ "Ass",
+ "Beautiful",
+ "Beautiful MILF",
+ "Big Tits",
+ "Blowjob",
+ "Brunette",
+ "Brunette MILF",
+ "Fingering",
+ "Fingering Panties",
+ "Fucking",
+ "MILF",
+ "MILF Deepthroat",
+ "MILF Sucking Cock",
+ "Mature",
+ "Natural",
+ "Natural Look",
+ "Panties",
+ "Skinny",
+ "Skinny MILF Fuck"
+ ],
+ "source": {
+ "network": "Amateur Europe",
+ "channel": null
+ },
+ "rating": "",
+ "views": null,
+ "image_urls": [
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_003_2111.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_019_6348.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_025_081f.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_039_1999.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_051_265d.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_061_8154.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_065_df40.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_081_4f2a.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_082_c7b0.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_083_4454.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_095_e7a6.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_111_da0a.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_113_b4fc.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_129_b070.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_139_20c6.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_142_88c8.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_152_6319.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_167_eb1e.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_175_2ab9.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_191_9439.jpg",
+ "https://cdni.pornpics.com/1280/7/443/54684463/54684463_200_7eb0.jpg"
+ ],
+ "image_count": 21,
+ "date_scraped": "2025-11-07T23:19:54.823362+00:00",
+ "source_url": "https://www.pornpics.com/galleries/sexy-mature-with-big-tits-alora-jaymes-gives-head-and-gets-rammed-54684463/",
+ "source_label": null,
+ "import_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2319_Alora Jaymes_Sexy_mature_with_big_tits_Alora_Jaymes_gives_head_and_gets_rammed"
+}
\ No newline at end of file
diff --git a/Galleries/index.json b/Galleries/index.json
index cfd1053..53f0222 100644
--- a/Galleries/index.json
+++ b/Galleries/index.json
@@ -32,6 +32,7 @@
"Hairy Amateur",
"Hairy Redhead",
"Hairy Redhead Pussy",
+ "Office",
"Redhead Ass",
"Redhead Pussy"
],
@@ -927,5 +928,1088 @@
"folder": "20251106_2055_Jayme Langford_ATK_Archives_featuring_Jayme_Langford_Hot_Images",
"metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2055_Jayme Langford_ATK_Archives_featuring_Jayme_Langford_Hot_Images/metadata.json",
"timestamp": "2025-11-06T20:55:07.129269+00:00"
+ },
+ {
+ "id": "20251106_2236",
+ "title": "Amateur mom Susanna Glam gets stripped and fucked by her personal trainer",
+ "models": [
+ "Susanna Glam",
+ "Deny Lou"
+ ],
+ "tags": [
+ "Amateur",
+ "Beautiful",
+ "Beautiful Granny",
+ "Blowjob",
+ "GILF",
+ "Granny Handjob",
+ "Granny Slut",
+ "Handjob",
+ "Mature",
+ "Mature Boy",
+ "Mom Boy",
+ "Mom Son",
+ "Pussy",
+ "Sexy GILF",
+ "Teen"
+ ],
+ "url": "https://www.pornpics.com/galleries/amateur-mom-susanna-glam-gets-stripped-and-fucked-by-her-personal-trainer-54709783/",
+ "folder": "20251106_2236_Susanna Glam_Deny Lou_Amateur_mom_Susanna_Glam_gets_stripped_and_fucked_by_her_personal_trainer",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Susanna Glam_Deny Lou_Amateur_mom_Susanna_Glam_gets_stripped_and_fucked_by_her_personal_trainer/metadata.json",
+ "timestamp": "2025-11-06T22:36:11.000270+00:00"
+ },
+ {
+ "id": "20251106_2236",
+ "title": "All Over 30 starring Angel Rai, Chicka Bomb Nude Photos",
+ "models": [
+ "Angel Rai",
+ "Chicka Bomb"
+ ],
+ "tags": [
+ "Amateur",
+ "Ass",
+ "Beautiful",
+ "Beautiful Pussy",
+ "Hot Naked Women",
+ "Lesbian",
+ "Lesbian Facesitting",
+ "Lesbian Scissoring",
+ "Nice Pussy",
+ "Petite",
+ "Pussy",
+ "Redhead",
+ "Redhead Lesbian",
+ "Teen",
+ "Ukraine Pussy",
+ "Ukrainian",
+ "Wet Teen Pussy"
+ ],
+ "url": "https://www.pornpics.com/galleries/all-over-30-starring-angel-rai-chicka-bomb-nude-photos-66224044/",
+ "folder": "20251106_2236_Angel Rai_Chicka Bomb_All_Over_30_starring_Angel_Rai__Chicka_Bomb_Nude_Photos",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Angel Rai_Chicka Bomb_All_Over_30_starring_Angel_Rai__Chicka_Bomb_Nude_Photos/metadata.json",
+ "timestamp": "2025-11-06T22:36:16.505880+00:00"
+ },
+ {
+ "id": "20251106_2236",
+ "title": "Adorable little teen Elen rides her boyfriend's dong and gets a facial",
+ "models": [
+ "Taissia Shanti"
+ ],
+ "tags": [
+ "Ass",
+ "Big Cock",
+ "Big Tits",
+ "Clothed Fuck",
+ "Cumshot",
+ "Facial",
+ "Fucking",
+ "Hardcore",
+ "Pussy",
+ "Russian",
+ "Russian Teen",
+ "Shorts",
+ "Skinny",
+ "Skinny Teen Fuck",
+ "Small Tits Fuck",
+ "Teen",
+ "Teen Cum",
+ "Teen Facesitting",
+ "Teen Fuck",
+ "Teen Hardcore"
+ ],
+ "url": "https://www.pornpics.com/galleries/adorable-little-teen-elen-rides-her-boyfriends-dong-and-gets-a-facial-73470783/",
+ "folder": "20251106_2236_Taissia Shanti_Adorable_little_teen_Elen_rides_her_boyfriend_s_dong_and_gets_a_facial",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Taissia Shanti_Adorable_little_teen_Elen_rides_her_boyfriend_s_dong_and_gets_a_facial/metadata.json",
+ "timestamp": "2025-11-06T22:36:21.117480+00:00"
+ },
+ {
+ "id": "20251106_2236",
+ "title": "Porn Megaload featuring Kama Oxi, Tom Holland Sex Pictures",
+ "models": [
+ "Kama Oxi",
+ "Tom Holland"
+ ],
+ "tags": [
+ "Beautiful",
+ "Beautiful Blowjob",
+ "Blowjob",
+ "Brunette",
+ "Brunette Teen",
+ "Fit",
+ "Friends Mom",
+ "Fucking",
+ "Mom Boy",
+ "Mom Pussy",
+ "Mom Son",
+ "Pussy",
+ "Teen",
+ "Teen Schoolgirl"
+ ],
+ "url": "https://www.pornpics.com/galleries/porn-megaload-featuring-kama-oxi-tom-holland-sex-pictures-76288217/",
+ "folder": "20251106_2236_Kama Oxi_Tom Holland_Porn_Megaload_featuring_Kama_Oxi__Tom_Holland_Sex_Pictures",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Kama Oxi_Tom Holland_Porn_Megaload_featuring_Kama_Oxi__Tom_Holland_Sex_Pictures/metadata.json",
+ "timestamp": "2025-11-06T22:36:26.070601+00:00"
+ },
+ {
+ "id": "20251106_2236",
+ "title": "Pretty brunette teen Jorden Kennedy exposes her sweet body in a hot striptease",
+ "models": [
+ "jorden kennedy"
+ ],
+ "tags": [
+ "Amateur",
+ "Amateur Hairy Pussy",
+ "Beautiful",
+ "Beautiful Hairy",
+ "Big Hairy Pussy",
+ "Brunette",
+ "Extremely Hairy Pussy",
+ "Hairy",
+ "Hairy Bush",
+ "Natural",
+ "Natural Hairy",
+ "Natural Look",
+ "Outdoor",
+ "Pussy",
+ "Teen"
+ ],
+ "url": "https://www.pornpics.com/galleries/pretty-brunette-teen-jorden-kennedy-exposes-her-sweet-body-in-a-hot-striptease-47702961/",
+ "folder": "20251106_2236_jorden kennedy_Pretty_brunette_teen_Jorden_Kennedy_exposes_her_sweet_body_in_a_hot_striptease",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_jorden kennedy_Pretty_brunette_teen_Jorden_Kennedy_exposes_her_sweet_body_in_a_hot_striptease/metadata.json",
+ "timestamp": "2025-11-06T22:36:35.305079+00:00"
+ },
+ {
+ "id": "20251106_2236",
+ "title": "Curvy brunette Riley Reid gets a DP in a steamy threesome with hung studs",
+ "models": [
+ "Markus Dupree",
+ "Ramon Nomar",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Anal",
+ "Anal Fetish",
+ "Brunette",
+ "Brunette Hairy Pussy",
+ "Curvy",
+ "Double Anal",
+ "Dress",
+ "Facial",
+ "Fetish",
+ "Hairy",
+ "Hairy Upskirt",
+ "High Heels",
+ "Latex",
+ "Latex Fetish",
+ "Panties",
+ "Penetration",
+ "Pornstar",
+ "Pussy",
+ "Sexy Dress",
+ "Short Skirt High Heels",
+ "Short Skirt No Panties",
+ "Skirt",
+ "Threesome",
+ "Tight Dress",
+ "Upskirt No Panties"
+ ],
+ "url": "https://www.pornpics.com/galleries/curvy-brunette-riley-reid-gets-a-dp-in-a-steamy-threesome-with-hung-studs-31077441/",
+ "folder": "20251106_2236_Markus Dupree_Ramon Nomar_Riley Reid_Curvy_brunette_Riley_Reid_gets_a_DP_in_a_steamy_threesome_with_hung_studs",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Markus Dupree_Ramon Nomar_Riley Reid_Curvy_brunette_Riley_Reid_gets_a_DP_in_a_steamy_threesome_with_hung_studs/metadata.json",
+ "timestamp": "2025-11-06T22:36:52.785931+00:00"
+ },
+ {
+ "id": "20251106_2236",
+ "title": "Skinny coed with trimmed muff Riley Reid gives shows her spread love holes",
+ "models": [
+ "Riley Reid"
+ ],
+ "tags": [
+ "Ass",
+ "Ass Spread",
+ "Beautiful",
+ "Bent Over",
+ "Bent Over Ass",
+ "Hairy",
+ "Hot Naked Women",
+ "Nude",
+ "PAWG Solo",
+ "Pornstar",
+ "Pussy",
+ "Sexy Ass",
+ "Skinny",
+ "Solo",
+ "Wet Pussy Close Up"
+ ],
+ "url": "https://www.pornpics.com/galleries/skinny-coed-with-trimmed-muff-riley-reid-gives-shows-her-spread-love-holes-56770461/",
+ "folder": "20251106_2236_Riley Reid_Skinny_coed_with_trimmed_muff_Riley_Reid_gives_shows_her_spread_love_holes",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2236_Riley Reid_Skinny_coed_with_trimmed_muff_Riley_Reid_gives_shows_her_spread_love_holes/metadata.json",
+ "timestamp": "2025-11-06T22:36:56.876114+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Cute brunette with a petite figure Riley Reid gets ass railed by a BBC",
+ "models": [
+ "Dredd",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Anal",
+ "Anal Fetish",
+ "Ass",
+ "BBC",
+ "BBC Anal",
+ "Big Black Cock",
+ "Big Black Dick",
+ "Big Cock",
+ "Big Cock Blowjob",
+ "Big Dick Anal",
+ "Blowjob",
+ "Brunette",
+ "Doggystyle",
+ "Doggystyle Anal",
+ "Fucking",
+ "Interracial",
+ "Interracial Anal",
+ "Monster Cock",
+ "Petite",
+ "Pool"
+ ],
+ "url": "https://www.pornpics.com/galleries/cute-brunette-with-a-petite-figure-riley-reid-gets-ass-railed-by-a-bbc-60016759/",
+ "folder": "20251106_2237_Dredd_Riley Reid_Cute_brunette_with_a_petite_figure_Riley_Reid_gets_ass_railed_by_a_BBC",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Dredd_Riley Reid_Cute_brunette_with_a_petite_figure_Riley_Reid_gets_ass_railed_by_a_BBC/metadata.json",
+ "timestamp": "2025-11-06T22:37:01.679280+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Mr POV starring Riley Reid Naked Images",
+ "models": [
+ "Riley Reid"
+ ],
+ "tags": [
+ "Brunette",
+ "Cumshot",
+ "Handjob",
+ "Money",
+ "Outdoor",
+ "POV",
+ "POV Handjob",
+ "Petite",
+ "Pornstar"
+ ],
+ "url": "https://www.pornpics.com/galleries/mr-pov-starring-riley-reid-naked-images-39106284/",
+ "folder": "20251106_2237_Riley Reid_Mr_POV_starring_Riley_Reid_Naked_Images",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Mr_POV_starring_Riley_Reid_Naked_Images/metadata.json",
+ "timestamp": "2025-11-06T22:37:09.633343+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Smiley teenage hottie with tattoos revealing her perky titties and neat ass",
+ "models": [
+ "Riley Reid"
+ ],
+ "tags": [
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Brunette Ass",
+ "Brunette Hairy Pussy",
+ "Cute Face",
+ "Cute Hairy",
+ "Hairy",
+ "Hairy Erotica",
+ "Hairy Teen Pussy",
+ "Hot Naked Women",
+ "Natural",
+ "Natural Look",
+ "Pussy",
+ "Teen",
+ "Tight Ass"
+ ],
+ "url": "https://www.pornpics.com/galleries/smiley-teenage-hottie-with-tattoos-revealing-her-perky-titties-and-neat-ass-63010314/",
+ "folder": "20251106_2237_Riley Reid_Smiley_teenage_hottie_with_tattoos_revealing_her_perky_titties_and_neat_ass",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Smiley_teenage_hottie_with_tattoos_revealing_her_perky_titties_and_neat_ass/metadata.json",
+ "timestamp": "2025-11-06T22:37:14.542771+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Nerdy American schoolgirl with tiny tits Riley Reid showing off",
+ "models": [
+ "Riley Reid"
+ ],
+ "tags": [
+ "Big Tits",
+ "Brunette",
+ "Classroom",
+ "College Pussy",
+ "English",
+ "Pussy",
+ "School Uniform",
+ "Uniform",
+ "Uniform Fetish"
+ ],
+ "url": "https://www.pornpics.com/galleries/nerdy-american-schoolgirl-with-tiny-tits-riley-reid-showing-off-24451045/",
+ "folder": "20251106_2237_Riley Reid_Nerdy_American_schoolgirl_with_tiny_tits_Riley_Reid_showing_off",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Nerdy_American_schoolgirl_with_tiny_tits_Riley_Reid_showing_off/metadata.json",
+ "timestamp": "2025-11-06T22:37:20.020823+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Petite female Riley Reid rips off her prison jumper to model in the nude",
+ "models": [
+ "Riley Reid"
+ ],
+ "tags": [
+ "Beautiful",
+ "Beautiful Mature",
+ "Brunette",
+ "Mature",
+ "Mature Older Women",
+ "Mature Pussy",
+ "Mature Spreading",
+ "Mature Undressing",
+ "Model",
+ "Older Women",
+ "Over 50",
+ "Petite",
+ "Pornstar",
+ "Pussy",
+ "Sexy Older Women"
+ ],
+ "url": "https://www.pornpics.com/galleries/petite-female-riley-reid-rips-off-her-prison-jumper-to-model-in-the-nude-12420368/",
+ "folder": "20251106_2237_Riley Reid_Petite_female_Riley_Reid_rips_off_her_prison_jumper_to_model_in_the_nude",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Petite_female_Riley_Reid_rips_off_her_prison_jumper_to_model_in_the_nude/metadata.json",
+ "timestamp": "2025-11-06T22:37:24.611918+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Attractive Eva Lovia & Riley Reid fuck a handsome businessman in a 3some",
+ "models": [
+ "Damon Dice",
+ "Eva Lovia",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Big Tits",
+ "Blowjob",
+ "Brunette",
+ "Brunette Natural Tits",
+ "Cowgirl",
+ "Fucking",
+ "Natural",
+ "Natural Look",
+ "Petite",
+ "Pornstar",
+ "Pussy",
+ "Reverse Cowgirl",
+ "Skinny",
+ "Skinny Small Tits",
+ "Threesome",
+ "Trimmed Pussy"
+ ],
+ "url": "https://www.pornpics.com/galleries/attractive-eva-lovia-riley-reid-fuck-a-handsome-businessman-in-a-3some-56531264/",
+ "folder": "20251106_2237_Damon Dice_Eva Lovia_Riley Reid_Attractive_Eva_Lovia___Riley_Reid_fuck_a_handsome_businessman_in_a_3some",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Damon Dice_Eva Lovia_Riley Reid_Attractive_Eva_Lovia___Riley_Reid_fuck_a_handsome_businessman_in_a_3some/metadata.json",
+ "timestamp": "2025-11-06T22:37:29.826327+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Petite babysitter Riley Reid enjoys a cheating husband's big dick",
+ "models": [
+ "Preston Parker",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Beautiful",
+ "Beautiful Blowjob",
+ "Big Tits",
+ "Blowjob",
+ "Dress",
+ "Fucking",
+ "Hardcore",
+ "High Heels",
+ "High Heels Fuck",
+ "Lingerie",
+ "Petite",
+ "Pussy",
+ "Pussy Fuck",
+ "Sexy Blowjob",
+ "Short Skirt High Heels",
+ "Skirt",
+ "Summer Dress",
+ "Tight Dress",
+ "Underwear"
+ ],
+ "url": "https://www.pornpics.com/galleries/petite-babysitter-riley-reid-enjoys-a-cheating-husbands-big-dick-90908574/",
+ "folder": "20251106_2237_Preston Parker_Riley Reid_Petite_babysitter_Riley_Reid_enjoys_a_cheating_husband_s_big_dick",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Preston Parker_Riley Reid_Petite_babysitter_Riley_Reid_enjoys_a_cheating_husband_s_big_dick/metadata.json",
+ "timestamp": "2025-11-06T22:37:36.547337+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Tiny brunette Riley Reid shows her sexy holes and fucks a huge dick in POV",
+ "models": [
+ "Mike Adriano",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Amateur",
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Doggystyle",
+ "Fucking",
+ "Gaping Pussy",
+ "Hairy",
+ "Hairy Asshole",
+ "Hairy MILF Fuck",
+ "Hairy Pussy Fuck",
+ "Hardcore",
+ "MILF",
+ "MILF Fuck",
+ "Mature",
+ "POV",
+ "Perfect",
+ "Perfect Body",
+ "Pussy",
+ "Pussy Fuck",
+ "Pussy Spreading",
+ "Skinny",
+ "Skinny Girl Fat Pussy"
+ ],
+ "url": "https://www.pornpics.com/galleries/tiny-brunette-riley-reid-shows-her-sexy-holes-and-fucks-a-huge-dick-in-pov-56734787/",
+ "folder": "20251106_2237_Mike Adriano_Riley Reid_Tiny_brunette_Riley_Reid_shows_her_sexy_holes_and_fucks_a_huge_dick_in_POV",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Mike Adriano_Riley Reid_Tiny_brunette_Riley_Reid_shows_her_sexy_holes_and_fucks_a_huge_dick_in_POV/metadata.json",
+ "timestamp": "2025-11-06T22:37:44.327840+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Mr POV featuring Riley Reid Nude Photos",
+ "models": [
+ "Riley Reid"
+ ],
+ "tags": [
+ "Blowjob",
+ "Cum On Face",
+ "Cumshot",
+ "Facial",
+ "Handjob",
+ "POV",
+ "POV Handjob",
+ "Petite",
+ "Petite Facial",
+ "Pussy"
+ ],
+ "url": "https://www.pornpics.com/galleries/mr-pov-featuring-riley-reid-nude-photos-58732399/",
+ "folder": "20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Mr_POV_featuring_Riley_Reid_Nude_Photos/metadata.json",
+ "timestamp": "2025-11-06T22:37:48.823848+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Kinky nympho Riley Reid hikes up her red dress and gets blacked hardcore",
+ "models": [
+ "Riley Reid",
+ "Xavier Miller"
+ ],
+ "tags": [
+ "Ass",
+ "BBC",
+ "Big Black Cock",
+ "Big Cock",
+ "Big Tits",
+ "Caught Masturbating",
+ "Dick",
+ "Dress",
+ "Hardcore",
+ "Interracial",
+ "Monster Cock",
+ "Panties",
+ "Pornstar",
+ "Skinny",
+ "Skinny BBC",
+ "Skinny Interracial",
+ "Skinny Small Tits",
+ "Upskirt No Panties"
+ ],
+ "url": "https://www.pornpics.com/galleries/kinky-nympho-riley-reid-hikes-up-her-red-dress-and-gets-blacked-hardcore-75565937/",
+ "folder": "20251106_2237_Riley Reid_Xavier Miller_Kinky_nympho_Riley_Reid_hikes_up_her_red_dress_and_gets_blacked_hardcore",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Riley Reid_Xavier Miller_Kinky_nympho_Riley_Reid_hikes_up_her_red_dress_and_gets_blacked_hardcore/metadata.json",
+ "timestamp": "2025-11-06T22:37:53.310419+00:00"
+ },
+ {
+ "id": "20251106_2237",
+ "title": "Petite Riley Reid & busty Lea Lexis tease with tits & flash hot panty upskirts",
+ "models": [
+ "Lea Lexis",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Ass",
+ "Big Tits",
+ "Brunette",
+ "Busty",
+ "Dress",
+ "Hairy",
+ "Hairy Armpits",
+ "Hairy Brunette",
+ "Hairy Panties",
+ "Lesbian",
+ "Natural",
+ "Natural Look",
+ "Panties",
+ "Petite",
+ "Romanian",
+ "Summer Dress",
+ "Tight Dress",
+ "Upskirt Panties"
+ ],
+ "url": "https://www.pornpics.com/galleries/petite-riley-reid-busty-lea-lexis-tease-with-tits-flash-hot-panty-upskirts-89239818/",
+ "folder": "20251106_2237_Lea Lexis_Riley Reid_Petite_Riley_Reid___busty_Lea_Lexis_tease_with_tits___flash_hot_panty_upskirts",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2237_Lea Lexis_Riley Reid_Petite_Riley_Reid___busty_Lea_Lexis_tease_with_tits___flash_hot_panty_upskirts/metadata.json",
+ "timestamp": "2025-11-06T22:37:58.188655+00:00"
+ },
+ {
+ "id": "20251106_2238",
+ "title": "Leggy white chick Riley Reid strips to black stockings with her glasses on",
+ "models": [
+ "Riley Reid"
+ ],
+ "tags": [
+ "Big Tits",
+ "Natural",
+ "Natural Look",
+ "Office",
+ "Pornstar",
+ "Pussy",
+ "Stockings",
+ "Stockings Spread",
+ "Uniform",
+ "Uniform Fetish"
+ ],
+ "url": "https://www.pornpics.com/galleries/leggy-white-chick-riley-reid-strips-to-black-stockings-with-her-glasses-on-56822993/",
+ "folder": "20251106_2238_Riley Reid_Leggy_white_chick_Riley_Reid_strips_to_black_stockings_with_her_glasses_on",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2238_Riley Reid_Leggy_white_chick_Riley_Reid_strips_to_black_stockings_with_her_glasses_on/metadata.json",
+ "timestamp": "2025-11-06T22:38:03.922937+00:00"
+ },
+ {
+ "id": "20251106_2238",
+ "title": "Petite babe Riley Reid spreads legs for her lover & fucks in front of husband",
+ "models": [
+ "Ramon Nomar",
+ "Riley Reid"
+ ],
+ "tags": [
+ "All Over 40",
+ "Bikini Blowjob",
+ "Blowjob",
+ "Cheating Wife",
+ "Cowgirl",
+ "MILF",
+ "MILF Bikini",
+ "MILF Stockings",
+ "Mature",
+ "Petite",
+ "Petite Stockings",
+ "Pussy",
+ "Sexy MILF",
+ "Stockings",
+ "Wife Blowjob"
+ ],
+ "url": "https://www.pornpics.com/galleries/petite-babe-riley-reid-spreads-legs-for-her-lover-fucks-in-front-of-husband-51353894/",
+ "folder": "20251106_2238_Ramon Nomar_Riley Reid_Petite_babe_Riley_Reid_spreads_legs_for_her_lover___fucks_in_front_of_husband",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2238_Ramon Nomar_Riley Reid_Petite_babe_Riley_Reid_spreads_legs_for_her_lover___fucks_in_front_of_husband/metadata.json",
+ "timestamp": "2025-11-06T22:38:15.767635+00:00"
+ },
+ {
+ "id": "20251106_2238",
+ "title": "Petite teen girl Riley Reid gives her guy cake and a fuck for his birthday",
+ "models": [
+ "Damon Dice",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Ass",
+ "Brunette",
+ "Brunette Teen",
+ "Close Up Fuck",
+ "Cowgirl",
+ "Fucking",
+ "Hairy",
+ "Hairy Pussy Fuck",
+ "Hairy Teen Pussy",
+ "Hairy Teen Spreading",
+ "Handjob",
+ "Hardcore",
+ "Juicy Pussy",
+ "Meaty Pussy",
+ "Petite",
+ "Pussy",
+ "Teen",
+ "Teen Handjob"
+ ],
+ "url": "https://www.pornpics.com/galleries/petite-teen-girl-riley-reid-gives-her-guy-cake-and-a-fuck-for-his-birthday-43223033/",
+ "folder": "20251106_2238_Damon Dice_Riley Reid_Petite_teen_girl_Riley_Reid_gives_her_guy_cake_and_a_fuck_for_his_birthday",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2238_Damon Dice_Riley Reid_Petite_teen_girl_Riley_Reid_gives_her_guy_cake_and_a_fuck_for_his_birthday/metadata.json",
+ "timestamp": "2025-11-06T22:38:20.128109+00:00"
+ },
+ {
+ "id": "20251106_2258",
+ "title": "Elegant Angel Adriana Chechik, Aj Applegate, Anikka Albrite, Keisha Grey, Kleio",
+ "models": [
+ "Adriana Chechik",
+ "Aj Applegate",
+ "Anikka Albrite",
+ "Keisha Grey",
+ "Kleio Valentien",
+ "Riley Reid",
+ "Vicki Chase"
+ ],
+ "tags": [
+ "Anal",
+ "Anal Fetish",
+ "Ass",
+ "Doggystyle",
+ "Doggystyle Anal",
+ "Fucking",
+ "Interracial",
+ "Interracial Anal",
+ "Latina Anal",
+ "Lingerie",
+ "MILF",
+ "MILF Anal",
+ "MILF DP",
+ "Mature",
+ "Penetration",
+ "Petite",
+ "Petite Anal",
+ "Sexy Anal",
+ "Teen",
+ "Teen Anal"
+ ],
+ "url": "https://www.pornpics.com/galleries/elegant-angel-adriana-chechik-aj-applegate-anikka-albrite-keisha-grey-kleio-85123161/",
+ "folder": "20251106_2258_Adriana Chechik_Aj Applegate_Anikka Albrite_Keisha Grey_Kleio Valentien_Riley Reid_Vicki Chase_Elegant_Angel_Adriana_Chechik__Aj_Applegate__Anikka_Albrite__Keisha_Grey__Kleio",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Adriana Chechik_Aj Applegate_Anikka Albrite_Keisha Grey_Kleio Valentien_Riley Reid_Vicki Chase_Elegant_Angel_Adriana_Chechik__Aj_Applegate__Anikka_Albrite__Keisha_Grey__Kleio/metadata.json",
+ "timestamp": "2025-11-06T22:58:04.155758+00:00"
+ },
+ {
+ "id": "20251106_2258",
+ "title": "Sluts Riley Reid & Aubrey Kate show off their big butts & give a double BJ",
+ "models": [
+ "Aubrey Kate",
+ "Riley Reid",
+ "Sebastian Keys"
+ ],
+ "tags": [
+ "Ass",
+ "Blonde",
+ "Blonde Shemale",
+ "Blowjob",
+ "Lesbian",
+ "Shemale Ass",
+ "Shemale Fucks Female",
+ "Shemale Fucks Girl",
+ "Shemale Lesbian",
+ "Shemale On Female",
+ "Shemale Pantyhose",
+ "Shemale Threesome",
+ "Threesome"
+ ],
+ "url": "https://www.pornpics.com/galleries/sluts-riley-reid-aubrey-kate-show-off-their-big-butts-give-a-double-bj-76348062/",
+ "folder": "20251106_2258_Aubrey Kate_Riley Reid_Sebastian Keys_Sluts_Riley_Reid___Aubrey_Kate_show_off_their_big_butts___give_a_double_BJ",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Aubrey Kate_Riley Reid_Sebastian Keys_Sluts_Riley_Reid___Aubrey_Kate_show_off_their_big_butts___give_a_double_BJ/metadata.json",
+ "timestamp": "2025-11-06T22:58:13.317125+00:00"
+ },
+ {
+ "id": "20251106_2258",
+ "title": "Erotic teen beauty Riley Reid takes a hard cock in sexy doggystyle fucking",
+ "models": [
+ "Riley Reid",
+ "Van Wylde"
+ ],
+ "tags": [
+ "Ass",
+ "Best Pussy",
+ "Big Tits",
+ "Blindfold Surprise",
+ "Cum On Pussy",
+ "Cum On Stockings",
+ "Cumshot",
+ "Doggystyle",
+ "Footjob",
+ "Fucking",
+ "Hairy",
+ "Hardcore",
+ "Natural",
+ "Natural Look",
+ "Pussy",
+ "Stockings",
+ "Teen",
+ "Teen Footjob",
+ "Teen Natural Tits",
+ "Teen Stockings",
+ "Tight Ass"
+ ],
+ "url": "https://www.pornpics.com/galleries/erotic-teen-beauty-riley-reid-takes-a-hard-cock-in-sexy-doggystyle-fucking-29035213/",
+ "folder": "20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Riley Reid_Van Wylde_Erotic_teen_beauty_Riley_Reid_takes_a_hard_cock_in_sexy_doggystyle_fucking/metadata.json",
+ "timestamp": "2025-11-06T22:58:16.191548+00:00"
+ },
+ {
+ "id": "20251106_2258",
+ "title": "Cheerleader Riley Reid shows her tiny tits before riding a pussy-wrecking dick",
+ "models": [
+ "Erik Everhard",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Big Tits",
+ "Blowjob",
+ "Cowgirl",
+ "Fucking",
+ "Hardcore",
+ "Horny",
+ "Pornstar",
+ "Pussy",
+ "Pussy Fuck",
+ "Riding",
+ "School Uniform",
+ "Slut",
+ "Sneakers",
+ "Uniform",
+ "Uniform Fetish"
+ ],
+ "url": "https://www.pornpics.com/galleries/cheerleader-riley-reid-shows-her-tiny-tits-before-riding-a-pussywrecking-dick-41471787/",
+ "folder": "20251106_2258_Erik Everhard_Riley Reid_Cheerleader_Riley_Reid_shows_her_tiny_tits_before_riding_a_pussy-wrecking_dick",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Erik Everhard_Riley Reid_Cheerleader_Riley_Reid_shows_her_tiny_tits_before_riding_a_pussy-wrecking_dick/metadata.json",
+ "timestamp": "2025-11-06T22:58:21.023626+00:00"
+ },
+ {
+ "id": "20251106_2258",
+ "title": "Lesbian girls Riley Reid and Melissa Moore lick and finger fuck each other",
+ "models": [
+ "Melissa Moore",
+ "Riley Reid"
+ ],
+ "tags": [
+ "Brunette",
+ "Fucking",
+ "Hairy",
+ "Lesbian",
+ "Oral",
+ "Pornstar",
+ "Pussy",
+ "Sexy Latina",
+ "Teen",
+ "Teen Lesbian"
+ ],
+ "url": "https://www.pornpics.com/galleries/lesbian-girls-riley-reid-and-melissa-moore-lick-and-finger-fuck-each-other-13944363/",
+ "folder": "20251106_2258_Melissa Moore_Riley Reid_Lesbian_girls_Riley_Reid_and_Melissa_Moore_lick_and_finger_fuck_each_other",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Melissa Moore_Riley Reid_Lesbian_girls_Riley_Reid_and_Melissa_Moore_lick_and_finger_fuck_each_other/metadata.json",
+ "timestamp": "2025-11-06T22:58:26.176526+00:00"
+ },
+ {
+ "id": "20251106_2258",
+ "title": "Naked blonde chick fist fucks herself to strong orgasmic contractions",
+ "models": [
+ "Riley Reid"
+ ],
+ "tags": [
+ "Amateur",
+ "Beautiful",
+ "Blonde",
+ "Glamour",
+ "Hot Naked Women",
+ "Model",
+ "Pussy",
+ "Solo"
+ ],
+ "url": "https://www.pornpics.com/galleries/naked-blonde-chick-fist-fucks-herself-to-strong-orgasmic-contractions-17634641/",
+ "folder": "20251106_2258_Riley Reid_Naked_blonde_chick_fist_fucks_herself_to_strong_orgasmic_contractions",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2258_Riley Reid_Naked_blonde_chick_fist_fucks_herself_to_strong_orgasmic_contractions/metadata.json",
+ "timestamp": "2025-11-06T22:58:37.951805+00:00"
+ },
+ {
+ "id": "20251106_2335",
+ "title": "MILFed starring Paige Owens, Steve Holmes Hot Porn Pics",
+ "models": [
+ "Paige Owens",
+ "Steve Holmes"
+ ],
+ "tags": [
+ "Beautiful",
+ "Beautiful MILF",
+ "Bride",
+ "Brunette",
+ "Cheating Wife",
+ "Fetish",
+ "MILF",
+ "MILF Pussy",
+ "Mature",
+ "Pussy",
+ "Sucking Cock",
+ "Teen",
+ "Teen Stepdaughter"
+ ],
+ "url": "https://www.pornpics.com/galleries/milfed-starring-paige-owens-steve-holmes-hot-porn-pics-65759020/",
+ "folder": "20251106_2335_Paige Owens_Steve Holmes_MILFed_starring_Paige_Owens__Steve_Holmes_Hot_Porn_Pics",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251106_2335_Paige Owens_Steve Holmes_MILFed_starring_Paige_Owens__Steve_Holmes_Hot_Porn_Pics/metadata.json",
+ "timestamp": "2025-11-06T23:35:19.445466+00:00"
+ },
+ {
+ "id": "20251107_2029",
+ "title": "Young redhead Alex Tanner shows her petite body while completely naked",
+ "models": [
+ "Alex Tanner"
+ ],
+ "tags": [
+ "Amateur",
+ "Amateur College",
+ "Cute Redhead",
+ "Ginger Teen",
+ "Kinky",
+ "Natural",
+ "Natural Look",
+ "Natural Redhead",
+ "Pale Redhead",
+ "Petite",
+ "Pussy",
+ "Redhead",
+ "Redhead Freckles",
+ "Redhead Teen",
+ "Teen"
+ ],
+ "url": "https://www.pornpics.com/galleries/young-redhead-alex-tanner-shows-her-petite-body-while-completely-naked-63489082/",
+ "folder": "20251107_2029_Alex Tanner_Young_redhead_Alex_Tanner_shows_her_petite_body_while_completely_naked",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2029_Alex Tanner_Young_redhead_Alex_Tanner_shows_her_petite_body_while_completely_naked/metadata.json",
+ "timestamp": "2025-11-07T20:29:27.087119+00:00"
+ },
+ {
+ "id": "20251107_2031",
+ "title": "Young redhead Alex Tanner demonstrating her perfectly smooth pussy",
+ "models": [
+ "Alex Tanner"
+ ],
+ "tags": [
+ "Ass",
+ "Big Ass Redhead",
+ "Big Tits",
+ "High Heels",
+ "Panties",
+ "Pussy",
+ "Redhead",
+ "Redhead Ass",
+ "Redhead Teen",
+ "Sexy Redhead",
+ "Shaved",
+ "Shorts",
+ "Teen",
+ "Tight Shorts"
+ ],
+ "url": "https://www.pornpics.com/galleries/young-redhead-alex-tanner-demonstrating-her-perfectly-smooth-pussy-26775799/",
+ "folder": "20251107_2031_Alex Tanner_Young_redhead_Alex_Tanner_demonstrating_her_perfectly_smooth_pussy",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2031_Alex Tanner_Young_redhead_Alex_Tanner_demonstrating_her_perfectly_smooth_pussy/metadata.json",
+ "timestamp": "2025-11-07T20:31:21.604057+00:00"
+ },
+ {
+ "id": "20251107_2031",
+ "title": "Blonde party girl flashes nude upskirt & gets cum on face in hot orgy",
+ "models": [
+ "Esmi Lee",
+ "Brooke Wylde",
+ "Gianna Nicole",
+ "Tiffany Taylor",
+ "Nikki Lima",
+ "Sasha Summers",
+ "Alex Tanner",
+ "J Mac",
+ "Sabrina Banks",
+ "Dani Desire"
+ ],
+ "tags": [
+ "Ass",
+ "Blonde",
+ "Cumshot",
+ "Doggystyle",
+ "Fucking",
+ "Hardcore",
+ "Indian Fuck",
+ "MILF",
+ "MILF Hardcore",
+ "Mature",
+ "Mature Orgy",
+ "Orgy",
+ "Party",
+ "Redhead",
+ "Redhead Doggystyle",
+ "Redhead Fuck",
+ "Redhead MILF",
+ "Skinny",
+ "Skinny Mature Fuck",
+ "Teen",
+ "Teen Orgy"
+ ],
+ "url": "https://www.pornpics.com/galleries/blonde-party-girl-flashes-nude-upskirt-gets-cum-on-face-in-hot-orgy-17122410/",
+ "folder": "20251107_2031_Esmi Lee_Brooke Wylde_Gianna Nicole_Tiffany Taylor_Nikki Lima_Sasha Summers_Alex Tanner_J Mac_Sabrina Banks_Dani Desire_Blonde_party_girl_flashes_nude_upskirt___gets_cum_on_face_in_hot_orgy",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2031_Esmi Lee_Brooke Wylde_Gianna Nicole_Tiffany Taylor_Nikki Lima_Sasha Summers_Alex Tanner_J Mac_Sabrina Banks_Dani Desire_Blonde_party_girl_flashes_nude_upskirt___gets_cum_on_face_in_hot_orgy/metadata.json",
+ "timestamp": "2025-11-07T20:31:35.064524+00:00"
+ },
+ {
+ "id": "20251107_2031",
+ "title": "Mr POV performed by Alex Tanner XXX Photos",
+ "models": [
+ "Alex Tanner"
+ ],
+ "tags": [
+ "Big Pussy",
+ "Big Tits",
+ "Blowjob",
+ "Curvy",
+ "Curvy Petite",
+ "Handjob",
+ "Legs Up Missionary",
+ "Missionary",
+ "Natural",
+ "Natural Look",
+ "POV",
+ "POV Blowjob",
+ "Petite",
+ "Pornstar",
+ "Pussy",
+ "Slut",
+ "Sucking Cock"
+ ],
+ "url": "https://www.pornpics.com/galleries/mr-pov-performed-by-alex-tanner-xxx-photos-99243967/",
+ "folder": "20251107_2031_Alex Tanner_Mr_POV_performed_by_Alex_Tanner_XXX_Photos",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2031_Alex Tanner_Mr_POV_performed_by_Alex_Tanner_XXX_Photos/metadata.json",
+ "timestamp": "2025-11-07T20:31:48.239211+00:00"
+ },
+ {
+ "id": "20251107_2037",
+ "title": "OnlyFans Luv Hanna Zuki Luv Hanna Zuki",
+ "models": [],
+ "tags": [
+ "Amateur",
+ "Asian Lingerie",
+ "Asian Model",
+ "Asian Teen",
+ "Ass",
+ "Beautiful",
+ "Beautiful Asian",
+ "Big Ass Teen",
+ "Brunette",
+ "Brunette Teen",
+ "Lingerie",
+ "Model",
+ "Perfect",
+ "Perfect Ass",
+ "Perfect Body",
+ "Perfect Teen Body",
+ "Teen"
+ ],
+ "url": "https://www.pornpics.com/galleries/onlyfans-luv-hanna-zuki-luv-hanna-zuki-52529080/",
+ "folder": "20251107_2037_Unknown_Model_OnlyFans_Luv_Hanna_Zuki_Luv_Hanna_Zuki",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2037_Unknown_Model_OnlyFans_Luv_Hanna_Zuki_Luv_Hanna_Zuki/metadata.json",
+ "timestamp": "2025-11-07T20:37:13.826670+00:00"
+ },
+ {
+ "id": "20251107_2037",
+ "title": "Hot babe in a sinful bikini Jayden Lee blows a big rod & gets fucked on a sofa",
+ "models": [
+ "Jayden Lee",
+ "Marcus London"
+ ],
+ "tags": [
+ "Asian Blowjob",
+ "Asian Cumshot",
+ "Asian Fuck",
+ "Asian Hardcore",
+ "Asian Lingerie",
+ "Asian Model",
+ "Big Tits",
+ "Blowjob",
+ "Brunette",
+ "Couch",
+ "Cumshot",
+ "Fucking",
+ "Hardcore",
+ "Lingerie",
+ "Model",
+ "Model Fuck",
+ "Panties",
+ "Pussy",
+ "Skinny",
+ "Teen"
+ ],
+ "url": "https://www.pornpics.com/galleries/hot-babe-in-a-sinful-bikini-jayden-lee-blows-a-big-rod-gets-fucked-on-a-sofa-16020943/",
+ "folder": "20251107_2037_Jayden Lee_Marcus London_Hot_babe_in_a_sinful_bikini_Jayden_Lee_blows_a_big_rod___gets_fucked_on_a_sofa",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2037_Jayden Lee_Marcus London_Hot_babe_in_a_sinful_bikini_Jayden_Lee_blows_a_big_rod___gets_fucked_on_a_sofa/metadata.json",
+ "timestamp": "2025-11-07T20:37:31.031921+00:00"
+ },
+ {
+ "id": "20251107_2037",
+ "title": "Evil Angel featuring Aaron Rock, Alexa Flexy, Mia Split Naked Images",
+ "models": [
+ "Mia Split",
+ "Aaron Rock",
+ "Alexa Flexy"
+ ],
+ "tags": [
+ "Amateur",
+ "Anal",
+ "Anal Fetish",
+ "Ass",
+ "Big Tits",
+ "Black And White",
+ "Hot Naked Women",
+ "Interracial",
+ "Interracial Anal",
+ "Interracial Threesome",
+ "Natural",
+ "Natural Look",
+ "Petite",
+ "Pussy",
+ "Teen",
+ "Threesome"
+ ],
+ "url": "https://www.pornpics.com/galleries/evil-angel-featuring-aaron-rock-alexa-flexy-mia-split-naked-images-71699035/",
+ "folder": "20251107_2037_Mia Split_Aaron Rock_Alexa Flexy_Evil_Angel_featuring_Aaron_Rock__Alexa_Flexy__Mia_Split_Naked_Images",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2037_Mia Split_Aaron Rock_Alexa Flexy_Evil_Angel_featuring_Aaron_Rock__Alexa_Flexy__Mia_Split_Naked_Images/metadata.json",
+ "timestamp": "2025-11-07T20:37:59.865361+00:00"
+ },
+ {
+ "id": "20251107_2319",
+ "title": "Sexy mature with big tits Alora Jaymes gives head and gets rammed",
+ "models": [
+ "Alora Jaymes"
+ ],
+ "tags": [
+ "Amateur",
+ "Amateur Blowjob",
+ "Amateur Deepthroat",
+ "Ass",
+ "Beautiful",
+ "Beautiful MILF",
+ "Big Tits",
+ "Blowjob",
+ "Brunette",
+ "Brunette MILF",
+ "Fingering",
+ "Fingering Panties",
+ "Fucking",
+ "MILF",
+ "MILF Deepthroat",
+ "MILF Sucking Cock",
+ "Mature",
+ "Natural",
+ "Natural Look",
+ "Panties",
+ "Skinny",
+ "Skinny MILF Fuck"
+ ],
+ "url": "https://www.pornpics.com/galleries/sexy-mature-with-big-tits-alora-jaymes-gives-head-and-gets-rammed-54684463/",
+ "folder": "20251107_2319_Alora Jaymes_Sexy_mature_with_big_tits_Alora_Jaymes_gives_head_and_gets_rammed",
+ "metadata_path": "/home/stu/Projects/PD/Goondex/Galleries/20251107_2319_Alora Jaymes_Sexy_mature_with_big_tits_Alora_Jaymes_gives_head_and_gets_rammed/metadata.json",
+ "timestamp": "2025-11-07T23:19:54.823362+00:00"
}
]
\ No newline at end of file
diff --git a/VERSION b/VERSION
index b2ceef6..724c927 100644
--- a/VERSION
+++ b/VERSION
@@ -1 +1,2 @@
-v0.3.5-r1
+v0.3.5-r2
+
diff --git a/assets/logo/GOONDEX_logo.png b/assets/logo/GOONDEX_logo.png
new file mode 100644
index 0000000..c9b1a40
Binary files /dev/null and b/assets/logo/GOONDEX_logo.png differ
diff --git a/assets/logo/GOONDEX_logo.svg b/assets/logo/GOONDEX_logo.svg
index dfb7360..1bf3bb8 100644
--- a/assets/logo/GOONDEX_logo.svg
+++ b/assets/logo/GOONDEX_logo.svg
@@ -23,15 +23,32 @@
inkscape:pagecheckerboard="0"
inkscape:deskcolor="#505050"
inkscape:document-units="px"
- inkscape:zoom="1.5483025"
- inkscape:cx="269.00429"
- inkscape:cy="227.02282"
+ inkscape:zoom="2.1896304"
+ inkscape:cx="898.55348"
+ inkscape:cy="158.70258"
inkscape:window-width="1920"
- inkscape:window-height="1080"
+ inkscape:window-height="1048"
inkscape:window-x="0"
inkscape:window-y="0"
inkscape:window-maximized="1"
- inkscape:current-layer="layer1" />
+ inkscape:current-layer="svg1">
+
+
+
+
+
+
+
+
+
diff --git a/assets/logo/GOONDEX_logo_dark.png b/assets/logo/GOONDEX_logo_dark.png
new file mode 100644
index 0000000..a286bba
Binary files /dev/null and b/assets/logo/GOONDEX_logo_dark.png differ
diff --git a/assets/logo/GOONDEX_logo_light.png b/assets/logo/GOONDEX_logo_light.png
new file mode 100644
index 0000000..f29d3a1
Binary files /dev/null and b/assets/logo/GOONDEX_logo_light.png differ
diff --git a/data/faces/alexis_texas/thumbnail.jpg b/data/faces/alexis_texas/thumbnail.jpg
new file mode 100644
index 0000000..7f3639e
Binary files /dev/null and b/data/faces/alexis_texas/thumbnail.jpg differ
diff --git a/data/faces/faye_reagan/thumbnail.jpg b/data/faces/faye_reagan/thumbnail.jpg
new file mode 100644
index 0000000..8925000
Binary files /dev/null and b/data/faces/faye_reagan/thumbnail.jpg differ
diff --git a/data/faces/j_mac/thumbnail.jpg b/data/faces/j_mac/thumbnail.jpg
new file mode 100644
index 0000000..471f58d
Binary files /dev/null and b/data/faces/j_mac/thumbnail.jpg differ
diff --git a/data/faces/johnny_sins/thumbnail.jpg b/data/faces/johnny_sins/thumbnail.jpg
new file mode 100644
index 0000000..f6db50e
Binary files /dev/null and b/data/faces/johnny_sins/thumbnail.jpg differ
diff --git a/data/faces/madison_scott/thumbnail.jpg b/data/faces/madison_scott/thumbnail.jpg
new file mode 100644
index 0000000..6ede65d
Binary files /dev/null and b/data/faces/madison_scott/thumbnail.jpg differ
diff --git a/data/faces/mia_split/thumbnail.jpg b/data/faces/mia_split/thumbnail.jpg
new file mode 100644
index 0000000..c782507
Binary files /dev/null and b/data/faces/mia_split/thumbnail.jpg differ
diff --git a/data/faces/monique_alexander/thumbnail.jpg b/data/faces/monique_alexander/thumbnail.jpg
new file mode 100644
index 0000000..b934881
Binary files /dev/null and b/data/faces/monique_alexander/thumbnail.jpg differ
diff --git a/data/faces/riley_reid/thumbnail.jpg b/data/faces/riley_reid/thumbnail.jpg
new file mode 100644
index 0000000..28699c6
Binary files /dev/null and b/data/faces/riley_reid/thumbnail.jpg differ
diff --git a/data/faces/sasha_grey/thumbnail.jpg b/data/faces/sasha_grey/thumbnail.jpg
new file mode 100644
index 0000000..e381045
Binary files /dev/null and b/data/faces/sasha_grey/thumbnail.jpg differ
diff --git a/data/performers/01638222-6708-4698-a6c1-30b8c80eb09a/performer.json b/data/performers/01638222-6708-4698-a6c1-30b8c80eb09a/performer.json
new file mode 100644
index 0000000..2b0ec84
--- /dev/null
+++ b/data/performers/01638222-6708-4698-a6c1-30b8c80eb09a/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "01638222-6708-4698-a6c1-30b8c80eb09a",
+ "name": "Miss Korrine",
+ "url": "https://theporndb.net/performer/01638222-6708-4698-a6c1-30b8c80eb09a",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.491295"
+}
\ No newline at end of file
diff --git a/data/performers/0315dae6-9643-4265-ac66-0f2e47264bd3/performer.json b/data/performers/0315dae6-9643-4265-ac66-0f2e47264bd3/performer.json
new file mode 100644
index 0000000..dcc05c8
--- /dev/null
+++ b/data/performers/0315dae6-9643-4265-ac66-0f2e47264bd3/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "0315dae6-9643-4265-ac66-0f2e47264bd3",
+ "name": "Madame Beatrix",
+ "url": "https://theporndb.net/performer/0315dae6-9643-4265-ac66-0f2e47264bd3",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.751738"
+}
\ No newline at end of file
diff --git a/data/performers/064f0295-3c36-48c1-89ea-76fa547f201e/performer.json b/data/performers/064f0295-3c36-48c1-89ea-76fa547f201e/performer.json
new file mode 100644
index 0000000..9a3f2ea
--- /dev/null
+++ b/data/performers/064f0295-3c36-48c1-89ea-76fa547f201e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "064f0295-3c36-48c1-89ea-76fa547f201e",
+ "name": "Rae Voltage",
+ "url": "https://theporndb.net/performer/064f0295-3c36-48c1-89ea-76fa547f201e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.591389"
+}
\ No newline at end of file
diff --git a/data/performers/0664972e-8f2c-43f8-95ff-1ac01681420d/performer.json b/data/performers/0664972e-8f2c-43f8-95ff-1ac01681420d/performer.json
new file mode 100644
index 0000000..6899ab0
--- /dev/null
+++ b/data/performers/0664972e-8f2c-43f8-95ff-1ac01681420d/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "0664972e-8f2c-43f8-95ff-1ac01681420d",
+ "name": "Maddie Wren",
+ "url": "https://theporndb.net/performer/0664972e-8f2c-43f8-95ff-1ac01681420d",
+ "aliases": "[\"Maddie\", \"Bratty Maddie\"]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:38.019503"
+}
\ No newline at end of file
diff --git a/data/performers/0912d9fa-e824-414a-917c-29165ff39f7e/performer.json b/data/performers/0912d9fa-e824-414a-917c-29165ff39f7e/performer.json
new file mode 100644
index 0000000..cd7f741
--- /dev/null
+++ b/data/performers/0912d9fa-e824-414a-917c-29165ff39f7e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "0912d9fa-e824-414a-917c-29165ff39f7e",
+ "name": "VixXxen",
+ "url": "https://theporndb.net/performer/0912d9fa-e824-414a-917c-29165ff39f7e",
+ "aliases": "[\"Vixxxen\"]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:36.506861"
+}
\ No newline at end of file
diff --git a/data/performers/09d40f92-e294-4fe1-ab99-394ce50f762e/performer.json b/data/performers/09d40f92-e294-4fe1-ab99-394ce50f762e/performer.json
new file mode 100644
index 0000000..09236af
--- /dev/null
+++ b/data/performers/09d40f92-e294-4fe1-ab99-394ce50f762e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "09d40f92-e294-4fe1-ab99-394ce50f762e",
+ "name": "Cheri Houston",
+ "url": "https://theporndb.net/performer/09d40f92-e294-4fe1-ab99-394ce50f762e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.960143"
+}
\ No newline at end of file
diff --git a/data/performers/0bbdc743-cd03-4588-999f-7b81bef05f3c/performer.json b/data/performers/0bbdc743-cd03-4588-999f-7b81bef05f3c/performer.json
new file mode 100644
index 0000000..15b2d18
--- /dev/null
+++ b/data/performers/0bbdc743-cd03-4588-999f-7b81bef05f3c/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "0bbdc743-cd03-4588-999f-7b81bef05f3c",
+ "name": "Abbyabby Marieabby Paradise",
+ "url": "https://theporndb.net/performer/0bbdc743-cd03-4588-999f-7b81bef05f3c",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.707821"
+}
\ No newline at end of file
diff --git a/data/performers/145ac6dd-0c84-49d7-82f7-42ba092e4ea9/performer.json b/data/performers/145ac6dd-0c84-49d7-82f7-42ba092e4ea9/performer.json
new file mode 100644
index 0000000..71fb79a
--- /dev/null
+++ b/data/performers/145ac6dd-0c84-49d7-82f7-42ba092e4ea9/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "145ac6dd-0c84-49d7-82f7-42ba092e4ea9",
+ "name": "Julie Cats",
+ "url": "https://theporndb.net/performer/145ac6dd-0c84-49d7-82f7-42ba092e4ea9",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.675382"
+}
\ No newline at end of file
diff --git a/data/performers/15efbebe-10c1-4e99-b863-1780551d2fb1/performer.json b/data/performers/15efbebe-10c1-4e99-b863-1780551d2fb1/performer.json
new file mode 100644
index 0000000..cae27e9
--- /dev/null
+++ b/data/performers/15efbebe-10c1-4e99-b863-1780551d2fb1/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "15efbebe-10c1-4e99-b863-1780551d2fb1",
+ "name": "Princess Chanel",
+ "url": "https://theporndb.net/performer/15efbebe-10c1-4e99-b863-1780551d2fb1",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.921675"
+}
\ No newline at end of file
diff --git a/data/performers/1f0a7f0d-297d-4731-8853-9d44dd31f3a4/performer.json b/data/performers/1f0a7f0d-297d-4731-8853-9d44dd31f3a4/performer.json
new file mode 100644
index 0000000..f8cce58
--- /dev/null
+++ b/data/performers/1f0a7f0d-297d-4731-8853-9d44dd31f3a4/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "1f0a7f0d-297d-4731-8853-9d44dd31f3a4",
+ "name": "Guido Kirsch",
+ "url": "https://theporndb.net/performer/1f0a7f0d-297d-4731-8853-9d44dd31f3a4",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:27.023063"
+}
\ No newline at end of file
diff --git a/data/performers/21161316-f25e-4941-9d34-f0aaa118b4ad/performer.json b/data/performers/21161316-f25e-4941-9d34-f0aaa118b4ad/performer.json
new file mode 100644
index 0000000..50544ea
--- /dev/null
+++ b/data/performers/21161316-f25e-4941-9d34-f0aaa118b4ad/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "21161316-f25e-4941-9d34-f0aaa118b4ad",
+ "name": "Lexie Lowe",
+ "url": "https://theporndb.net/performer/21161316-f25e-4941-9d34-f0aaa118b4ad",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.658660"
+}
\ No newline at end of file
diff --git a/data/performers/21757d89-4b0a-4120-a07b-692f5649eb07/performer.json b/data/performers/21757d89-4b0a-4120-a07b-692f5649eb07/performer.json
new file mode 100644
index 0000000..f22ed04
--- /dev/null
+++ b/data/performers/21757d89-4b0a-4120-a07b-692f5649eb07/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "21757d89-4b0a-4120-a07b-692f5649eb07",
+ "name": "Alison Sweet",
+ "url": "https://theporndb.net/performer/21757d89-4b0a-4120-a07b-692f5649eb07",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.200661"
+}
\ No newline at end of file
diff --git a/data/performers/26a117de-578d-4533-836f-6f461f675393/performer.json b/data/performers/26a117de-578d-4533-836f-6f461f675393/performer.json
new file mode 100644
index 0000000..6adb764
--- /dev/null
+++ b/data/performers/26a117de-578d-4533-836f-6f461f675393/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "26a117de-578d-4533-836f-6f461f675393",
+ "name": "Poppy Prynne",
+ "url": "https://theporndb.net/performer/26a117de-578d-4533-836f-6f461f675393",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.872031"
+}
\ No newline at end of file
diff --git a/data/performers/29fbbbb1-f967-4b54-a5ee-60eaf8b505f9/performer.json b/data/performers/29fbbbb1-f967-4b54-a5ee-60eaf8b505f9/performer.json
new file mode 100644
index 0000000..730525f
--- /dev/null
+++ b/data/performers/29fbbbb1-f967-4b54-a5ee-60eaf8b505f9/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "29fbbbb1-f967-4b54-a5ee-60eaf8b505f9",
+ "name": "Nina",
+ "url": "https://theporndb.net/performer/29fbbbb1-f967-4b54-a5ee-60eaf8b505f9",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.507347"
+}
\ No newline at end of file
diff --git a/data/performers/2c9d762f-5360-4471-8ef7-ce5e6158c59e/performer.json b/data/performers/2c9d762f-5360-4471-8ef7-ce5e6158c59e/performer.json
new file mode 100644
index 0000000..6008b4c
--- /dev/null
+++ b/data/performers/2c9d762f-5360-4471-8ef7-ce5e6158c59e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "2c9d762f-5360-4471-8ef7-ce5e6158c59e",
+ "name": "Heaven",
+ "url": "https://theporndb.net/performer/2c9d762f-5360-4471-8ef7-ce5e6158c59e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:27.411923"
+}
\ No newline at end of file
diff --git a/data/performers/2f700de5-b525-4dbe-b8e1-d7e066089e7e/performer.json b/data/performers/2f700de5-b525-4dbe-b8e1-d7e066089e7e/performer.json
new file mode 100644
index 0000000..435e324
--- /dev/null
+++ b/data/performers/2f700de5-b525-4dbe-b8e1-d7e066089e7e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "2f700de5-b525-4dbe-b8e1-d7e066089e7e",
+ "name": "Ziva Ziva Fey",
+ "url": "https://theporndb.net/performer/2f700de5-b525-4dbe-b8e1-d7e066089e7e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.771331"
+}
\ No newline at end of file
diff --git a/data/performers/2f89fd04-e81d-4430-8d26-f75eb4ee65e0/performer.json b/data/performers/2f89fd04-e81d-4430-8d26-f75eb4ee65e0/performer.json
new file mode 100644
index 0000000..11be189
--- /dev/null
+++ b/data/performers/2f89fd04-e81d-4430-8d26-f75eb4ee65e0/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "2f89fd04-e81d-4430-8d26-f75eb4ee65e0",
+ "name": "Lucas Caruso",
+ "url": "https://theporndb.net/performer/2f89fd04-e81d-4430-8d26-f75eb4ee65e0",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:27.043638"
+}
\ No newline at end of file
diff --git a/data/performers/32cbf56e-9443-44c2-b53f-1c0dc5e0701c/performer.json b/data/performers/32cbf56e-9443-44c2-b53f-1c0dc5e0701c/performer.json
new file mode 100644
index 0000000..3240857
--- /dev/null
+++ b/data/performers/32cbf56e-9443-44c2-b53f-1c0dc5e0701c/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "32cbf56e-9443-44c2-b53f-1c0dc5e0701c",
+ "name": "Kako Crunchie",
+ "url": "https://theporndb.net/performer/32cbf56e-9443-44c2-b53f-1c0dc5e0701c",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.034761"
+}
\ No newline at end of file
diff --git a/data/performers/337a4c2f-2622-48d8-a06d-62a6b1dcd561/performer.json b/data/performers/337a4c2f-2622-48d8-a06d-62a6b1dcd561/performer.json
new file mode 100644
index 0000000..052bb67
--- /dev/null
+++ b/data/performers/337a4c2f-2622-48d8-a06d-62a6b1dcd561/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "337a4c2f-2622-48d8-a06d-62a6b1dcd561",
+ "name": "Teen Dragon",
+ "url": "https://theporndb.net/performer/337a4c2f-2622-48d8-a06d-62a6b1dcd561",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:37.500064"
+}
\ No newline at end of file
diff --git a/data/performers/345c71e2-cf3a-498e-a3ca-9dfa965c498d/performer.json b/data/performers/345c71e2-cf3a-498e-a3ca-9dfa965c498d/performer.json
new file mode 100644
index 0000000..daa9019
--- /dev/null
+++ b/data/performers/345c71e2-cf3a-498e-a3ca-9dfa965c498d/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "345c71e2-cf3a-498e-a3ca-9dfa965c498d",
+ "name": "Isis Nice",
+ "url": "https://theporndb.net/performer/345c71e2-cf3a-498e-a3ca-9dfa965c498d",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.327930"
+}
\ No newline at end of file
diff --git a/data/performers/34ac207a-5de9-4129-8f3e-2bf29175a320/performer.json b/data/performers/34ac207a-5de9-4129-8f3e-2bf29175a320/performer.json
new file mode 100644
index 0000000..647a35f
--- /dev/null
+++ b/data/performers/34ac207a-5de9-4129-8f3e-2bf29175a320/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "34ac207a-5de9-4129-8f3e-2bf29175a320",
+ "name": "Blackate",
+ "url": "https://theporndb.net/performer/34ac207a-5de9-4129-8f3e-2bf29175a320",
+ "aliases": "[\"Kittykate69\"]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.149715"
+}
\ No newline at end of file
diff --git a/data/performers/34acd6b6-b1f7-485e-ab02-e4c3a9a9b79a/performer.json b/data/performers/34acd6b6-b1f7-485e-ab02-e4c3a9a9b79a/performer.json
new file mode 100644
index 0000000..2a2b09b
--- /dev/null
+++ b/data/performers/34acd6b6-b1f7-485e-ab02-e4c3a9a9b79a/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "34acd6b6-b1f7-485e-ab02-e4c3a9a9b79a",
+ "name": "Four A",
+ "url": "https://theporndb.net/performer/34acd6b6-b1f7-485e-ab02-e4c3a9a9b79a",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.607766"
+}
\ No newline at end of file
diff --git a/data/performers/394436d7-a063-4e06-890e-e0dacad8c8b7/performer.json b/data/performers/394436d7-a063-4e06-890e-e0dacad8c8b7/performer.json
new file mode 100644
index 0000000..94883b1
--- /dev/null
+++ b/data/performers/394436d7-a063-4e06-890e-e0dacad8c8b7/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "394436d7-a063-4e06-890e-e0dacad8c8b7",
+ "name": "Ludo Desire Room",
+ "url": "https://theporndb.net/performer/394436d7-a063-4e06-890e-e0dacad8c8b7",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:28.675640"
+}
\ No newline at end of file
diff --git a/data/performers/397688c6-f37b-43c1-9416-16cb0aa5ee45/performer.json b/data/performers/397688c6-f37b-43c1-9416-16cb0aa5ee45/performer.json
new file mode 100644
index 0000000..3131ad4
--- /dev/null
+++ b/data/performers/397688c6-f37b-43c1-9416-16cb0aa5ee45/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "397688c6-f37b-43c1-9416-16cb0aa5ee45",
+ "name": "Maria El Aouad",
+ "url": "https://theporndb.net/performer/397688c6-f37b-43c1-9416-16cb0aa5ee45",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:27.085225"
+}
\ No newline at end of file
diff --git a/data/performers/39783e16-c611-4ae5-b02d-fd2f9c9ed54b/performer.json b/data/performers/39783e16-c611-4ae5-b02d-fd2f9c9ed54b/performer.json
new file mode 100644
index 0000000..0c72b0d
--- /dev/null
+++ b/data/performers/39783e16-c611-4ae5-b02d-fd2f9c9ed54b/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "39783e16-c611-4ae5-b02d-fd2f9c9ed54b",
+ "name": "Jolie Desire Room",
+ "url": "https://theporndb.net/performer/39783e16-c611-4ae5-b02d-fd2f9c9ed54b",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:29.201353"
+}
\ No newline at end of file
diff --git a/data/performers/3cdad92a-bc0e-49a5-868e-3a41fd712aa6/performer.json b/data/performers/3cdad92a-bc0e-49a5-868e-3a41fd712aa6/performer.json
new file mode 100644
index 0000000..09d8d0e
--- /dev/null
+++ b/data/performers/3cdad92a-bc0e-49a5-868e-3a41fd712aa6/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "3cdad92a-bc0e-49a5-868e-3a41fd712aa6",
+ "name": "Pepa Dicky",
+ "url": "https://theporndb.net/performer/3cdad92a-bc0e-49a5-868e-3a41fd712aa6",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.100208"
+}
\ No newline at end of file
diff --git a/data/performers/3d33f525-2711-408b-9e6d-528392fd9552/performer.json b/data/performers/3d33f525-2711-408b-9e6d-528392fd9552/performer.json
new file mode 100644
index 0000000..b2607c0
--- /dev/null
+++ b/data/performers/3d33f525-2711-408b-9e6d-528392fd9552/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "3d33f525-2711-408b-9e6d-528392fd9552",
+ "name": "V Silverss",
+ "url": "https://theporndb.net/performer/3d33f525-2711-408b-9e6d-528392fd9552",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:34.650948"
+}
\ No newline at end of file
diff --git a/data/performers/3d7c2897-8d8b-4f80-996c-0b145d5c1580/performer.json b/data/performers/3d7c2897-8d8b-4f80-996c-0b145d5c1580/performer.json
new file mode 100644
index 0000000..3980a6b
--- /dev/null
+++ b/data/performers/3d7c2897-8d8b-4f80-996c-0b145d5c1580/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "3d7c2897-8d8b-4f80-996c-0b145d5c1580",
+ "name": "Mike",
+ "url": "https://theporndb.net/performer/3d7c2897-8d8b-4f80-996c-0b145d5c1580",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:31.147237"
+}
\ No newline at end of file
diff --git a/data/performers/3ec91510-89b1-4f8a-b88b-013abfae59be/performer.json b/data/performers/3ec91510-89b1-4f8a-b88b-013abfae59be/performer.json
new file mode 100644
index 0000000..524dcee
--- /dev/null
+++ b/data/performers/3ec91510-89b1-4f8a-b88b-013abfae59be/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "3ec91510-89b1-4f8a-b88b-013abfae59be",
+ "name": "Camilo Cortes",
+ "url": "https://theporndb.net/performer/3ec91510-89b1-4f8a-b88b-013abfae59be",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:33.371732"
+}
\ No newline at end of file
diff --git a/data/performers/3f6ab31d-04a7-4557-be15-d55b0db8f5d1/performer.json b/data/performers/3f6ab31d-04a7-4557-be15-d55b0db8f5d1/performer.json
new file mode 100644
index 0000000..30a682c
--- /dev/null
+++ b/data/performers/3f6ab31d-04a7-4557-be15-d55b0db8f5d1/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "3f6ab31d-04a7-4557-be15-d55b0db8f5d1",
+ "name": "Richard Lotto",
+ "url": "https://theporndb.net/performer/3f6ab31d-04a7-4557-be15-d55b0db8f5d1",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.132836"
+}
\ No newline at end of file
diff --git a/data/performers/3fbb8994-94d9-4008-b79f-f43162a097a6/performer.json b/data/performers/3fbb8994-94d9-4008-b79f-f43162a097a6/performer.json
new file mode 100644
index 0000000..d31a9c9
--- /dev/null
+++ b/data/performers/3fbb8994-94d9-4008-b79f-f43162a097a6/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "3fbb8994-94d9-4008-b79f-f43162a097a6",
+ "name": "Nun B",
+ "url": "https://theporndb.net/performer/3fbb8994-94d9-4008-b79f-f43162a097a6",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.885917"
+}
\ No newline at end of file
diff --git a/data/performers/4141e782-6ece-44fe-8795-4b1d9ceb8929/performer.json b/data/performers/4141e782-6ece-44fe-8795-4b1d9ceb8929/performer.json
new file mode 100644
index 0000000..190f0b4
--- /dev/null
+++ b/data/performers/4141e782-6ece-44fe-8795-4b1d9ceb8929/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "4141e782-6ece-44fe-8795-4b1d9ceb8929",
+ "name": "Bankroll Barbiee",
+ "url": "https://theporndb.net/performer/4141e782-6ece-44fe-8795-4b1d9ceb8929",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.892314"
+}
\ No newline at end of file
diff --git a/data/performers/4157fed0-bbed-479f-bd0b-58f4e97fc5da/performer.json b/data/performers/4157fed0-bbed-479f-bd0b-58f4e97fc5da/performer.json
new file mode 100644
index 0000000..64d4622
--- /dev/null
+++ b/data/performers/4157fed0-bbed-479f-bd0b-58f4e97fc5da/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "4157fed0-bbed-479f-bd0b-58f4e97fc5da",
+ "name": "Carmel Monroe",
+ "url": "https://theporndb.net/performer/4157fed0-bbed-479f-bd0b-58f4e97fc5da",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:27.001710"
+}
\ No newline at end of file
diff --git a/data/performers/460b73ae-852f-401a-b92f-1d050160b203/performer.json b/data/performers/460b73ae-852f-401a-b92f-1d050160b203/performer.json
new file mode 100644
index 0000000..d3a4563
--- /dev/null
+++ b/data/performers/460b73ae-852f-401a-b92f-1d050160b203/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "460b73ae-852f-401a-b92f-1d050160b203",
+ "name": "Mike",
+ "url": "https://theporndb.net/performer/460b73ae-852f-401a-b92f-1d050160b203",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:31.977774"
+}
\ No newline at end of file
diff --git a/data/performers/4b91ce7d-ff4c-402d-8917-aaa3a0c27ba0/performer.json b/data/performers/4b91ce7d-ff4c-402d-8917-aaa3a0c27ba0/performer.json
new file mode 100644
index 0000000..90639c3
--- /dev/null
+++ b/data/performers/4b91ce7d-ff4c-402d-8917-aaa3a0c27ba0/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "4b91ce7d-ff4c-402d-8917-aaa3a0c27ba0",
+ "name": "Mia Tresji",
+ "url": "https://theporndb.net/performer/4b91ce7d-ff4c-402d-8917-aaa3a0c27ba0",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.939967"
+}
\ No newline at end of file
diff --git a/data/performers/4ece5f55-80d2-4991-9862-dcabe174bcdb/performer.json b/data/performers/4ece5f55-80d2-4991-9862-dcabe174bcdb/performer.json
new file mode 100644
index 0000000..40b78d0
--- /dev/null
+++ b/data/performers/4ece5f55-80d2-4991-9862-dcabe174bcdb/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "4ece5f55-80d2-4991-9862-dcabe174bcdb",
+ "name": "Bella Madyson",
+ "url": "https://theporndb.net/performer/4ece5f55-80d2-4991-9862-dcabe174bcdb",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.263138"
+}
\ No newline at end of file
diff --git a/data/performers/4ee89ba2-6210-4486-bbe2-c3a75dcc9012/performer.json b/data/performers/4ee89ba2-6210-4486-bbe2-c3a75dcc9012/performer.json
new file mode 100644
index 0000000..fcc77e0
--- /dev/null
+++ b/data/performers/4ee89ba2-6210-4486-bbe2-c3a75dcc9012/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "4ee89ba2-6210-4486-bbe2-c3a75dcc9012",
+ "name": "Iris Murray",
+ "url": "https://theporndb.net/performer/4ee89ba2-6210-4486-bbe2-c3a75dcc9012",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.441528"
+}
\ No newline at end of file
diff --git a/data/performers/5174e511-3f70-4a85-9ecb-182effbd9b42/performer.json b/data/performers/5174e511-3f70-4a85-9ecb-182effbd9b42/performer.json
new file mode 100644
index 0000000..ff12108
--- /dev/null
+++ b/data/performers/5174e511-3f70-4a85-9ecb-182effbd9b42/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "5174e511-3f70-4a85-9ecb-182effbd9b42",
+ "name": "Nico Savage",
+ "url": "https://theporndb.net/performer/5174e511-3f70-4a85-9ecb-182effbd9b42",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.067051"
+}
\ No newline at end of file
diff --git a/data/performers/5496783f-aba6-479f-881d-5fe8e9efad21/performer.json b/data/performers/5496783f-aba6-479f-881d-5fe8e9efad21/performer.json
new file mode 100644
index 0000000..65f8829
--- /dev/null
+++ b/data/performers/5496783f-aba6-479f-881d-5fe8e9efad21/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "5496783f-aba6-479f-881d-5fe8e9efad21",
+ "name": "Goddess Lexie",
+ "url": "https://theporndb.net/performer/5496783f-aba6-479f-881d-5fe8e9efad21",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:30.492477"
+}
\ No newline at end of file
diff --git a/data/performers/55ee1f08-0c5e-49a0-9e7a-8f02b7a5e9e4/performer.json b/data/performers/55ee1f08-0c5e-49a0-9e7a-8f02b7a5e9e4/performer.json
new file mode 100644
index 0000000..36903e7
--- /dev/null
+++ b/data/performers/55ee1f08-0c5e-49a0-9e7a-8f02b7a5e9e4/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "55ee1f08-0c5e-49a0-9e7a-8f02b7a5e9e4",
+ "name": "Cherry Blossom",
+ "url": "https://theporndb.net/performer/55ee1f08-0c5e-49a0-9e7a-8f02b7a5e9e4",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.852371"
+}
\ No newline at end of file
diff --git a/data/performers/59a3c146-a631-4678-a07a-2348ae04711d/performer.json b/data/performers/59a3c146-a631-4678-a07a-2348ae04711d/performer.json
new file mode 100644
index 0000000..c896a05
--- /dev/null
+++ b/data/performers/59a3c146-a631-4678-a07a-2348ae04711d/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "59a3c146-a631-4678-a07a-2348ae04711d",
+ "name": "Aleks Stein",
+ "url": "https://theporndb.net/performer/59a3c146-a631-4678-a07a-2348ae04711d",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.376500"
+}
\ No newline at end of file
diff --git a/data/performers/5b12c499-c83c-464b-bfeb-9023b57dffa5/performer.json b/data/performers/5b12c499-c83c-464b-bfeb-9023b57dffa5/performer.json
new file mode 100644
index 0000000..7339a4e
--- /dev/null
+++ b/data/performers/5b12c499-c83c-464b-bfeb-9023b57dffa5/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "5b12c499-c83c-464b-bfeb-9023b57dffa5",
+ "name": "Keeks",
+ "url": "https://theporndb.net/performer/5b12c499-c83c-464b-bfeb-9023b57dffa5",
+ "aliases": "[\"Keeks3005\"]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:30.077519"
+}
\ No newline at end of file
diff --git a/data/performers/5e1df0e1-d2bb-4d65-9544-1ee64098eda2/performer.json b/data/performers/5e1df0e1-d2bb-4d65-9544-1ee64098eda2/performer.json
new file mode 100644
index 0000000..de943e7
--- /dev/null
+++ b/data/performers/5e1df0e1-d2bb-4d65-9544-1ee64098eda2/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "5e1df0e1-d2bb-4d65-9544-1ee64098eda2",
+ "name": "Levine",
+ "url": "https://theporndb.net/performer/5e1df0e1-d2bb-4d65-9544-1ee64098eda2",
+ "aliases": "[\"Fred\"]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:27.828139"
+}
\ No newline at end of file
diff --git a/data/performers/5e520864-611f-4389-bb53-7a72a9557a1b/performer.json b/data/performers/5e520864-611f-4389-bb53-7a72a9557a1b/performer.json
new file mode 100644
index 0000000..9bc0d7d
--- /dev/null
+++ b/data/performers/5e520864-611f-4389-bb53-7a72a9557a1b/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "5e520864-611f-4389-bb53-7a72a9557a1b",
+ "name": "Brooke Brooke Thomsen",
+ "url": "https://theporndb.net/performer/5e520864-611f-4389-bb53-7a72a9557a1b",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.851087"
+}
\ No newline at end of file
diff --git a/data/performers/6009e864-a2fa-4a13-83db-7a0145a3f000/performer.json b/data/performers/6009e864-a2fa-4a13-83db-7a0145a3f000/performer.json
new file mode 100644
index 0000000..f4cf968
--- /dev/null
+++ b/data/performers/6009e864-a2fa-4a13-83db-7a0145a3f000/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "6009e864-a2fa-4a13-83db-7a0145a3f000",
+ "name": "Sea Jewel",
+ "url": "https://theporndb.net/performer/6009e864-a2fa-4a13-83db-7a0145a3f000",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.574371"
+}
\ No newline at end of file
diff --git a/data/performers/626b9b45-b1cd-4a25-8c17-5191cddea29a/performer.json b/data/performers/626b9b45-b1cd-4a25-8c17-5191cddea29a/performer.json
new file mode 100644
index 0000000..b395d7f
--- /dev/null
+++ b/data/performers/626b9b45-b1cd-4a25-8c17-5191cddea29a/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "626b9b45-b1cd-4a25-8c17-5191cddea29a",
+ "name": "Maddy Maxx",
+ "url": "https://theporndb.net/performer/626b9b45-b1cd-4a25-8c17-5191cddea29a",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.115985"
+}
\ No newline at end of file
diff --git a/data/performers/628e0f9b-c988-45b6-b25f-610e0c9a3a4b/performer.json b/data/performers/628e0f9b-c988-45b6-b25f-610e0c9a3a4b/performer.json
new file mode 100644
index 0000000..7e1e09a
--- /dev/null
+++ b/data/performers/628e0f9b-c988-45b6-b25f-610e0c9a3a4b/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "628e0f9b-c988-45b6-b25f-610e0c9a3a4b",
+ "name": "You Uekura",
+ "url": "https://theporndb.net/performer/628e0f9b-c988-45b6-b25f-610e0c9a3a4b",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.343662"
+}
\ No newline at end of file
diff --git a/data/performers/640f3e84-7d93-4480-ad45-f752aa06e2f7/performer.json b/data/performers/640f3e84-7d93-4480-ad45-f752aa06e2f7/performer.json
new file mode 100644
index 0000000..ea7a277
--- /dev/null
+++ b/data/performers/640f3e84-7d93-4480-ad45-f752aa06e2f7/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "640f3e84-7d93-4480-ad45-f752aa06e2f7",
+ "name": "Suki Desire Room",
+ "url": "https://theporndb.net/performer/640f3e84-7d93-4480-ad45-f752aa06e2f7",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.903304"
+}
\ No newline at end of file
diff --git a/data/performers/64e4da78-689a-4368-8414-d8b1118e4c20/performer.json b/data/performers/64e4da78-689a-4368-8414-d8b1118e4c20/performer.json
new file mode 100644
index 0000000..bc10460
--- /dev/null
+++ b/data/performers/64e4da78-689a-4368-8414-d8b1118e4c20/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "64e4da78-689a-4368-8414-d8b1118e4c20",
+ "name": "Bianca",
+ "url": "https://theporndb.net/performer/64e4da78-689a-4368-8414-d8b1118e4c20",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:32.826569"
+}
\ No newline at end of file
diff --git a/data/performers/7279bb4e-f424-442c-830c-7284440d6649/performer.json b/data/performers/7279bb4e-f424-442c-830c-7284440d6649/performer.json
new file mode 100644
index 0000000..984de78
--- /dev/null
+++ b/data/performers/7279bb4e-f424-442c-830c-7284440d6649/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "7279bb4e-f424-442c-830c-7284440d6649",
+ "name": "Soyogi Amamiya",
+ "url": "https://theporndb.net/performer/7279bb4e-f424-442c-830c-7284440d6649",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.295691"
+}
\ No newline at end of file
diff --git a/data/performers/7556fddf-11e2-4580-8826-2436c45aea11/performer.json b/data/performers/7556fddf-11e2-4580-8826-2436c45aea11/performer.json
new file mode 100644
index 0000000..d29419f
--- /dev/null
+++ b/data/performers/7556fddf-11e2-4580-8826-2436c45aea11/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "7556fddf-11e2-4580-8826-2436c45aea11",
+ "name": "Angie Jolina",
+ "url": "https://theporndb.net/performer/7556fddf-11e2-4580-8826-2436c45aea11",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.641535"
+}
\ No newline at end of file
diff --git a/data/performers/79f11787-1fc7-427e-b815-6cef6a38b6d3/performer.json b/data/performers/79f11787-1fc7-427e-b815-6cef6a38b6d3/performer.json
new file mode 100644
index 0000000..77002c7
--- /dev/null
+++ b/data/performers/79f11787-1fc7-427e-b815-6cef6a38b6d3/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "79f11787-1fc7-427e-b815-6cef6a38b6d3",
+ "name": "Lexilicious Reid",
+ "url": "https://theporndb.net/performer/79f11787-1fc7-427e-b815-6cef6a38b6d3",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.800114"
+}
\ No newline at end of file
diff --git a/data/performers/7bce4de8-3206-43d1-9f2c-f816900fa79a/performer.json b/data/performers/7bce4de8-3206-43d1-9f2c-f816900fa79a/performer.json
new file mode 100644
index 0000000..183e28a
--- /dev/null
+++ b/data/performers/7bce4de8-3206-43d1-9f2c-f816900fa79a/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "7bce4de8-3206-43d1-9f2c-f816900fa79a",
+ "name": "Nicolas Novoa",
+ "url": "https://theporndb.net/performer/7bce4de8-3206-43d1-9f2c-f816900fa79a",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:29.637441"
+}
\ No newline at end of file
diff --git a/data/performers/7d341ba8-3fe5-496e-871b-61148ee2eaba/performer.json b/data/performers/7d341ba8-3fe5-496e-871b-61148ee2eaba/performer.json
new file mode 100644
index 0000000..7aac681
--- /dev/null
+++ b/data/performers/7d341ba8-3fe5-496e-871b-61148ee2eaba/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "7d341ba8-3fe5-496e-871b-61148ee2eaba",
+ "name": "Logan Roth",
+ "url": "https://theporndb.net/performer/7d341ba8-3fe5-496e-871b-61148ee2eaba",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.458290"
+}
\ No newline at end of file
diff --git a/data/performers/7eb1fc26-8201-495a-8428-1a56a26efeee/performer.json b/data/performers/7eb1fc26-8201-495a-8428-1a56a26efeee/performer.json
new file mode 100644
index 0000000..5beb4d0
--- /dev/null
+++ b/data/performers/7eb1fc26-8201-495a-8428-1a56a26efeee/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "7eb1fc26-8201-495a-8428-1a56a26efeee",
+ "name": "Diego Aracena",
+ "url": "https://theporndb.net/performer/7eb1fc26-8201-495a-8428-1a56a26efeee",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.000436"
+}
\ No newline at end of file
diff --git a/data/performers/82809dcd-5c1d-4f44-b1a9-a2be82fecd05/performer.json b/data/performers/82809dcd-5c1d-4f44-b1a9-a2be82fecd05/performer.json
new file mode 100644
index 0000000..e67cbca
--- /dev/null
+++ b/data/performers/82809dcd-5c1d-4f44-b1a9-a2be82fecd05/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "82809dcd-5c1d-4f44-b1a9-a2be82fecd05",
+ "name": "Rileyriley Mae",
+ "url": "https://theporndb.net/performer/82809dcd-5c1d-4f44-b1a9-a2be82fecd05",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.755258"
+}
\ No newline at end of file
diff --git a/data/performers/83e99bb4-ba31-4758-9332-e0d031948d47/performer.json b/data/performers/83e99bb4-ba31-4758-9332-e0d031948d47/performer.json
new file mode 100644
index 0000000..a7789bd
--- /dev/null
+++ b/data/performers/83e99bb4-ba31-4758-9332-e0d031948d47/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "83e99bb4-ba31-4758-9332-e0d031948d47",
+ "name": "Ricky Idol",
+ "url": "https://theporndb.net/performer/83e99bb4-ba31-4758-9332-e0d031948d47",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.234015"
+}
\ No newline at end of file
diff --git a/data/performers/90208299-6cff-4bba-a0c7-062445fe3b00/performer.json b/data/performers/90208299-6cff-4bba-a0c7-062445fe3b00/performer.json
new file mode 100644
index 0000000..f2661d2
--- /dev/null
+++ b/data/performers/90208299-6cff-4bba-a0c7-062445fe3b00/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "90208299-6cff-4bba-a0c7-062445fe3b00",
+ "name": "Sabrina Sweet",
+ "url": "https://theporndb.net/performer/90208299-6cff-4bba-a0c7-062445fe3b00",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.980910"
+}
\ No newline at end of file
diff --git a/data/performers/9071b9c4-c08e-4784-853e-f43010b9972e/performer.json b/data/performers/9071b9c4-c08e-4784-853e-f43010b9972e/performer.json
new file mode 100644
index 0000000..dc1a75d
--- /dev/null
+++ b/data/performers/9071b9c4-c08e-4784-853e-f43010b9972e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "9071b9c4-c08e-4784-853e-f43010b9972e",
+ "name": "Amelia Ash",
+ "url": "https://theporndb.net/performer/9071b9c4-c08e-4784-853e-f43010b9972e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.217243"
+}
\ No newline at end of file
diff --git a/data/performers/9247eded-8e48-4bde-ac44-d735e2895200/performer.json b/data/performers/9247eded-8e48-4bde-ac44-d735e2895200/performer.json
new file mode 100644
index 0000000..434853c
--- /dev/null
+++ b/data/performers/9247eded-8e48-4bde-ac44-d735e2895200/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "9247eded-8e48-4bde-ac44-d735e2895200",
+ "name": "Bibi",
+ "url": "https://theporndb.net/performer/9247eded-8e48-4bde-ac44-d735e2895200",
+ "aliases": "[\"Bibi Fox\"]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:32.404204"
+}
\ No newline at end of file
diff --git a/data/performers/93be2f85-5519-4a0e-a1fe-e7d077ee9966/performer.json b/data/performers/93be2f85-5519-4a0e-a1fe-e7d077ee9966/performer.json
new file mode 100644
index 0000000..d3daf66
--- /dev/null
+++ b/data/performers/93be2f85-5519-4a0e-a1fe-e7d077ee9966/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "93be2f85-5519-4a0e-a1fe-e7d077ee9966",
+ "name": "Mike",
+ "url": "https://theporndb.net/performer/93be2f85-5519-4a0e-a1fe-e7d077ee9966",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:31.562168"
+}
\ No newline at end of file
diff --git a/data/performers/998e289f-9910-4f49-9ccc-99e22c0e5843/performer.json b/data/performers/998e289f-9910-4f49-9ccc-99e22c0e5843/performer.json
new file mode 100644
index 0000000..2353092
--- /dev/null
+++ b/data/performers/998e289f-9910-4f49-9ccc-99e22c0e5843/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "998e289f-9910-4f49-9ccc-99e22c0e5843",
+ "name": "Luci Lovette",
+ "url": "https://theporndb.net/performer/998e289f-9910-4f49-9ccc-99e22c0e5843",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.739283"
+}
\ No newline at end of file
diff --git a/data/performers/9adabd18-6371-472f-b346-544f210a6c2a/performer.json b/data/performers/9adabd18-6371-472f-b346-544f210a6c2a/performer.json
new file mode 100644
index 0000000..f931070
--- /dev/null
+++ b/data/performers/9adabd18-6371-472f-b346-544f210a6c2a/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "9adabd18-6371-472f-b346-544f210a6c2a",
+ "name": "Peter Summers",
+ "url": "https://theporndb.net/performer/9adabd18-6371-472f-b346-544f210a6c2a",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.183337"
+}
\ No newline at end of file
diff --git a/data/performers/9b77a441-ecc9-4e9e-b5d0-d98a9f2e5d3e/performer.json b/data/performers/9b77a441-ecc9-4e9e-b5d0-d98a9f2e5d3e/performer.json
new file mode 100644
index 0000000..e5b75bc
--- /dev/null
+++ b/data/performers/9b77a441-ecc9-4e9e-b5d0-d98a9f2e5d3e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "9b77a441-ecc9-4e9e-b5d0-d98a9f2e5d3e",
+ "name": "Marek Fire",
+ "url": "https://theporndb.net/performer/9b77a441-ecc9-4e9e-b5d0-d98a9f2e5d3e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:33.796586"
+}
\ No newline at end of file
diff --git a/data/performers/P487184.json b/data/performers/P487184.json
new file mode 100644
index 0000000..738cb27
--- /dev/null
+++ b/data/performers/P487184.json
@@ -0,0 +1,25 @@
+{
+ "id": "P487184",
+ "name": "faye raegan",
+ "aliases": [],
+ "gender": "-",
+ "birthdate": "-",
+ "country": "-",
+ "nationality": "-",
+ "ethnicity": "-",
+ "hair_color": "-",
+ "eye_color": "-",
+ "height_cm": null,
+ "measurements": "-",
+ "breast_type": "-",
+ "tags": [],
+ "thumbnail": null,
+ "url": "https://www.pornpics.com/pornstars/faye-raegan/",
+ "stats": {
+ "total_galleries": 0
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/faye-raegan/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/PP10802.json b/data/performers/PP10802.json
new file mode 100644
index 0000000..aa2a372
--- /dev/null
+++ b/data/performers/PP10802.json
@@ -0,0 +1,34 @@
+{
+ "id": "PP10802",
+ "name": "Sasha Grey",
+ "aliases": [
+ "Sasha Gray"
+ ],
+ "gender": "Female",
+ "birthdate": "1988-03-14",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": 170,
+ "measurements": "32B-26-31",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "American",
+ "Brunette",
+ "Natural Tits",
+ "Skinny",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/s/sasha_grey.jpg",
+ "url": "https://www.pornpics.com/pornstars/sasha-grey/",
+ "stats": {
+ "total_galleries": 371
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/sasha-grey/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/PP17020.json b/data/performers/PP17020.json
new file mode 100644
index 0000000..51bcce9
--- /dev/null
+++ b/data/performers/PP17020.json
@@ -0,0 +1,32 @@
+{
+ "id": "PP17020",
+ "name": "Mia Split",
+ "aliases": [],
+ "gender": "Female",
+ "birthdate": "",
+ "country": "Russian Federation",
+ "nationality": "Russian",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": null,
+ "measurements": "??-??-??",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "Brunette",
+ "Natural Tits",
+ "Petite",
+ "Russian",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/m/mia_split.jpg",
+ "url": "https://www.pornpics.com/pornstars/mia-split/",
+ "stats": {
+ "total_galleries": 73
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/mia-split/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/PP21083.json b/data/performers/PP21083.json
new file mode 100644
index 0000000..c5ea452
--- /dev/null
+++ b/data/performers/PP21083.json
@@ -0,0 +1,32 @@
+{
+ "id": "PP21083",
+ "name": "J Mac",
+ "aliases": [
+ "Jmac"
+ ],
+ "gender": "Male",
+ "birthdate": "1985-03-12",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": 185,
+ "measurements": "",
+ "breast_type": "",
+ "tags": [
+ "American",
+ "Brunette",
+ "Tattoo",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/j/j_mac.jpg",
+ "url": "https://www.pornpics.com/pornstars/j-mac/",
+ "stats": {
+ "total_galleries": 2277
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/j-mac/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/PP21647.json b/data/performers/PP21647.json
new file mode 100644
index 0000000..39cebcd
--- /dev/null
+++ b/data/performers/PP21647.json
@@ -0,0 +1,36 @@
+{
+ "id": "PP21647",
+ "name": "Johnny Sins",
+ "aliases": [
+ "Jonny Sins",
+ "Johnny Sinns",
+ "Johnny Sinn",
+ "Johny Sins",
+ "Jhonny Sins"
+ ],
+ "gender": "Male",
+ "birthdate": "1978-12-31",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": 183,
+ "measurements": "",
+ "breast_type": "",
+ "tags": [
+ "American",
+ "Bald",
+ "Brunette",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/j/johnny_sins.jpg",
+ "url": "https://www.pornpics.com/pornstars/johnny-sins/",
+ "stats": {
+ "total_galleries": 2081
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/johnny-sins/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/PP3684.json b/data/performers/PP3684.json
new file mode 100644
index 0000000..9973c1d
--- /dev/null
+++ b/data/performers/PP3684.json
@@ -0,0 +1,33 @@
+{
+ "id": "PP3684",
+ "name": "Alexis Texas",
+ "aliases": [],
+ "gender": "Female",
+ "birthdate": "1985-05-25",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Blonde",
+ "eye_color": "-",
+ "height_cm": 173,
+ "measurements": "34C-27-40",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "American",
+ "Blonde",
+ "MILF",
+ "Natural Tits",
+ "Puerto Rican",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/a/alexis_texas.jpg",
+ "url": "https://www.pornpics.com/pornstars/alexis-texas/",
+ "stats": {
+ "total_galleries": 1060
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/alexis-texas/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/PP4806.json b/data/performers/PP4806.json
new file mode 100644
index 0000000..30b4c6c
--- /dev/null
+++ b/data/performers/PP4806.json
@@ -0,0 +1,36 @@
+{
+ "id": "PP4806",
+ "name": "Faye Reagan",
+ "aliases": [
+ "Faye B",
+ "Faye Raegan",
+ "Faye Regan",
+ "Faye Reagen"
+ ],
+ "gender": "Female",
+ "birthdate": "1988-09-19",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Redhead",
+ "eye_color": "-",
+ "height_cm": 163,
+ "measurements": "34C-28-36",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "American",
+ "MILF",
+ "Natural Tits",
+ "Redhead",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/f/faye_reagan.jpg",
+ "url": "https://www.pornpics.com/pornstars/faye-reagan/",
+ "stats": {
+ "total_galleries": 549
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/faye-reagan/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/PP4988.json b/data/performers/PP4988.json
new file mode 100644
index 0000000..1e9c6b9
--- /dev/null
+++ b/data/performers/PP4988.json
@@ -0,0 +1,40 @@
+{
+ "id": "PP4988",
+ "name": "Monique Alexander",
+ "aliases": [
+ "Monique Alexandre",
+ "Savannah Moore",
+ "Briana Burke",
+ "Monique Alex"
+ ],
+ "gender": "Female",
+ "birthdate": "1982-05-26",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Redhead",
+ "eye_color": "-",
+ "height_cm": 165,
+ "measurements": "32C-24-34",
+ "breast_type": "Fake Tits",
+ "tags": [
+ "American",
+ "Fake Tits",
+ "MILF",
+ "Portuguese",
+ "Redhead",
+ "Skinny",
+ "Tattoo",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/m/monique_alexander.jpg",
+ "url": "https://www.pornpics.com/pornstars/monique-alexander/",
+ "stats": {
+ "total_galleries": 1017
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/monique-alexander/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/PP899.json b/data/performers/PP899.json
new file mode 100644
index 0000000..0c7ff9f
--- /dev/null
+++ b/data/performers/PP899.json
@@ -0,0 +1,38 @@
+{
+ "id": "PP899",
+ "name": "Madison Scott",
+ "aliases": [
+ "Madison Scot"
+ ],
+ "gender": "Female",
+ "birthdate": "1988-07-13",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Blonde",
+ "eye_color": "-",
+ "height_cm": 155,
+ "measurements": "32DD-20-26",
+ "breast_type": "Fake Tits",
+ "tags": [
+ "American",
+ "Big Tits",
+ "Blonde",
+ "Fake Tits",
+ "MILF",
+ "Petite",
+ "Short",
+ "Skinny",
+ "Tattoo",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/m/madison_scott.jpg",
+ "url": "https://www.pornpics.com/pornstars/madison-scott/",
+ "stats": {
+ "total_galleries": 385
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/madison-scott/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/a32c1c26-6c22-44fc-a4a2-f8956da2f485/performer.json b/data/performers/a32c1c26-6c22-44fc-a4a2-f8956da2f485/performer.json
new file mode 100644
index 0000000..dcf1a68
--- /dev/null
+++ b/data/performers/a32c1c26-6c22-44fc-a4a2-f8956da2f485/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "a32c1c26-6c22-44fc-a4a2-f8956da2f485",
+ "name": "O1st Xxx",
+ "url": "https://theporndb.net/performer/a32c1c26-6c22-44fc-a4a2-f8956da2f485",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.981628"
+}
\ No newline at end of file
diff --git a/data/performers/a379151c-67d5-41d4-853f-1773ad515fbf/performer.json b/data/performers/a379151c-67d5-41d4-853f-1773ad515fbf/performer.json
new file mode 100644
index 0000000..f37a2e5
--- /dev/null
+++ b/data/performers/a379151c-67d5-41d4-853f-1773ad515fbf/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "a379151c-67d5-41d4-853f-1773ad515fbf",
+ "name": "The Real Diabla",
+ "url": "https://theporndb.net/performer/a379151c-67d5-41d4-853f-1773ad515fbf",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.425449"
+}
\ No newline at end of file
diff --git a/data/performers/a3d6765e-3e7e-4046-8bf3-b315b8abb747/performer.json b/data/performers/a3d6765e-3e7e-4046-8bf3-b315b8abb747/performer.json
new file mode 100644
index 0000000..aae132b
--- /dev/null
+++ b/data/performers/a3d6765e-3e7e-4046-8bf3-b315b8abb747/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "a3d6765e-3e7e-4046-8bf3-b315b8abb747",
+ "name": "Kittymocap Cgi",
+ "url": "https://theporndb.net/performer/a3d6765e-3e7e-4046-8bf3-b315b8abb747",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.767704"
+}
\ No newline at end of file
diff --git a/data/performers/a4ff8226-47ed-4836-a377-a3692cd0b071/performer.json b/data/performers/a4ff8226-47ed-4836-a377-a3692cd0b071/performer.json
new file mode 100644
index 0000000..65c39bb
--- /dev/null
+++ b/data/performers/a4ff8226-47ed-4836-a377-a3692cd0b071/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "a4ff8226-47ed-4836-a377-a3692cd0b071",
+ "name": "Alejandro Alzate",
+ "url": "https://theporndb.net/performer/a4ff8226-47ed-4836-a377-a3692cd0b071",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.735925"
+}
\ No newline at end of file
diff --git a/data/performers/a6a3dfde-c755-4cdf-8a5d-f89294800d44/performer.json b/data/performers/a6a3dfde-c755-4cdf-8a5d-f89294800d44/performer.json
new file mode 100644
index 0000000..6aa8869
--- /dev/null
+++ b/data/performers/a6a3dfde-c755-4cdf-8a5d-f89294800d44/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "a6a3dfde-c755-4cdf-8a5d-f89294800d44",
+ "name": "Citah Manson",
+ "url": "https://theporndb.net/performer/a6a3dfde-c755-4cdf-8a5d-f89294800d44",
+ "aliases": "[\"Citah\", \"Citah69\"]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.539911"
+}
\ No newline at end of file
diff --git a/data/performers/a7b79a20-2554-46df-962d-b25a171f3506/performer.json b/data/performers/a7b79a20-2554-46df-962d-b25a171f3506/performer.json
new file mode 100644
index 0000000..55c8029
--- /dev/null
+++ b/data/performers/a7b79a20-2554-46df-962d-b25a171f3506/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "a7b79a20-2554-46df-962d-b25a171f3506",
+ "name": "Dahlia Fvr",
+ "url": "https://theporndb.net/performer/a7b79a20-2554-46df-962d-b25a171f3506",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.280206"
+}
\ No newline at end of file
diff --git a/data/performers/aab0808b-4d84-424e-87d8-eb973aa98ce3/performer.json b/data/performers/aab0808b-4d84-424e-87d8-eb973aa98ce3/performer.json
new file mode 100644
index 0000000..65124c6
--- /dev/null
+++ b/data/performers/aab0808b-4d84-424e-87d8-eb973aa98ce3/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "aab0808b-4d84-424e-87d8-eb973aa98ce3",
+ "name": "Sanae Kiyoshige",
+ "url": "https://theporndb.net/performer/aab0808b-4d84-424e-87d8-eb973aa98ce3",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.556915"
+}
\ No newline at end of file
diff --git a/data/performers/alexis-texas.json b/data/performers/alexis-texas.json
new file mode 100644
index 0000000..9973c1d
--- /dev/null
+++ b/data/performers/alexis-texas.json
@@ -0,0 +1,33 @@
+{
+ "id": "PP3684",
+ "name": "Alexis Texas",
+ "aliases": [],
+ "gender": "Female",
+ "birthdate": "1985-05-25",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Blonde",
+ "eye_color": "-",
+ "height_cm": 173,
+ "measurements": "34C-27-40",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "American",
+ "Blonde",
+ "MILF",
+ "Natural Tits",
+ "Puerto Rican",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/a/alexis_texas.jpg",
+ "url": "https://www.pornpics.com/pornstars/alexis-texas/",
+ "stats": {
+ "total_galleries": 1060
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/alexis-texas/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/b0c35557-470f-4bae-9818-22e433da8174/performer.json b/data/performers/b0c35557-470f-4bae-9818-22e433da8174/performer.json
new file mode 100644
index 0000000..6e55a8f
--- /dev/null
+++ b/data/performers/b0c35557-470f-4bae-9818-22e433da8174/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "b0c35557-470f-4bae-9818-22e433da8174",
+ "name": "Master Sir Alex Payne",
+ "url": "https://theporndb.net/performer/b0c35557-470f-4bae-9818-22e433da8174",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.828539"
+}
\ No newline at end of file
diff --git a/data/performers/b1878fa0-08c8-44e1-be3c-9c0efe88fc45/performer.json b/data/performers/b1878fa0-08c8-44e1-be3c-9c0efe88fc45/performer.json
new file mode 100644
index 0000000..d0a7023
--- /dev/null
+++ b/data/performers/b1878fa0-08c8-44e1-be3c-9c0efe88fc45/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "b1878fa0-08c8-44e1-be3c-9c0efe88fc45",
+ "name": "Connor Peters",
+ "url": "https://theporndb.net/performer/b1878fa0-08c8-44e1-be3c-9c0efe88fc45",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.166937"
+}
\ No newline at end of file
diff --git a/data/performers/b245fca1-4bd8-4670-9030-79b8987a90e7/performer.json b/data/performers/b245fca1-4bd8-4670-9030-79b8987a90e7/performer.json
new file mode 100644
index 0000000..2abe490
--- /dev/null
+++ b/data/performers/b245fca1-4bd8-4670-9030-79b8987a90e7/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "b245fca1-4bd8-4670-9030-79b8987a90e7",
+ "name": "Kenneth Anderson",
+ "url": "https://theporndb.net/performer/b245fca1-4bd8-4670-9030-79b8987a90e7",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:38.439708"
+}
\ No newline at end of file
diff --git a/data/performers/b433f066-fa57-4c4a-b76f-c5e326201a2e/performer.json b/data/performers/b433f066-fa57-4c4a-b76f-c5e326201a2e/performer.json
new file mode 100644
index 0000000..69464c8
--- /dev/null
+++ b/data/performers/b433f066-fa57-4c4a-b76f-c5e326201a2e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "b433f066-fa57-4c4a-b76f-c5e326201a2e",
+ "name": "Nova Tevez",
+ "url": "https://theporndb.net/performer/b433f066-fa57-4c4a-b76f-c5e326201a2e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.960566"
+}
\ No newline at end of file
diff --git a/data/performers/b615735f-94da-4fae-b55c-59072384809d/performer.json b/data/performers/b615735f-94da-4fae-b55c-59072384809d/performer.json
new file mode 100644
index 0000000..bdbc8c0
--- /dev/null
+++ b/data/performers/b615735f-94da-4fae-b55c-59072384809d/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "b615735f-94da-4fae-b55c-59072384809d",
+ "name": "Luciano Lutti",
+ "url": "https://theporndb.net/performer/b615735f-94da-4fae-b55c-59072384809d",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.474882"
+}
\ No newline at end of file
diff --git a/data/performers/b71db76e-7f0b-4049-bd24-29707ffe0621/performer.json b/data/performers/b71db76e-7f0b-4049-bd24-29707ffe0621/performer.json
new file mode 100644
index 0000000..4a65055
--- /dev/null
+++ b/data/performers/b71db76e-7f0b-4049-bd24-29707ffe0621/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "b71db76e-7f0b-4049-bd24-29707ffe0621",
+ "name": "Jessajessa Jordan",
+ "url": "https://theporndb.net/performer/b71db76e-7f0b-4049-bd24-29707ffe0621",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.809425"
+}
\ No newline at end of file
diff --git a/data/performers/b87a5b3a-01d6-4314-a087-aba786ecfba4/performer.json b/data/performers/b87a5b3a-01d6-4314-a087-aba786ecfba4/performer.json
new file mode 100644
index 0000000..230ab88
--- /dev/null
+++ b/data/performers/b87a5b3a-01d6-4314-a087-aba786ecfba4/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "b87a5b3a-01d6-4314-a087-aba786ecfba4",
+ "name": "Kinky Bitch",
+ "url": "https://theporndb.net/performer/b87a5b3a-01d6-4314-a087-aba786ecfba4",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.050693"
+}
\ No newline at end of file
diff --git a/data/performers/b888b8da-c3b4-44c1-92aa-2b9521b52a0a/performer.json b/data/performers/b888b8da-c3b4-44c1-92aa-2b9521b52a0a/performer.json
new file mode 100644
index 0000000..edb0920
--- /dev/null
+++ b/data/performers/b888b8da-c3b4-44c1-92aa-2b9521b52a0a/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "b888b8da-c3b4-44c1-92aa-2b9521b52a0a",
+ "name": "Domina Ava Savage",
+ "url": "https://theporndb.net/performer/b888b8da-c3b4-44c1-92aa-2b9521b52a0a",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.817034"
+}
\ No newline at end of file
diff --git a/data/performers/c56fd205-3a75-4a73-9c4c-95a2c901c8bf/performer.json b/data/performers/c56fd205-3a75-4a73-9c4c-95a2c901c8bf/performer.json
new file mode 100644
index 0000000..58d1228
--- /dev/null
+++ b/data/performers/c56fd205-3a75-4a73-9c4c-95a2c901c8bf/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "c56fd205-3a75-4a73-9c4c-95a2c901c8bf",
+ "name": "Reika Makino",
+ "url": "https://theporndb.net/performer/c56fd205-3a75-4a73-9c4c-95a2c901c8bf",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.311907"
+}
\ No newline at end of file
diff --git a/data/performers/c6175cb7-142c-40ba-b1f2-850bb23bb121/performer.json b/data/performers/c6175cb7-142c-40ba-b1f2-850bb23bb121/performer.json
new file mode 100644
index 0000000..dd5bf8e
--- /dev/null
+++ b/data/performers/c6175cb7-142c-40ba-b1f2-850bb23bb121/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "c6175cb7-142c-40ba-b1f2-850bb23bb121",
+ "name": "Yulija Malkika",
+ "url": "https://theporndb.net/performer/c6175cb7-142c-40ba-b1f2-850bb23bb121",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.624469"
+}
\ No newline at end of file
diff --git a/data/performers/c64e3a3d-6657-460c-a03d-f753954e4110/performer.json b/data/performers/c64e3a3d-6657-460c-a03d-f753954e4110/performer.json
new file mode 100644
index 0000000..ac038d0
--- /dev/null
+++ b/data/performers/c64e3a3d-6657-460c-a03d-f753954e4110/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "c64e3a3d-6657-460c-a03d-f753954e4110",
+ "name": "Sumiko Dreams",
+ "url": "https://theporndb.net/performer/c64e3a3d-6657-460c-a03d-f753954e4110",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.834255"
+}
\ No newline at end of file
diff --git a/data/performers/d0b993ce-fc6b-4bab-983b-b02290525681/performer.json b/data/performers/d0b993ce-fc6b-4bab-983b-b02290525681/performer.json
new file mode 100644
index 0000000..cc17712
--- /dev/null
+++ b/data/performers/d0b993ce-fc6b-4bab-983b-b02290525681/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "d0b993ce-fc6b-4bab-983b-b02290525681",
+ "name": "Luna 32 B2434",
+ "url": "https://theporndb.net/performer/d0b993ce-fc6b-4bab-983b-b02290525681",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.869054"
+}
\ No newline at end of file
diff --git a/data/performers/d1085beb-c80e-4765-af26-e65f16fcb7c1/performer.json b/data/performers/d1085beb-c80e-4765-af26-e65f16fcb7c1/performer.json
new file mode 100644
index 0000000..3e247ee
--- /dev/null
+++ b/data/performers/d1085beb-c80e-4765-af26-e65f16fcb7c1/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "d1085beb-c80e-4765-af26-e65f16fcb7c1",
+ "name": "Erocom Yuakari",
+ "url": "https://theporndb.net/performer/d1085beb-c80e-4765-af26-e65f16fcb7c1",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.408568"
+}
\ No newline at end of file
diff --git a/data/performers/d8fa3627-75d9-4026-9eea-00a9f9c023fe/performer.json b/data/performers/d8fa3627-75d9-4026-9eea-00a9f9c023fe/performer.json
new file mode 100644
index 0000000..0663f81
--- /dev/null
+++ b/data/performers/d8fa3627-75d9-4026-9eea-00a9f9c023fe/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "d8fa3627-75d9-4026-9eea-00a9f9c023fe",
+ "name": "Amori",
+ "url": "https://theporndb.net/performer/d8fa3627-75d9-4026-9eea-00a9f9c023fe",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:28.237363"
+}
\ No newline at end of file
diff --git a/data/performers/dd555c22-b5ac-41ee-a783-8831cafaa2a9/performer.json b/data/performers/dd555c22-b5ac-41ee-a783-8831cafaa2a9/performer.json
new file mode 100644
index 0000000..3e2b84b
--- /dev/null
+++ b/data/performers/dd555c22-b5ac-41ee-a783-8831cafaa2a9/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "dd555c22-b5ac-41ee-a783-8831cafaa2a9",
+ "name": "Oliver Clothesoff",
+ "url": "https://theporndb.net/performer/dd555c22-b5ac-41ee-a783-8831cafaa2a9",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:35.514375"
+}
\ No newline at end of file
diff --git a/data/performers/dd6bd00a-2a54-492a-a6a5-00004f923c2f/performer.json b/data/performers/dd6bd00a-2a54-492a-a6a5-00004f923c2f/performer.json
new file mode 100644
index 0000000..c24fbb9
--- /dev/null
+++ b/data/performers/dd6bd00a-2a54-492a-a6a5-00004f923c2f/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "dd6bd00a-2a54-492a-a6a5-00004f923c2f",
+ "name": "Christian Black",
+ "url": "https://theporndb.net/performer/dd6bd00a-2a54-492a-a6a5-00004f923c2f",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:34.228030"
+}
\ No newline at end of file
diff --git a/data/performers/ddfd7716-9b9e-4c9c-9860-5fea74912dd3/performer.json b/data/performers/ddfd7716-9b9e-4c9c-9860-5fea74912dd3/performer.json
new file mode 100644
index 0000000..3fea4f2
--- /dev/null
+++ b/data/performers/ddfd7716-9b9e-4c9c-9860-5fea74912dd3/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "ddfd7716-9b9e-4c9c-9860-5fea74912dd3",
+ "name": "Natalia Dark",
+ "url": "https://theporndb.net/performer/ddfd7716-9b9e-4c9c-9860-5fea74912dd3",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.783942"
+}
\ No newline at end of file
diff --git a/data/performers/e3a55de0-acbb-4089-b9be-d521548e2a91/performer.json b/data/performers/e3a55de0-acbb-4089-b9be-d521548e2a91/performer.json
new file mode 100644
index 0000000..648ac5a
--- /dev/null
+++ b/data/performers/e3a55de0-acbb-4089-b9be-d521548e2a91/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "e3a55de0-acbb-4089-b9be-d521548e2a91",
+ "name": "Dic Tracy",
+ "url": "https://theporndb.net/performer/e3a55de0-acbb-4089-b9be-d521548e2a91",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:35.955467"
+}
\ No newline at end of file
diff --git a/data/performers/e645db83-24bb-4d65-a166-91787f1f3c40/performer.json b/data/performers/e645db83-24bb-4d65-a166-91787f1f3c40/performer.json
new file mode 100644
index 0000000..4fd7207
--- /dev/null
+++ b/data/performers/e645db83-24bb-4d65-a166-91787f1f3c40/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "e645db83-24bb-4d65-a166-91787f1f3c40",
+ "name": "Bandida Do Funk",
+ "url": "https://theporndb.net/performer/e645db83-24bb-4d65-a166-91787f1f3c40",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.392338"
+}
\ No newline at end of file
diff --git a/data/performers/e7972b51-145a-4041-b390-aae1d0044f6e/performer.json b/data/performers/e7972b51-145a-4041-b390-aae1d0044f6e/performer.json
new file mode 100644
index 0000000..d4baa29
--- /dev/null
+++ b/data/performers/e7972b51-145a-4041-b390-aae1d0044f6e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "e7972b51-145a-4041-b390-aae1d0044f6e",
+ "name": "Jessajessa Jordan",
+ "url": "https://theporndb.net/performer/e7972b51-145a-4041-b390-aae1d0044f6e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.793030"
+}
\ No newline at end of file
diff --git a/data/performers/e9a7ba8b-e6b4-49e8-bf31-3cdb94e7b06a/performer.json b/data/performers/e9a7ba8b-e6b4-49e8-bf31-3cdb94e7b06a/performer.json
new file mode 100644
index 0000000..fa68b2b
--- /dev/null
+++ b/data/performers/e9a7ba8b-e6b4-49e8-bf31-3cdb94e7b06a/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "e9a7ba8b-e6b4-49e8-bf31-3cdb94e7b06a",
+ "name": "Mike",
+ "url": "https://theporndb.net/performer/e9a7ba8b-e6b4-49e8-bf31-3cdb94e7b06a",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:35.076234"
+}
\ No newline at end of file
diff --git a/data/performers/ecaf9000-d1e3-4553-b181-b7855c9805b6/performer.json b/data/performers/ecaf9000-d1e3-4553-b181-b7855c9805b6/performer.json
new file mode 100644
index 0000000..d2f4cee
--- /dev/null
+++ b/data/performers/ecaf9000-d1e3-4553-b181-b7855c9805b6/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "ecaf9000-d1e3-4553-b181-b7855c9805b6",
+ "name": "Martina Sinblond",
+ "url": "https://theporndb.net/performer/ecaf9000-d1e3-4553-b181-b7855c9805b6",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.083516"
+}
\ No newline at end of file
diff --git a/data/performers/ed1dfb9e-2ef2-4edc-b037-12646434307e/performer.json b/data/performers/ed1dfb9e-2ef2-4edc-b037-12646434307e/performer.json
new file mode 100644
index 0000000..bcb1822
--- /dev/null
+++ b/data/performers/ed1dfb9e-2ef2-4edc-b037-12646434307e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "ed1dfb9e-2ef2-4edc-b037-12646434307e",
+ "name": "Valentina Crush",
+ "url": "https://theporndb.net/performer/ed1dfb9e-2ef2-4edc-b037-12646434307e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.916999"
+}
\ No newline at end of file
diff --git a/data/performers/ef182473-6644-4d58-a210-7fb215358795/performer.json b/data/performers/ef182473-6644-4d58-a210-7fb215358795/performer.json
new file mode 100644
index 0000000..556d2b4
--- /dev/null
+++ b/data/performers/ef182473-6644-4d58-a210-7fb215358795/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "ef182473-6644-4d58-a210-7fb215358795",
+ "name": "Benjamin Xl",
+ "url": "https://theporndb.net/performer/ef182473-6644-4d58-a210-7fb215358795",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.018422"
+}
\ No newline at end of file
diff --git a/data/performers/f5a8e799-1d79-4edb-bc64-c5bae81ace23/performer.json b/data/performers/f5a8e799-1d79-4edb-bc64-c5bae81ace23/performer.json
new file mode 100644
index 0000000..a7424a7
--- /dev/null
+++ b/data/performers/f5a8e799-1d79-4edb-bc64-c5bae81ace23/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "f5a8e799-1d79-4edb-bc64-c5bae81ace23",
+ "name": "Elliott Thomas",
+ "url": "https://theporndb.net/performer/f5a8e799-1d79-4edb-bc64-c5bae81ace23",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:25.938209"
+}
\ No newline at end of file
diff --git a/data/performers/f72ead88-f212-49ad-9ef9-53fd8a3d148d/performer.json b/data/performers/f72ead88-f212-49ad-9ef9-53fd8a3d148d/performer.json
new file mode 100644
index 0000000..80802e0
--- /dev/null
+++ b/data/performers/f72ead88-f212-49ad-9ef9-53fd8a3d148d/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "f72ead88-f212-49ad-9ef9-53fd8a3d148d",
+ "name": "Milli George",
+ "url": "https://theporndb.net/performer/f72ead88-f212-49ad-9ef9-53fd8a3d148d",
+ "aliases": "[\"Amelia George\"]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": null,
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:37.075856"
+}
\ No newline at end of file
diff --git a/data/performers/f8f6d764-887d-4c77-91d7-f8b357f9f95e/performer.json b/data/performers/f8f6d764-887d-4c77-91d7-f8b357f9f95e/performer.json
new file mode 100644
index 0000000..aa6bb60
--- /dev/null
+++ b/data/performers/f8f6d764-887d-4c77-91d7-f8b357f9f95e/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "f8f6d764-887d-4c77-91d7-f8b357f9f95e",
+ "name": "Naomi Swaan",
+ "url": "https://theporndb.net/performer/f8f6d764-887d-4c77-91d7-f8b357f9f95e",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.723780"
+}
\ No newline at end of file
diff --git a/data/performers/f94f90ed-df41-4a4c-9b7c-b53e2d5118f7/performer.json b/data/performers/f94f90ed-df41-4a4c-9b7c-b53e2d5118f7/performer.json
new file mode 100644
index 0000000..89fca42
--- /dev/null
+++ b/data/performers/f94f90ed-df41-4a4c-9b7c-b53e2d5118f7/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "f94f90ed-df41-4a4c-9b7c-b53e2d5118f7",
+ "name": "Torsten Harnisch",
+ "url": "https://theporndb.net/performer/f94f90ed-df41-4a4c-9b7c-b53e2d5118f7",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:27.063967"
+}
\ No newline at end of file
diff --git a/data/performers/faye-reagan.json b/data/performers/faye-reagan.json
new file mode 100644
index 0000000..30b4c6c
--- /dev/null
+++ b/data/performers/faye-reagan.json
@@ -0,0 +1,36 @@
+{
+ "id": "PP4806",
+ "name": "Faye Reagan",
+ "aliases": [
+ "Faye B",
+ "Faye Raegan",
+ "Faye Regan",
+ "Faye Reagen"
+ ],
+ "gender": "Female",
+ "birthdate": "1988-09-19",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Redhead",
+ "eye_color": "-",
+ "height_cm": 163,
+ "measurements": "34C-28-36",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "American",
+ "MILF",
+ "Natural Tits",
+ "Redhead",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/f/faye_reagan.jpg",
+ "url": "https://www.pornpics.com/pornstars/faye-reagan/",
+ "stats": {
+ "total_galleries": 549
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/faye-reagan/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/fc0ebcbe-2885-43d5-a330-cd30ebbe1aef/performer.json b/data/performers/fc0ebcbe-2885-43d5-a330-cd30ebbe1aef/performer.json
new file mode 100644
index 0000000..58f1ab1
--- /dev/null
+++ b/data/performers/fc0ebcbe-2885-43d5-a330-cd30ebbe1aef/performer.json
@@ -0,0 +1,18 @@
+{
+ "id": "fc0ebcbe-2885-43d5-a330-cd30ebbe1aef",
+ "name": "Angelika Vrgoddess",
+ "url": "https://theporndb.net/performer/fc0ebcbe-2885-43d5-a330-cd30ebbe1aef",
+ "aliases": "[]",
+ "gender": "Unknown",
+ "birthdate": null,
+ "ethnicity": null,
+ "hair_color": null,
+ "eye_color": null,
+ "height_cm": null,
+ "measurements": null,
+ "nationality": "Unknown",
+ "country_code": null,
+ "tags": null,
+ "source": "TPDB",
+ "last_updated": "2025-10-27T00:31:26.691665"
+}
\ No newline at end of file
diff --git a/data/performers/j-mac.json b/data/performers/j-mac.json
new file mode 100644
index 0000000..c5ea452
--- /dev/null
+++ b/data/performers/j-mac.json
@@ -0,0 +1,32 @@
+{
+ "id": "PP21083",
+ "name": "J Mac",
+ "aliases": [
+ "Jmac"
+ ],
+ "gender": "Male",
+ "birthdate": "1985-03-12",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": 185,
+ "measurements": "",
+ "breast_type": "",
+ "tags": [
+ "American",
+ "Brunette",
+ "Tattoo",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/j/j_mac.jpg",
+ "url": "https://www.pornpics.com/pornstars/j-mac/",
+ "stats": {
+ "total_galleries": 2277
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/j-mac/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/johnny-sins.json b/data/performers/johnny-sins.json
new file mode 100644
index 0000000..39cebcd
--- /dev/null
+++ b/data/performers/johnny-sins.json
@@ -0,0 +1,36 @@
+{
+ "id": "PP21647",
+ "name": "Johnny Sins",
+ "aliases": [
+ "Jonny Sins",
+ "Johnny Sinns",
+ "Johnny Sinn",
+ "Johny Sins",
+ "Jhonny Sins"
+ ],
+ "gender": "Male",
+ "birthdate": "1978-12-31",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": 183,
+ "measurements": "",
+ "breast_type": "",
+ "tags": [
+ "American",
+ "Bald",
+ "Brunette",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/j/johnny_sins.jpg",
+ "url": "https://www.pornpics.com/pornstars/johnny-sins/",
+ "stats": {
+ "total_galleries": 2081
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/johnny-sins/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/madison-scott.json b/data/performers/madison-scott.json
new file mode 100644
index 0000000..0c7ff9f
--- /dev/null
+++ b/data/performers/madison-scott.json
@@ -0,0 +1,38 @@
+{
+ "id": "PP899",
+ "name": "Madison Scott",
+ "aliases": [
+ "Madison Scot"
+ ],
+ "gender": "Female",
+ "birthdate": "1988-07-13",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Blonde",
+ "eye_color": "-",
+ "height_cm": 155,
+ "measurements": "32DD-20-26",
+ "breast_type": "Fake Tits",
+ "tags": [
+ "American",
+ "Big Tits",
+ "Blonde",
+ "Fake Tits",
+ "MILF",
+ "Petite",
+ "Short",
+ "Skinny",
+ "Tattoo",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/m/madison_scott.jpg",
+ "url": "https://www.pornpics.com/pornstars/madison-scott/",
+ "stats": {
+ "total_galleries": 385
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/madison-scott/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/mia-split.json b/data/performers/mia-split.json
new file mode 100644
index 0000000..51bcce9
--- /dev/null
+++ b/data/performers/mia-split.json
@@ -0,0 +1,32 @@
+{
+ "id": "PP17020",
+ "name": "Mia Split",
+ "aliases": [],
+ "gender": "Female",
+ "birthdate": "",
+ "country": "Russian Federation",
+ "nationality": "Russian",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": null,
+ "measurements": "??-??-??",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "Brunette",
+ "Natural Tits",
+ "Petite",
+ "Russian",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/m/mia_split.jpg",
+ "url": "https://www.pornpics.com/pornstars/mia-split/",
+ "stats": {
+ "total_galleries": 73
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/mia-split/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/monique-alexander.json b/data/performers/monique-alexander.json
new file mode 100644
index 0000000..1e9c6b9
--- /dev/null
+++ b/data/performers/monique-alexander.json
@@ -0,0 +1,40 @@
+{
+ "id": "PP4988",
+ "name": "Monique Alexander",
+ "aliases": [
+ "Monique Alexandre",
+ "Savannah Moore",
+ "Briana Burke",
+ "Monique Alex"
+ ],
+ "gender": "Female",
+ "birthdate": "1982-05-26",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Redhead",
+ "eye_color": "-",
+ "height_cm": 165,
+ "measurements": "32C-24-34",
+ "breast_type": "Fake Tits",
+ "tags": [
+ "American",
+ "Fake Tits",
+ "MILF",
+ "Portuguese",
+ "Redhead",
+ "Skinny",
+ "Tattoo",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/m/monique_alexander.jpg",
+ "url": "https://www.pornpics.com/pornstars/monique-alexander/",
+ "stats": {
+ "total_galleries": 1017
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/monique-alexander/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/riley-reid.json b/data/performers/riley-reid.json
new file mode 100644
index 0000000..054fb94
--- /dev/null
+++ b/data/performers/riley-reid.json
@@ -0,0 +1,38 @@
+{
+ "id": "PP4373",
+ "name": "Riley Reid",
+ "aliases": [
+ "Riley Reed",
+ "Riley Ried",
+ "Paige Riley",
+ "Riley Reia",
+ "Reily Reid"
+ ],
+ "gender": "Female",
+ "birthdate": "1991-07-09",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": 162,
+ "measurements": "34B-25-36",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "American",
+ "Brunette",
+ "Natural Tits",
+ "Tattoo",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/r/riley_reid.jpg",
+ "url": "https://www.pornpics.com/pornstars/riley-reid/",
+ "stats": {
+ "total_galleries": 1728
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/riley-reid/"
+ }
+}
\ No newline at end of file
diff --git a/data/performers/sasha-grey.json b/data/performers/sasha-grey.json
new file mode 100644
index 0000000..aa2a372
--- /dev/null
+++ b/data/performers/sasha-grey.json
@@ -0,0 +1,34 @@
+{
+ "id": "PP10802",
+ "name": "Sasha Grey",
+ "aliases": [
+ "Sasha Gray"
+ ],
+ "gender": "Female",
+ "birthdate": "1988-03-14",
+ "country": "United States",
+ "nationality": "American",
+ "ethnicity": "White",
+ "hair_color": "Brunette",
+ "eye_color": "-",
+ "height_cm": 170,
+ "measurements": "32B-26-31",
+ "breast_type": "Natural Tits",
+ "tags": [
+ "American",
+ "Brunette",
+ "Natural Tits",
+ "Skinny",
+ "Tiny Tits",
+ "White"
+ ],
+ "thumbnail": "https://cdni.pornpics.com/models/s/sasha_grey.jpg",
+ "url": "https://www.pornpics.com/pornstars/sasha-grey/",
+ "stats": {
+ "total_galleries": 371
+ },
+ "source": "PornPics",
+ "sources": {
+ "pornpics": "https://www.pornpics.com/pornstars/sasha-grey/"
+ }
+}
\ No newline at end of file
diff --git a/src/importer/__pycache__/cli.cpython-313.pyc b/src/importer/__pycache__/cli.cpython-313.pyc
index 6207513..cf28d7e 100644
Binary files a/src/importer/__pycache__/cli.cpython-313.pyc and b/src/importer/__pycache__/cli.cpython-313.pyc differ
diff --git a/src/importer/cli.py b/src/importer/cli.py
index df12305..a6d3e30 100644
--- a/src/importer/cli.py
+++ b/src/importer/cli.py
@@ -16,13 +16,14 @@ metadata refresh, and tag analytics with color-coded output.
Usage examples:
goondex import "https://www.pornpics.com/galleries/..."
goondex refresh-all
- goondex refresh-one "Gallery_Name"
- goondex validate-tags
- goondex tag-stats
+ goondex search-performer "Riley Reid"
+ goondex enrich-all
"""
import sys
import os
+import subprocess
+from pathlib import Path
# ───────────────────────────────────────────────
# Module imports
@@ -38,7 +39,6 @@ try:
except ImportError:
metadata_tools = None
-
# ───────────────────────────────────────────────
# COLOR DEFINITIONS
# ───────────────────────────────────────────────
@@ -53,7 +53,6 @@ class Colors:
def colorize(text, color):
- """Wrap text with ANSI color codes."""
return f"{color}{text}{Colors.RESET}"
@@ -61,18 +60,15 @@ def colorize(text, color):
# VERSION HANDLER
# ───────────────────────────────────────────────
def load_version():
- """Safely read version number from root VERSION file."""
try:
root_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../.."))
- version_file = os.path.join(root_dir, "VERSION")
- with open(version_file, "r", encoding="utf-8") as f:
+ with open(os.path.join(root_dir, "VERSION"), "r", encoding="utf-8") as f:
return f.read().strip()
except FileNotFoundError:
return "unknown"
def print_version():
- """Print Goondex version string."""
version = load_version()
print(colorize(f"Goondex v{version}", Colors.CYAN))
sys.exit(0)
@@ -88,11 +84,11 @@ def print_usage():
Usage:
goondex [args...]
-Commands:
+Gallery Commands:
import Import a new gallery from PornPics
refresh-all Refresh inferred tags for all galleries
refresh-one Refresh inferred tags for a single gallery
- validate-tags Validate YAML tag dictionaries for duplicates/conflicts
+ validate-tags Validate YAML tag dictionaries
tag-stats Generate frequency report for all tags
list List all available galleries
list-tags List tags for one gallery
@@ -102,16 +98,14 @@ Commands:
show-metadata Show metadata.json content
source set Set gallery source (single or all)
+Performer Commands:
+ search-performer "" Search or fetch performer metadata
+ enrich-all Sync all performer JSONs into SQLite
+
Flags:
-h, --help Show this help message
-v, --version Show current version
-
-Examples:
- goondex import "https://www.pornpics.com/galleries/example/"
- goondex refresh-one "20251020_2117_Mariella_Sun"
- goondex tag-stats
- goondex validate-tags
-""".strip())
+""")
# ───────────────────────────────────────────────
@@ -133,6 +127,43 @@ def main():
if cmd in ("--version", "-v", "version"):
print_version()
+ # ─────────────── PERFORMER COMMANDS
+ if cmd == "search-performer":
+ if not args:
+ print(colorize("[!] Usage: goondex search-performer \"\"", Colors.RED))
+ sys.exit(1)
+ subprocess.run(["python", "-m", "src.performers.search", *args])
+ return
+
+ elif cmd == "enrich-all":
+ print(colorize("[INFO] Syncing performer JSONs into SQLite…", Colors.CYAN))
+ subprocess.run(["python", "-m", "src.performers.sync.sync_json_to_sqlite"])
+ print(colorize("[OK] Performer enrichment complete.", Colors.GREEN))
+ return
+
+ # ─────────────── ENRICHMENT BRIDGE
+ elif cmd == "enrich-bridge":
+ limit = None
+ if args and args[0].isdigit():
+ limit = args[0]
+
+ print(colorize("[INFO] Launching Goondex Enrichment Bridge...", Colors.CYAN))
+ env = os.environ.copy()
+ env["PYTHONPATH"] = "src" # ensures the 'performers' package is found
+
+ try:
+ subprocess.run(
+ ["python", "-m", "performers.enrichment_bridge", *( [limit] if limit else [] )],
+ check=True,
+ env=env,
+ )
+ print(colorize("[OK] Bridge enrichment complete.", Colors.GREEN))
+ except subprocess.CalledProcessError as e:
+ print(colorize(f"[ERROR] Enrichment bridge failed with code {e.returncode}", Colors.RED))
+ except Exception as e:
+ print(colorize(f"[ERROR] Enrichment bridge failed: {e}", Colors.RED))
+ return
+
# ─────────────── IMPORT GALLERY
if cmd == "import":
if not args:
@@ -212,7 +243,6 @@ def main():
# ─────────────── ALL OTHER COMMANDS
else:
- # Explicit command map for all supported operations
command_map = {
"list": tag_gallery.list_galleries,
"list-tags": tag_gallery.list_tags,
diff --git a/src/importer/db/performers.db b/src/importer/db/performers.db
index 646654c..d5ecd1e 100644
Binary files a/src/importer/db/performers.db and b/src/importer/db/performers.db differ
diff --git a/src/importer/pornpics_bridge.py b/src/importer/pornpics_bridge.py
new file mode 100644
index 0000000..9cb1685
--- /dev/null
+++ b/src/importer/pornpics_bridge.py
@@ -0,0 +1,215 @@
+#!/usr/bin/env python3
+"""
+pornpics_bridge.py
+─────────────────────────────────────────────
+Scraper bridge for PornPics performer pages.
+Fetches performer metadata when TPDB data
+is unavailable or incomplete.
+
+Now writes files as:
+ data/performers/riley-reid.json
+
+If a file already exists, only missing fields are filled in.
+"""
+
+import re
+import json
+import hashlib
+import requests
+from bs4 import BeautifulSoup
+from urllib.parse import quote_plus
+from pathlib import Path
+
+HEADERS = {
+ "User-Agent": (
+ "Mozilla/5.0 (X11; Linux x86_64) "
+ "AppleWebKit/537.36 (KHTML, like Gecko) "
+ "Chrome/122.0 Safari/537.36"
+ )
+}
+
+# ─────────────────────────────────────────────
+# Helpers
+# ─────────────────────────────────────────────
+def _numeric_id(name: str) -> str:
+ """Fallback short numeric performer ID like P000123."""
+ h = int(hashlib.sha1(name.encode("utf-8")).hexdigest(), 16) % 1_000_000
+ return f"P{h:06d}"
+
+
+def _safe_filename(name: str) -> str:
+ """Normalize a performer name to a safe lowercase filename."""
+ return re.sub(r"[^a-z0-9\-]+", "-", name.lower().strip()).strip("-")
+
+
+def _cache_thumbnail(name: str, image_url: str):
+ """Download and cache performer thumbnail image."""
+ try:
+ if not image_url:
+ return None
+ base = Path(__file__).resolve().parents[2] / "data" / "faces"
+ folder = base / name.lower().replace(" ", "_")
+ folder.mkdir(parents=True, exist_ok=True)
+ dest = folder / "thumbnail.jpg"
+ r = requests.get(image_url, headers=HEADERS, timeout=10)
+ if r.status_code == 200:
+ dest.write_bytes(r.content)
+ print(f"[🖼️] Cached thumbnail → {dest}")
+ return str(dest)
+ except Exception as e:
+ print(f"[!] Thumbnail cache failed: {e}")
+ return None
+
+
+def _merge_performer(existing: dict, new: dict) -> dict:
+ """Merge new scraper data into existing JSON, preserving old values."""
+ merged = existing.copy()
+ for key, val in new.items():
+ if isinstance(val, dict):
+ merged[key] = _merge_performer(existing.get(key, {}), val)
+ elif isinstance(val, list):
+ # merge lists, avoiding duplicates
+ merged[key] = sorted(set(existing.get(key, []) + val))
+ else:
+ if not existing.get(key) or existing.get(key) == "-":
+ merged[key] = val
+ return merged
+
+
+# ─────────────────────────────────────────────
+# Main Scraper
+# ─────────────────────────────────────────────
+def fetch_pornpics_profile(name: str):
+ """Fetch performer profile metadata from PornPics."""
+ try:
+ slug = quote_plus(name.lower().replace(" ", "-"))
+ url = f"https://www.pornpics.com/pornstars/{slug}/"
+ r = requests.get(url, headers=HEADERS, timeout=10)
+ if r.status_code != 200:
+ print(f"[!] PornPics returned {r.status_code}")
+ return None
+
+ soup = BeautifulSoup(r.text, "html.parser")
+
+ # --- Display name ---
+ display_el = soup.select_one("div.card-title h2")
+ display_name = display_el.get_text(strip=True) if display_el else name
+ display_name = display_name.replace("Nude Pics", "").strip()
+
+ # --- Performer numeric ID ---
+ id_match = re.search(r'PP_PROFILE_ID\s*=\s*"(\d+)"', r.text)
+ performer_id = f"PP{id_match.group(1)}" if id_match else _numeric_id(display_name)
+
+ # --- Thumbnail ---
+ img_tag = soup.select_one("div.card-logo img")
+ image_url = img_tag["src"] if img_tag and "src" in img_tag.attrs else None
+
+ # --- Gallery count ---
+ total_galleries = 0
+ count_div = soup.select_one("div.card-galleries-count")
+ if count_div:
+ text = count_div.get_text(strip=True).replace(",", "")
+ m = re.search(r"(\d+)", text)
+ if m:
+ total_galleries = int(m.group(1))
+ if not total_galleries:
+ # fallback
+ text = soup.get_text(" ", strip=True)
+ m = re.search(r"(\d{2,5})\s+(?:Galleries|Photos|Albums)", text, re.I)
+ if m:
+ total_galleries = int(m.group(1))
+
+ # --- Metadata info items ---
+ bio = {}
+ for item in soup.select("div.card-additional-info .item"):
+ label = item.select_one(".label")
+ value = item.select_one(".value")
+ if not (label and value):
+ continue
+ key = label.get_text(strip=True).rstrip(":").lower()
+ val = value.get_text(strip=True)
+ bio[key] = val
+
+ # --- Parse key fields ---
+ aliases = [a.strip() for a in bio.get("aliases", "").split(",") if a.strip()]
+ gender = bio.get("gender", "-")
+ country = bio.get("country of birth", "-")
+ nationality = bio.get("nationality", "-")
+ ethnicity = bio.get("ethnicity", "-")
+ birthday = bio.get("birthday", "-")
+ hair_color = bio.get("hair color", "-")
+ eye_color = bio.get("eye color", "-")
+ height = bio.get("height", "-")
+ breast_size = bio.get("breast size", "-")
+ breast_type = bio.get("breast type", "-")
+ tags = [t.strip() for t in bio.get("categories", "").split(",") if t.strip()]
+
+ def parse_height_cm(val: str):
+ m = re.search(r"(\d{2,3})\s*cm", val)
+ return int(m.group(1)) if m else None
+
+ # --- Construct structured performer record ---
+ performer = {
+ "id": performer_id,
+ "name": display_name,
+ "aliases": aliases,
+ "gender": gender,
+ "birthdate": birthday,
+ "country": country,
+ "nationality": nationality,
+ "ethnicity": ethnicity,
+ "hair_color": hair_color,
+ "eye_color": eye_color,
+ "height_cm": parse_height_cm(height),
+ "measurements": breast_size,
+ "breast_type": breast_type,
+ "tags": tags,
+ "thumbnail": image_url,
+ "url": url,
+ "stats": {"total_galleries": total_galleries},
+ "source": "PornPics",
+ "sources": {"pornpics": url},
+ }
+
+ # --- Cache thumbnail ---
+ _cache_thumbnail(display_name, image_url)
+
+ # --- Write JSON (merge-safe) ---
+ base = Path(__file__).resolve().parents[2] / "data" / "performers"
+ base.mkdir(parents=True, exist_ok=True)
+
+ safe_name = _safe_filename(display_name)
+ json_path = base / f"{safe_name}.json"
+
+ if json_path.exists():
+ try:
+ existing = json.loads(json_path.read_text(encoding="utf-8"))
+ performer = _merge_performer(existing, performer)
+ print(f"[♻️] Updated existing performer → {json_path.name}")
+ except Exception as e:
+ print(f"[!] Failed to merge existing file: {e}")
+
+ json_path.write_text(
+ json.dumps(performer, indent=2, ensure_ascii=False),
+ encoding="utf-8",
+ )
+
+ print(f"[💾] Cached performer JSON → {json_path}")
+
+ return performer
+
+ except Exception as e:
+ print(f"[!] PornPics fetch failed: {e}")
+ return None
+
+
+# ─────────────────────────────────────────────
+# CLI Entry (for testing)
+# ─────────────────────────────────────────────
+if __name__ == "__main__":
+ import sys
+ target = sys.argv[1] if len(sys.argv) > 1 else "Riley Reid"
+ print(f"[🔎] Fetching PornPics data for: {target}")
+ data = fetch_pornpics_profile(target)
+ if data:
+ print(json.dumps(data, indent=2, ensure_ascii=False))
diff --git a/src/importer/reports/tag_stats.json b/src/importer/reports/tag_stats.json
index 7f49210..1bd0de5 100644
--- a/src/importer/reports/tag_stats.json
+++ b/src/importer/reports/tag_stats.json
@@ -1,23 +1,72 @@
{
- "School Uniform": 12,
+ "Pussy": 22,
+ "School Uniform": 14,
+ "Brunette": 14,
+ "Ass": 12,
+ "Petite": 11,
+ "Teen": 11,
+ "Fucking": 11,
+ "Big Tits": 11,
+ "Hot Naked Women": 9,
+ "Beautiful": 9,
+ "Blowjob": 9,
+ "Hairy": 9,
+ "Pornstar": 9,
"Pantyhose Skirt": 7,
+ "Hardcore": 7,
+ "Teen Schoolgirl": 6,
"Pantyhose Ass": 6,
+ "Mature": 6,
+ "Natural": 6,
+ "Natural Look": 6,
"Pantyhose Pussy": 5,
- "Teen Schoolgirl": 5,
- "Hot Naked Women": 5,
+ "Amateur": 5,
+ "Skinny": 5,
"Teen Pantyhose": 4,
+ "Ass Spread": 4,
+ "Lesbian": 4,
+ "Dress": 4,
+ "Handjob": 4,
+ "Cumshot": 4,
+ "Cowgirl": 4,
+ "Doggystyle": 4,
+ "MILF": 4,
"Solo Masturbation": 3,
"Schoolgirl Skirt": 3,
"Amateur Pantyhose": 3,
"Topless": 3,
- "Ass Spread": 3,
"Hot Naked Girls": 3,
+ "Amateur Hairy Pussy": 3,
+ "Hairy Teen Pussy": 3,
+ "Best Pussy": 3,
+ "Upskirt No Panties": 3,
+ "Anal": 3,
+ "Anal Fetish": 3,
+ "Facial": 3,
+ "Panties": 3,
+ "Threesome": 3,
+ "Tight Dress": 3,
+ "Big Cock": 3,
+ "Interracial": 3,
+ "POV": 3,
+ "Pussy Fuck": 3,
+ "Uniform": 3,
+ "Uniform Fetish": 3,
+ "Stockings": 3,
"Hairy Amateur": 2,
+ "Office": 2,
"Redhead Ass": 2,
+ "Over 50": 2,
+ "Mom Pussy": 2,
+ "Gaping Pussy": 2,
"Big Natural Tits": 2,
"Amateur Teen": 2,
+ "Busty": 2,
"Redhead Pantyhose": 2,
"Schoolgirl Upskirt": 2,
+ "Teen Stockings": 2,
+ "Beautiful Pussy": 2,
+ "Wet Pussy Close Up": 2,
"Teen Masturbation": 2,
"Pantyhose Legs": 2,
"Big Tits Masturbation": 2,
@@ -25,10 +74,40 @@
"Spread Legs": 2,
"Vagina": 2,
"Pantyhose Feet": 2,
- "Amateur Hairy Pussy": 2,
"Big Tits Hairy Pussy": 2,
- "Best Pussy": 2,
+ "Hairy Teen Spreading": 2,
"Teen Panties": 2,
+ "Bent Over": 2,
+ "Teen Anal": 2,
+ "Beautiful Hairy": 2,
+ "Short Skirt No Panties": 2,
+ "Dick": 2,
+ "Beautiful Blowjob": 2,
+ "Brunette Teen": 2,
+ "Mom Boy": 2,
+ "Mom Son": 2,
+ "Brunette Hairy Pussy": 2,
+ "Fetish": 2,
+ "High Heels": 2,
+ "Penetration": 2,
+ "Short Skirt High Heels": 2,
+ "Skirt": 2,
+ "Solo": 2,
+ "Outdoor": 2,
+ "Skinny Small Tits": 2,
+ "BBC": 2,
+ "Big Black Cock": 2,
+ "Doggystyle Anal": 2,
+ "Interracial Anal": 2,
+ "Monster Cock": 2,
+ "Summer Dress": 2,
+ "Hairy Pussy Fuck": 2,
+ "Lingerie": 2,
+ "POV Handjob": 2,
+ "Model": 2,
+ "Tight Ass": 2,
+ "Cheating Wife": 2,
+ "Blonde": 2,
"Blonde Masturbating": 1,
"Amateur Undressing": 1,
"Amateur PAWG": 1,
@@ -36,13 +115,10 @@
"Big Ass Redhead": 1,
"Hairy Redhead": 1,
"Hairy Redhead Pussy": 1,
- "Office": 1,
"Redhead Pussy": 1,
"Hairy MILF": 1,
"Mature Hairy Pussy": 1,
- "Over 50": 1,
"Mature Blonde": 1,
- "Mom Pussy": 1,
"Hairy Mature": 1,
"Mom Masturbating": 1,
"Mature Mom": 1,
@@ -55,7 +131,6 @@
"Sexy Black Women": 1,
"Ebony Pussy": 1,
"Big Tits Nipples": 1,
- "Gaping Pussy": 1,
"Monster Tits": 1,
"Amateur College": 1,
"Short Hair Brunette": 1,
@@ -66,19 +141,15 @@
"Teen Babe": 1,
"Redhead Upskirt": 1,
"Redhead Big Tits": 1,
- "Busty": 1,
"Redhead Glasses": 1,
"Cleavage": 1,
"White Panties": 1,
- "Teen Stockings": 1,
"Teen Upskirt Panties": 1,
"Beautiful Stockings": 1,
"Amateur Stockings": 1,
"Sexy Pornstars": 1,
- "Beautiful Pussy": 1,
"Amateur Anal": 1,
"Anal Masturbation": 1,
- "Wet Pussy Close Up": 1,
"Teen Pussy Close Up": 1,
"Teen Nudist": 1,
"Skinny Teen": 1,
@@ -133,8 +204,6 @@
"Sensual": 1,
"Asian Schoolgirl": 1,
"Hairy Babe": 1,
- "Hairy Teen Pussy": 1,
- "Hairy Teen Spreading": 1,
"Beautiful Babe": 1,
"B Cup Tits": 1,
"Ginger": 1,
@@ -142,14 +211,12 @@
"Big Tits College": 1,
"Big Tits Lingerie": 1,
"Perfect Natural Tits": 1,
- "Bent Over": 1,
"Tits And Pussy": 1,
"Blonde Pussy": 1,
"Blonde Big Tits": 1,
"Pornstar Pussy": 1,
"Teen Deepthroat": 1,
"Throat Fuck": 1,
- "Teen Anal": 1,
"Slutty Teen": 1,
"Teen Big Cock": 1,
"Teen Cumshot": 1,
@@ -158,7 +225,6 @@
"Wide Hips Thick Thighs": 1,
"Chubby Hairy": 1,
"Hairy Close Up": 1,
- "Beautiful Hairy": 1,
"Hot Teen": 1,
"Beautiful Teen": 1,
"Bubble Butt": 1,
@@ -167,10 +233,7 @@
"Huge Ass": 1,
"Leather Skirt": 1,
"Beautiful Ass": 1,
- "Upskirt No Panties": 1,
- "Short Skirt No Panties": 1,
"Nylon Pussy": 1,
- "Dick": 1,
"Brazilian Hairy Pussy": 1,
"Brazilian Teen": 1,
"Brazilian Anal": 1,
@@ -186,5 +249,132 @@
"Big Pussy": 1,
"See Through Panties": 1,
"Loose Pussy": 1,
- "Teen Dildo": 1
+ "Teen Dildo": 1,
+ "Lesbian Facesitting": 1,
+ "Lesbian Scissoring": 1,
+ "Nice Pussy": 1,
+ "Redhead": 1,
+ "Redhead Lesbian": 1,
+ "Ukraine Pussy": 1,
+ "Ukrainian": 1,
+ "Wet Teen Pussy": 1,
+ "Fit": 1,
+ "Friends Mom": 1,
+ "Curvy": 1,
+ "Double Anal": 1,
+ "Hairy Upskirt": 1,
+ "Latex": 1,
+ "Latex Fetish": 1,
+ "Sexy Dress": 1,
+ "Bent Over Ass": 1,
+ "Nude": 1,
+ "PAWG Solo": 1,
+ "Sexy Ass": 1,
+ "Beautiful Granny": 1,
+ "GILF": 1,
+ "Granny Handjob": 1,
+ "Granny Slut": 1,
+ "Mature Boy": 1,
+ "Sexy GILF": 1,
+ "Clothed Fuck": 1,
+ "Russian": 1,
+ "Russian Teen": 1,
+ "Shorts": 1,
+ "Skinny Teen Fuck": 1,
+ "Small Tits Fuck": 1,
+ "Teen Cum": 1,
+ "Teen Facesitting": 1,
+ "Teen Fuck": 1,
+ "Teen Hardcore": 1,
+ "Big Hairy Pussy": 1,
+ "Extremely Hairy Pussy": 1,
+ "Hairy Bush": 1,
+ "Natural Hairy": 1,
+ "Brunette Natural Tits": 1,
+ "Reverse Cowgirl": 1,
+ "Trimmed Pussy": 1,
+ "BBC Anal": 1,
+ "Big Black Dick": 1,
+ "Big Cock Blowjob": 1,
+ "Big Dick Anal": 1,
+ "Pool": 1,
+ "Hairy Armpits": 1,
+ "Hairy Brunette": 1,
+ "Hairy Panties": 1,
+ "Romanian": 1,
+ "Upskirt Panties": 1,
+ "Hairy Asshole": 1,
+ "Hairy MILF Fuck": 1,
+ "MILF Fuck": 1,
+ "Perfect": 1,
+ "Perfect Body": 1,
+ "Pussy Spreading": 1,
+ "Skinny Girl Fat Pussy": 1,
+ "High Heels Fuck": 1,
+ "Sexy Blowjob": 1,
+ "Underwear": 1,
+ "Cum On Face": 1,
+ "Petite Facial": 1,
+ "Money": 1,
+ "Classroom": 1,
+ "College Pussy": 1,
+ "English": 1,
+ "Beautiful Mature": 1,
+ "Mature Older Women": 1,
+ "Mature Pussy": 1,
+ "Mature Spreading": 1,
+ "Mature Undressing": 1,
+ "Older Women": 1,
+ "Sexy Older Women": 1,
+ "Brunette Ass": 1,
+ "Cute Face": 1,
+ "Cute Hairy": 1,
+ "Hairy Erotica": 1,
+ "Caught Masturbating": 1,
+ "Skinny BBC": 1,
+ "Skinny Interracial": 1,
+ "Close Up Fuck": 1,
+ "Juicy Pussy": 1,
+ "Meaty Pussy": 1,
+ "Teen Handjob": 1,
+ "All Over 40": 1,
+ "Bikini Blowjob": 1,
+ "MILF Bikini": 1,
+ "MILF Stockings": 1,
+ "Petite Stockings": 1,
+ "Sexy MILF": 1,
+ "Wife Blowjob": 1,
+ "Stockings Spread": 1,
+ "Latina Anal": 1,
+ "MILF Anal": 1,
+ "MILF DP": 1,
+ "Petite Anal": 1,
+ "Sexy Anal": 1,
+ "Blonde Shemale": 1,
+ "Shemale Ass": 1,
+ "Shemale Fucks Female": 1,
+ "Shemale Fucks Girl": 1,
+ "Shemale Lesbian": 1,
+ "Shemale On Female": 1,
+ "Shemale Pantyhose": 1,
+ "Shemale Threesome": 1,
+ "Horny": 1,
+ "Riding": 1,
+ "Slut": 1,
+ "Sneakers": 1,
+ "Oral": 1,
+ "Sexy Latina": 1,
+ "Teen Lesbian": 1,
+ "Glamour": 1,
+ "Blindfold Surprise": 1,
+ "Cum On Pussy": 1,
+ "Cum On Stockings": 1,
+ "Footjob": 1,
+ "Teen Footjob": 1,
+ "Teen Natural Tits": 1,
+ "Beautiful MILF": 1,
+ "Bride": 1,
+ "MILF Pussy": 1,
+ "Sucking Cock": 1,
+ "Teen Stepdaughter": 1
}
\ No newline at end of file
diff --git a/src/importer/reports/tag_stats_sorted.txt b/src/importer/reports/tag_stats_sorted.txt
index eb82054..d9ffc7a 100644
--- a/src/importer/reports/tag_stats_sorted.txt
+++ b/src/importer/reports/tag_stats_sorted.txt
@@ -1,22 +1,71 @@
-School Uniform: 12
+Pussy: 22
+School Uniform: 14
+Brunette: 14
+Ass: 12
+Petite: 11
+Teen: 11
+Fucking: 11
+Big Tits: 11
+Hot Naked Women: 9
+Beautiful: 9
+Blowjob: 9
+Hairy: 9
+Pornstar: 9
Pantyhose Skirt: 7
+Hardcore: 7
+Teen Schoolgirl: 6
Pantyhose Ass: 6
+Mature: 6
+Natural: 6
+Natural Look: 6
Pantyhose Pussy: 5
-Teen Schoolgirl: 5
-Hot Naked Women: 5
+Amateur: 5
+Skinny: 5
Teen Pantyhose: 4
+Ass Spread: 4
+Lesbian: 4
+Dress: 4
+Handjob: 4
+Cumshot: 4
+Cowgirl: 4
+Doggystyle: 4
+MILF: 4
Solo Masturbation: 3
Schoolgirl Skirt: 3
Amateur Pantyhose: 3
Topless: 3
-Ass Spread: 3
Hot Naked Girls: 3
+Amateur Hairy Pussy: 3
+Hairy Teen Pussy: 3
+Best Pussy: 3
+Upskirt No Panties: 3
+Anal: 3
+Anal Fetish: 3
+Facial: 3
+Panties: 3
+Threesome: 3
+Tight Dress: 3
+Big Cock: 3
+Interracial: 3
+POV: 3
+Pussy Fuck: 3
+Uniform: 3
+Uniform Fetish: 3
+Stockings: 3
Hairy Amateur: 2
+Office: 2
Redhead Ass: 2
+Over 50: 2
+Mom Pussy: 2
+Gaping Pussy: 2
Big Natural Tits: 2
Amateur Teen: 2
+Busty: 2
Redhead Pantyhose: 2
Schoolgirl Upskirt: 2
+Teen Stockings: 2
+Beautiful Pussy: 2
+Wet Pussy Close Up: 2
Teen Masturbation: 2
Pantyhose Legs: 2
Big Tits Masturbation: 2
@@ -24,10 +73,40 @@ MILF Masturbation: 2
Spread Legs: 2
Vagina: 2
Pantyhose Feet: 2
-Amateur Hairy Pussy: 2
Big Tits Hairy Pussy: 2
-Best Pussy: 2
+Hairy Teen Spreading: 2
Teen Panties: 2
+Bent Over: 2
+Teen Anal: 2
+Beautiful Hairy: 2
+Short Skirt No Panties: 2
+Dick: 2
+Beautiful Blowjob: 2
+Brunette Teen: 2
+Mom Boy: 2
+Mom Son: 2
+Brunette Hairy Pussy: 2
+Fetish: 2
+High Heels: 2
+Penetration: 2
+Short Skirt High Heels: 2
+Skirt: 2
+Solo: 2
+Outdoor: 2
+Skinny Small Tits: 2
+BBC: 2
+Big Black Cock: 2
+Doggystyle Anal: 2
+Interracial Anal: 2
+Monster Cock: 2
+Summer Dress: 2
+Hairy Pussy Fuck: 2
+Lingerie: 2
+POV Handjob: 2
+Model: 2
+Tight Ass: 2
+Cheating Wife: 2
+Blonde: 2
Blonde Masturbating: 1
Amateur Undressing: 1
Amateur PAWG: 1
@@ -35,13 +114,10 @@ Big Ass Pussy: 1
Big Ass Redhead: 1
Hairy Redhead: 1
Hairy Redhead Pussy: 1
-Office: 1
Redhead Pussy: 1
Hairy MILF: 1
Mature Hairy Pussy: 1
-Over 50: 1
Mature Blonde: 1
-Mom Pussy: 1
Hairy Mature: 1
Mom Masturbating: 1
Mature Mom: 1
@@ -54,7 +130,6 @@ Ebony Ass Pussy: 1
Sexy Black Women: 1
Ebony Pussy: 1
Big Tits Nipples: 1
-Gaping Pussy: 1
Monster Tits: 1
Amateur College: 1
Short Hair Brunette: 1
@@ -65,19 +140,15 @@ Schoolgirl Lingerie: 1
Teen Babe: 1
Redhead Upskirt: 1
Redhead Big Tits: 1
-Busty: 1
Redhead Glasses: 1
Cleavage: 1
White Panties: 1
-Teen Stockings: 1
Teen Upskirt Panties: 1
Beautiful Stockings: 1
Amateur Stockings: 1
Sexy Pornstars: 1
-Beautiful Pussy: 1
Amateur Anal: 1
Anal Masturbation: 1
-Wet Pussy Close Up: 1
Teen Pussy Close Up: 1
Teen Nudist: 1
Skinny Teen: 1
@@ -132,8 +203,6 @@ Beautiful Asian: 1
Sensual: 1
Asian Schoolgirl: 1
Hairy Babe: 1
-Hairy Teen Pussy: 1
-Hairy Teen Spreading: 1
Beautiful Babe: 1
B Cup Tits: 1
Ginger: 1
@@ -141,14 +210,12 @@ Red Lips: 1
Big Tits College: 1
Big Tits Lingerie: 1
Perfect Natural Tits: 1
-Bent Over: 1
Tits And Pussy: 1
Blonde Pussy: 1
Blonde Big Tits: 1
Pornstar Pussy: 1
Teen Deepthroat: 1
Throat Fuck: 1
-Teen Anal: 1
Slutty Teen: 1
Teen Big Cock: 1
Teen Cumshot: 1
@@ -157,7 +224,6 @@ Hairy Vagina: 1
Wide Hips Thick Thighs: 1
Chubby Hairy: 1
Hairy Close Up: 1
-Beautiful Hairy: 1
Hot Teen: 1
Beautiful Teen: 1
Bubble Butt: 1
@@ -166,10 +232,7 @@ Nice Ass: 1
Huge Ass: 1
Leather Skirt: 1
Beautiful Ass: 1
-Upskirt No Panties: 1
-Short Skirt No Panties: 1
Nylon Pussy: 1
-Dick: 1
Brazilian Hairy Pussy: 1
Brazilian Teen: 1
Brazilian Anal: 1
@@ -186,3 +249,130 @@ Big Pussy: 1
See Through Panties: 1
Loose Pussy: 1
Teen Dildo: 1
+Lesbian Facesitting: 1
+Lesbian Scissoring: 1
+Nice Pussy: 1
+Redhead: 1
+Redhead Lesbian: 1
+Ukraine Pussy: 1
+Ukrainian: 1
+Wet Teen Pussy: 1
+Fit: 1
+Friends Mom: 1
+Curvy: 1
+Double Anal: 1
+Hairy Upskirt: 1
+Latex: 1
+Latex Fetish: 1
+Sexy Dress: 1
+Bent Over Ass: 1
+Nude: 1
+PAWG Solo: 1
+Sexy Ass: 1
+Beautiful Granny: 1
+GILF: 1
+Granny Handjob: 1
+Granny Slut: 1
+Mature Boy: 1
+Sexy GILF: 1
+Clothed Fuck: 1
+Russian: 1
+Russian Teen: 1
+Shorts: 1
+Skinny Teen Fuck: 1
+Small Tits Fuck: 1
+Teen Cum: 1
+Teen Facesitting: 1
+Teen Fuck: 1
+Teen Hardcore: 1
+Big Hairy Pussy: 1
+Extremely Hairy Pussy: 1
+Hairy Bush: 1
+Natural Hairy: 1
+Brunette Natural Tits: 1
+Reverse Cowgirl: 1
+Trimmed Pussy: 1
+BBC Anal: 1
+Big Black Dick: 1
+Big Cock Blowjob: 1
+Big Dick Anal: 1
+Pool: 1
+Hairy Armpits: 1
+Hairy Brunette: 1
+Hairy Panties: 1
+Romanian: 1
+Upskirt Panties: 1
+Hairy Asshole: 1
+Hairy MILF Fuck: 1
+MILF Fuck: 1
+Perfect: 1
+Perfect Body: 1
+Pussy Spreading: 1
+Skinny Girl Fat Pussy: 1
+High Heels Fuck: 1
+Sexy Blowjob: 1
+Underwear: 1
+Cum On Face: 1
+Petite Facial: 1
+Money: 1
+Classroom: 1
+College Pussy: 1
+English: 1
+Beautiful Mature: 1
+Mature Older Women: 1
+Mature Pussy: 1
+Mature Spreading: 1
+Mature Undressing: 1
+Older Women: 1
+Sexy Older Women: 1
+Brunette Ass: 1
+Cute Face: 1
+Cute Hairy: 1
+Hairy Erotica: 1
+Caught Masturbating: 1
+Skinny BBC: 1
+Skinny Interracial: 1
+Close Up Fuck: 1
+Juicy Pussy: 1
+Meaty Pussy: 1
+Teen Handjob: 1
+All Over 40: 1
+Bikini Blowjob: 1
+MILF Bikini: 1
+MILF Stockings: 1
+Petite Stockings: 1
+Sexy MILF: 1
+Wife Blowjob: 1
+Stockings Spread: 1
+Latina Anal: 1
+MILF Anal: 1
+MILF DP: 1
+Petite Anal: 1
+Sexy Anal: 1
+Blonde Shemale: 1
+Shemale Ass: 1
+Shemale Fucks Female: 1
+Shemale Fucks Girl: 1
+Shemale Lesbian: 1
+Shemale On Female: 1
+Shemale Pantyhose: 1
+Shemale Threesome: 1
+Horny: 1
+Riding: 1
+Slut: 1
+Sneakers: 1
+Oral: 1
+Sexy Latina: 1
+Teen Lesbian: 1
+Glamour: 1
+Blindfold Surprise: 1
+Cum On Pussy: 1
+Cum On Stockings: 1
+Footjob: 1
+Teen Footjob: 1
+Teen Natural Tits: 1
+Beautiful MILF: 1
+Bride: 1
+MILF Pussy: 1
+Sucking Cock: 1
+Teen Stepdaughter: 1
diff --git a/src/importer/secrets/tpdb_api_key.txt b/src/importer/secrets/tpdb_api_key.txt
new file mode 100644
index 0000000..d15f550
--- /dev/null
+++ b/src/importer/secrets/tpdb_api_key.txt
@@ -0,0 +1 @@
+ROhX6BrycQCKkMYjleW4GHsBXxJqAw9h8RjF5lBH6fe868a7
diff --git a/src/ml/__pycache__/tagging.cpython-313.pyc b/src/ml/__pycache__/tagging.cpython-313.pyc
index da5f0e8..f6fcbfe 100644
Binary files a/src/ml/__pycache__/tagging.cpython-313.pyc and b/src/ml/__pycache__/tagging.cpython-313.pyc differ
diff --git a/src/ml/facecrop/trainer.py b/src/ml/facecrop/trainer.py
index 8408f52..f9994bc 100644
--- a/src/ml/facecrop/trainer.py
+++ b/src/ml/facecrop/trainer.py
@@ -1,43 +1,196 @@
#!/usr/bin/env python3
"""
-trainer.py
------------
-Batch face verification and performer labeling loop.
-Scans a folder of uncategorized face crops, calls the verifier interactively,
-and moves confirmed files to the correct performer directory.
+verifier.py
+------------
+Interactive performer verification tool (Goondex v0.3.5-r1)
+------------------------------------------------------------
+Used by:
+ - goondex verify [tags]
+ - goondex trainer (batch loop)
+
+This version replaces the global performers_dump.json with
+per-performer JSON files located under:
+ data/faces//performer.json
+
+Each performer.json stores:
+ {
+ "name": "Riley Reid",
+ "normalized_id": "riley_reid",
+ "aliases": [],
+ "source_urls": [],
+ "stats": {
+ "known_galleries": 0,
+ "studio_appearances": {}
+ },
+ "faces": [
+ "001.jpg",
+ "002.jpg"
+ ]
+ }
"""
import os
import sys
+import json
+import shutil
from pathlib import Path
-from src.ml.facecrop.verifier import verify_face, record_verified_face
+from datetime import datetime
+from src.ml.facecrop.image_display import show_image
-FACES_CACHE = Path("ML/faces_cache") # adjust path if needed
+# New imports for schema consistency
+from src.performers.utils import (
+ ensure_performer_exists,
+ get_performer_path,
+ normalize_name,
+ save_json
+)
-def train_from_cache():
- if not FACES_CACHE.exists():
- print(f"[ERROR] No cache directory found: {FACES_CACHE}")
+# ------------------------------------------------------------
+# Directories
+# ------------------------------------------------------------
+
+BASE_DIR = Path("data/faces")
+BASE_DIR.mkdir(parents=True, exist_ok=True)
+
+# ------------------------------------------------------------
+# Helper functions
+# ------------------------------------------------------------
+
+def _normalize_name(name: str) -> str:
+ """Normalize performer name for folder use."""
+ return normalize_name(name)
+
+def _performer_folder(name: str) -> Path:
+ """Return the path for a performer's folder."""
+ return BASE_DIR / _normalize_name(name)
+
+def _performer_json_path(name: str) -> Path:
+ """Return the JSON path for a performer."""
+ return _performer_folder(name) / "performer.json"
+
+def _confirm(prompt: str) -> bool:
+ """Ask a simple [y/n] question."""
+ while True:
+ ans = input(f"{prompt} [y/n]: ").strip().lower()
+ if ans in ("y", "yes"):
+ return True
+ if ans in ("n", "no"):
+ return False
+
+def _load_performer_json(name: str) -> dict:
+ """Load or initialize performer JSON."""
+ path = _performer_json_path(name)
+ if path.exists():
+ try:
+ return json.loads(path.read_text(encoding="utf-8"))
+ except json.JSONDecodeError:
+ print(f"[WARN] Corrupted performer.json for {name}, recreating.")
+ # Fallback: create schema-aligned record
+ performer_data = ensure_performer_exists(name)
+ performer_data["last_updated"] = datetime.utcnow().isoformat() + "Z"
+ return performer_data
+
+def _save_performer_json(name: str, data: dict):
+ """Save performer JSON (schema-aware)."""
+ path = get_performer_path(name)
+ data["last_updated"] = datetime.utcnow().isoformat() + "Z"
+ save_json(data, path)
+
+def _next_unknown_label() -> str:
+ """Generate 'Unknown Performer #XXXX' label based on existing folders."""
+ unknowns = [
+ int(p.name.split("_")[-1])
+ for p in BASE_DIR.glob("unknown_performer_*")
+ if p.name.split("_")[-1].isdigit()
+ ]
+ next_id = (max(unknowns) + 1) if unknowns else 0
+ return f"Unknown Performer #{next_id:04d}"
+
+# ------------------------------------------------------------
+# Core verification
+# ------------------------------------------------------------
+
+def verify_face(image_path: str, candidate_tags: list[str]) -> str:
+ """
+ Show an image and ask who it is.
+ Returns the confirmed performer name (or Unknown label).
+ """
+ print("\n────────────────────────────────────────────")
+ print("🖼️ FACE PREVIEW")
+ print("────────────────────────────────────────────")
+ show_image(image_path, width=400)
+ print("────────────────────────────────────────────")
+
+ # Try candidate tags
+ for tag in candidate_tags:
+ if _confirm(f"Is this face {tag}?"):
+ print(f"[OK] Confirmed as {tag}")
+ return tag
+
+ # Manual entry
+ answer = input("Do you know this performer? (enter name or leave blank): ").strip()
+ if answer:
+ print(f"[OK] Added new performer: {answer}")
+ return answer
+
+ unknown = _next_unknown_label()
+ print(f"[INFO] Tagged as {unknown}")
+ return unknown
+
+def record_verified_face(image_path: str, performer_name: str):
+ """
+ Move verified image into performer's folder
+ and update performer.json.
+ """
+ folder = _performer_folder(performer_name)
+ folder.mkdir(parents=True, exist_ok=True)
+
+ json_path = _performer_json_path(performer_name)
+ data = _load_performer_json(performer_name)
+
+ src = Path(image_path)
+ dest = folder / src.name
+
+ # Avoid overwriting existing files
+ if dest.exists():
+ base, ext = os.path.splitext(dest.name)
+ i = 1
+ while (folder / f"{base}_{i}{ext}").exists():
+ i += 1
+ dest = folder / f"{base}_{i}{ext}"
+
+ try:
+ shutil.move(str(src), str(dest))
+ except Exception as e:
+ print(f"[WARN] Could not move file: {e}")
+ shutil.copy2(src, dest)
+
+ if "faces" not in data:
+ data["faces"] = []
+ data["faces"].append(dest.name)
+ data["last_updated"] = datetime.utcnow().isoformat() + "Z"
+
+ _save_performer_json(performer_name, data)
+
+ print(f"[OK] Saved {dest} under {performer_name}")
+
+# ------------------------------------------------------------
+# CLI entrypoint
+# ------------------------------------------------------------
+
+def main():
+ if len(sys.argv) < 2:
+ print("Usage: goondex verify [comma_separated_tags]")
sys.exit(1)
- images = sorted(p for p in FACES_CACHE.iterdir() if p.suffix.lower() in [".jpg", ".jpeg", ".png"])
- if not images:
- print(f"[INFO] No new face crops in {FACES_CACHE}")
- return
+ image_path = sys.argv[1]
+ if not os.path.exists(image_path):
+ print(f"[ERROR] File not found: {image_path}")
+ sys.exit(1)
- print(f"[INFO] Found {len(images)} cropped faces to verify.\n")
-
- for img_path in images:
- # Extract performer tags from filename (optional)
- candidate_tags = []
- name_part = img_path.stem
- if "_" in name_part:
- parts = name_part.split("_")
- candidate_tags = [p.replace("-", " ").title() for p in parts if p.isalpha()]
-
- performer = verify_face(str(img_path), candidate_tags)
- record_verified_face(str(img_path), performer)
-
- print("\n✅ Training session complete.")
+ tags = sys.argv[2].split(",") if len(sys.argv) > 2 else []
+ performer = verify_face(image_path, tags)
+ record_verified_face(image_path, performer)
if __name__ == "__main__":
- train_from_cache()
+ main()
diff --git a/src/ml/facecrop/verifier.py b/src/ml/facecrop/verifier.py
index d2cf96d..4b81b38 100644
--- a/src/ml/facecrop/verifier.py
+++ b/src/ml/facecrop/verifier.py
@@ -5,10 +5,12 @@ verifier.py
Interactive terminal tool for confirming performer identities
from cropped face images.
-- Displays actual performer images inline using Kitty graphics protocol.
-- Cycles through known performer tags (e.g., Riley Reid, Eva Lovia)
-- Asks user confirmation interactively.
-- Creates new "Unknown Performer" entries if no match confirmed.
+Integrates directly with the Goondex performer schema.
+
+- Displays cropped face images inline using Kitty graphics protocol
+- Cycles through candidate tags (e.g. Riley Reid, Eva Lovia)
+- Asks for user confirmation interactively
+- Creates or updates structured performer.json records
Usage:
python -m src.ml.facecrop.verifier ./data/faces_cache/image_001.jpg "Riley Reid,Eva Lovia"
@@ -16,106 +18,110 @@ Usage:
import os
import sys
-import json
from pathlib import Path
+from typing import List
from src.ml.facecrop.image_display import show_image
+from src.performers.utils import (
+ ensure_performer_exists,
+ update_performer_record,
+ save_json,
+ get_performer_path,
+ normalize_name,
+)
-# Storage paths
-PERFORMER_DB = Path("performers_dump.json")
+# Storage directories
FACES_DIR = Path("data/faces")
-
-# Ensure directories exist
FACES_DIR.mkdir(parents=True, exist_ok=True)
-if not PERFORMER_DB.exists():
- PERFORMER_DB.write_text("{}", encoding="utf-8")
# ------------------------------------------------------------
# Helper functions
# ------------------------------------------------------------
-def _load_performers() -> dict:
- """Load existing performer database."""
- try:
- return json.loads(PERFORMER_DB.read_text(encoding="utf-8"))
- except Exception:
- return {}
-
-def _save_performers(data: dict):
- """Save performer database."""
- PERFORMER_DB.write_text(json.dumps(data, indent=2), encoding="utf-8")
-
-def _next_unknown_id(data: dict) -> str:
- """Generate a new Unknown Performer ID."""
- unknowns = [int(k.split("#")[-1]) for k in data.keys() if k.startswith("Unknown Performer")]
- return f"Unknown Performer #{max(unknowns) + 1:04d}" if unknowns else "Unknown Performer #0000"
-
def _confirm(prompt: str) -> bool:
"""Ask a yes/no question."""
while True:
ans = input(f"{prompt} [y/n]: ").strip().lower()
- if ans in ("y", "yes"): return True
- if ans in ("n", "no"): return False
+ if ans in ("y", "yes"):
+ return True
+ if ans in ("n", "no"):
+ return False
+
+
+def _next_unknown_name(base_dir: Path = FACES_DIR) -> str:
+ """Generate the next available Unknown Performer label."""
+ existing = [
+ p.name for p in base_dir.iterdir()
+ if p.is_dir() and p.name.startswith("unknown_performer")
+ ]
+ ids = [int(p.split("_")[-1]) for p in existing if p.split("_")[-1].isdigit()]
+ next_id = (max(ids) + 1) if ids else 0
+ return f"Unknown Performer #{next_id:04d}"
+
# ------------------------------------------------------------
-# Core verification loop
+# Core verification logic
# ------------------------------------------------------------
-def verify_face(image_path: str, candidate_tags: list[str]):
+def verify_face(image_path: str, candidate_tags: List[str]) -> str:
"""
- Display an image and ask user who it is.
- Returns confirmed performer name or new unknown tag.
+ Display an image, ask user to confirm the performer.
+ Returns the confirmed performer name (or Unknown label).
"""
- performers = _load_performers()
-
print("\n────────────────────────────────────────────")
print("🖼️ FACE PREVIEW")
print("────────────────────────────────────────────")
show_image(image_path, width=400)
print("────────────────────────────────────────────")
- for name in candidate_tags:
- if _confirm(f"Is this face {name}?"):
- print(f"✅ Confirmed as {name}")
- return name
+ for tag in candidate_tags:
+ if _confirm(f"Is this {tag}?"):
+ print(f"✅ Confirmed as {tag}")
+ return tag
- # Try manual input
- answer = input("Do you know this performer? (enter name or leave blank): ").strip()
- if answer:
- print(f"✅ New performer: {answer}")
- return answer
+ manual = input("Do you know this performer? (enter name or leave blank): ").strip()
+ if manual:
+ print(f"✅ New performer added: {manual}")
+ return manual
+
+ unknown = _next_unknown_name()
+ print(f"⚠️ Tagged as {unknown}")
+ return unknown
- # Assign unknown
- unknown_id = _next_unknown_id(performers)
- print(f"⚠️ Tagged as {unknown_id}")
- return unknown_id
def record_verified_face(image_path: str, performer_name: str):
"""
- Move image to performer's folder and update DB.
+ Move verified face to performer's folder and update performer.json.
"""
- performers = _load_performers()
+ # Ensure performer schema exists and load it
+ performer = ensure_performer_exists(performer_name)
+ performer_id = normalize_name(performer_name)
- # Normalize key
- key = performer_name.lower().replace(" ", "_")
- performer_folder = FACES_DIR / key
+ performer_folder = FACES_DIR / performer_id
performer_folder.mkdir(parents=True, exist_ok=True)
- # Move/copy image
- dest = performer_folder / Path(image_path).name
- os.rename(image_path, dest)
+ src = Path(image_path)
+ dest = performer_folder / src.name
- # Update DB
- if performer_name not in performers:
- performers[performer_name] = {
- "faces": [],
- "confirmed": True
- }
+ try:
+ os.rename(src, dest)
+ except OSError:
+ print(f"[WARN] Could not move {src}, copying instead.")
+ import shutil
+ shutil.copy(src, dest)
- performers[performer_name]["faces"].append(str(dest))
- _save_performers(performers)
+ # Update performer record
+ rel_path = str(dest)
+ if "faces" not in performer:
+ performer["faces"] = []
+ if rel_path not in performer["faces"]:
+ performer["faces"].append(rel_path)
+ # Write back to performer.json
+ performer_path = get_performer_path(performer_name)
+ save_json(performer, performer_path)
print(f"💾 Saved {dest} under {performer_name}")
+
# ------------------------------------------------------------
# CLI entry point
# ------------------------------------------------------------
@@ -128,5 +134,5 @@ if __name__ == "__main__":
image_path = sys.argv[1]
tags = sys.argv[2].split(",") if len(sys.argv) > 2 else []
- performer = verify_face(image_path, tags)
- record_verified_face(image_path, performer)
+ performer_name = verify_face(image_path, tags)
+ record_verified_face(image_path, performer_name)
diff --git a/src/ml/tagging_config.py b/src/ml/tagging_config.py
new file mode 100644
index 0000000..04ad945
--- /dev/null
+++ b/src/ml/tagging_config.py
@@ -0,0 +1,19 @@
+#!/usr/bin/env python3
+"""
+tagging_config.py — Goondex v0.3.7
+────────────────────────────────────
+Default configuration for ML-based tagging system.
+
+Used by scraper.py and enrichment bridge for tagging consistency.
+"""
+
+tags_config = {
+ "confidence_threshold": 0.45,
+ "categories": {
+ "body": ["Blonde", "Brunette", "Redhead", "Ebony", "Asian", "Latina", "White"],
+ "acts": ["Anal", "Oral", "Vaginal", "Group", "Solo", "BDSM", "Lesbian", "POV"],
+ "style": ["Amateur", "Professional", "Softcore", "Outdoor", "VR", "HD", "4K"]
+ },
+ "excluded_keywords": ["thumbnail", "banner", "logo", "watermark"],
+ "version": "0.1.0"
+}
diff --git a/src/performers/__pycache__/db_manager.cpython-313.pyc b/src/performers/__pycache__/db_manager.cpython-313.pyc
index e23e2d4..9b76b1a 100644
Binary files a/src/performers/__pycache__/db_manager.cpython-313.pyc and b/src/performers/__pycache__/db_manager.cpython-313.pyc differ
diff --git a/src/performers/__pycache__/tpdb_bridge.cpython-313.pyc b/src/performers/__pycache__/tpdb_bridge.cpython-313.pyc
index 10082ab..5053cd7 100644
Binary files a/src/performers/__pycache__/tpdb_bridge.cpython-313.pyc and b/src/performers/__pycache__/tpdb_bridge.cpython-313.pyc differ
diff --git a/src/performers/__pycache__/utils.cpython-313.pyc b/src/performers/__pycache__/utils.cpython-313.pyc
index df88b0c..6788c4d 100644
Binary files a/src/performers/__pycache__/utils.cpython-313.pyc and b/src/performers/__pycache__/utils.cpython-313.pyc differ
diff --git a/src/performers/db_manager.py b/src/performers/db_manager.py
index 03aad46..6d500d3 100644
--- a/src/performers/db_manager.py
+++ b/src/performers/db_manager.py
@@ -1,7 +1,21 @@
+#!/usr/bin/env python3
+"""
+db_manager.py
+-------------
+Performer and Source database manager for Goondex (v0.3.5-r1)
+
+Handles:
+ - SQLite performer table creation and updates
+ - Source/channel link tracking
+ - JSON ↔ SQLite synchronization for per-performer files
+ - Integration with facecrop verification events
+"""
+
import sqlite3
from pathlib import Path
from datetime import datetime
import json
+import shutil
# ─────────────────────────────────────────────
# Database Path Configuration
@@ -9,6 +23,9 @@ import json
DB_PATH = Path(__file__).resolve().parents[1] / "importer" / "db" / "performers.db"
DB_PATH.parent.mkdir(parents=True, exist_ok=True)
+# JSON directory for performer data
+JSON_DIR = Path("data/performers")
+JSON_DIR.mkdir(parents=True, exist_ok=True)
# ─────────────────────────────────────────────
# Connection Helpers
@@ -75,6 +92,26 @@ def add_or_update_performer(perf: dict):
return value
with get_conn() as conn:
+ # ─── Deduplication Check ──────────────────────────────
+ name = perf.get("name", "").strip().lower()
+ if not name:
+ print("[!] Skipping unnamed performer record.")
+ return
+
+ cur = conn.execute("SELECT id FROM performers WHERE LOWER(name) = ?", (name,))
+ existing = cur.fetchone()
+ if existing:
+ # Already exists — just update instead of inserting a duplicate
+ conn.execute("""
+ UPDATE performers
+ SET last_updated = ?
+ WHERE id = ?
+ """, (datetime.utcnow().isoformat(), existing["id"]))
+ conn.commit()
+ print(f"[SKIP] Performer already exists → {perf.get('name')}")
+ return
+
+ # ─── Insert / Update Performer ─────────────────────────
conn.execute("""
INSERT INTO performers (
id, name, url, aliases, gender, birthdate, ethnicity,
@@ -262,3 +299,113 @@ def verify_source_integrity():
for o in orphans:
print(f" - ID {o['id']}: {o['performer_id']} → {o['source_name']}")
return orphans
+
+
+# ─────────────────────────────────────────────
+# JSON ↔ SQLite Sync Extensions
+# ─────────────────────────────────────────────
+def import_from_json(json_path: Path):
+ """Import a single performer.json into SQLite."""
+ if not json_path.exists():
+ print(f"[!] Missing JSON: {json_path}")
+ return
+ try:
+ data = json.loads(json_path.read_text(encoding="utf-8"))
+ except Exception as e:
+ print(f"[ERROR] Failed to load {json_path}: {e}")
+ return
+
+ record = {
+ "id": data.get("normalized_id"),
+ "name": data.get("name"),
+ "url": "",
+ "aliases": data.get("aliases", []),
+ "gender": data.get("gender", ""),
+ "birthdate": "",
+ "ethnicity": data.get("ethnicity", ""),
+ "hair_color": data.get("hair_color", ""),
+ "eye_color": data.get("eye_color", ""),
+ "height_cm": None,
+ "measurements": "",
+ "nationality": data.get("country", ""),
+ "country_code": "",
+ "tags": [],
+ "source": "Goondex",
+ }
+ add_or_update_performer(record)
+ print(f"[📥] Imported performer → {record['name']}")
+
+
+def export_to_json(performer_id: str):
+ """Export a performer record from SQLite into data/performers JSON."""
+ with get_conn() as conn:
+ cur = conn.execute("SELECT * FROM performers WHERE id = ?", (performer_id,))
+ row = cur.fetchone()
+ if not row:
+ print(f"[!] Performer not found: {performer_id}")
+ return
+
+ data = dict(row)
+ normalized = data["id"]
+ folder = JSON_DIR / normalized
+ folder.mkdir(parents=True, exist_ok=True)
+ out_path = folder / "performer.json"
+ out_path.write_text(json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
+ print(f"[💾] Exported → {out_path}")
+
+
+def record_face_verification(performer_id: str, image_path: str):
+ """
+ Log a verified face image under the performer's JSON folder
+ and increment the source appearance in SQLite.
+ """
+ normalized = performer_id.lower()
+ performer_dir = JSON_DIR / normalized
+ performer_dir.mkdir(parents=True, exist_ok=True)
+ dest = performer_dir / Path(image_path).name
+
+ if not dest.exists():
+ try:
+ shutil.copy(image_path, dest)
+ except Exception as e:
+ print(f"[WARN] Could not copy {image_path}: {e}")
+
+ # Update JSON file if exists
+ json_path = performer_dir / "performer.json"
+ if json_path.exists():
+ data = json.loads(json_path.read_text(encoding="utf-8"))
+ if "faces" not in data:
+ data["faces"] = []
+ if Path(image_path).name not in data["faces"]:
+ data["faces"].append(Path(image_path).name)
+ data["last_updated"] = datetime.utcnow().isoformat()
+ json_path.write_text(json.dumps(data, indent=2), encoding="utf-8")
+
+ add_or_update_source(performer_id, "Goondex", "FaceVerifier")
+ print(f"[🧠] Recorded face verification for {performer_id}")
+
+
+def verify_json_integrity():
+ """
+ Check for mismatch between SQLite and JSON performer timestamps.
+ """
+ mismatches = []
+ for json_path in JSON_DIR.glob("*/performer.json"):
+ try:
+ data = json.loads(json_path.read_text(encoding="utf-8"))
+ pid = data.get("normalized_id")
+ jtime = data.get("last_updated")
+ with get_conn() as conn:
+ cur = conn.execute("SELECT last_updated FROM performers WHERE id = ?", (pid,))
+ row = cur.fetchone()
+ if row and row["last_updated"] != jtime:
+ mismatches.append(pid)
+ except Exception:
+ continue
+
+ if mismatches:
+ print(f"[⚠️] Timestamp mismatches for {len(mismatches)} performer(s):")
+ for m in mismatches:
+ print(f" - {m}")
+ else:
+ print("[✅] All JSON ↔ SQLite timestamps match.")
diff --git a/src/performers/enrichment_bridge.py b/src/performers/enrichment_bridge.py
new file mode 100644
index 0000000..c5625f1
--- /dev/null
+++ b/src/performers/enrichment_bridge.py
@@ -0,0 +1,91 @@
+#!/usr/bin/env python3
+"""
+cli_colours.py — Goondex Terminal Colour Helper
+───────────────────────────────────────────────
+Centralised ANSI colour definitions for Goondex CLI output.
+Keeps all modules visually consistent (importer, TPDB bridge,
+performer search, ML tools, etc.)
+
+Palette — Flamingo Pulse theme:
+ pink → primary accent
+ lilac → secondary accent
+ cyan → highlight / link
+ yellow → warning / info
+ white → base text
+ grey → muted / subtle
+ red → error / critical (added for compatibility)
+ green → success / confirmation (added for compatibility)
+ reset → reset sequence
+"""
+
+# ANSI escape sequences
+_RESET = "\033[0m"
+
+# Brand palette (Flamingo Pulse inspired)
+PINK = "\033[38;5;205m" # vivid magenta-pink
+LILAC = "\033[38;5;177m" # soft violet accent
+CYAN = "\033[38;5;123m" # turquoise-cyan for links
+YELLOW = "\033[38;5;228m" # bright pastel yellow
+WHITE = "\033[38;5;255m" # near-white text
+GREY = "\033[38;5;246m" # neutral soft grey
+RED = "\033[38;5;196m" # bold red for critical errors
+GREEN = "\033[38;5;82m" # vivid green for confirmations
+BOLD = "\033[1m"
+DIM = "\033[2m"
+
+# ─────────────────────────────────────────────
+# Helper functions for inline use
+# ─────────────────────────────────────────────
+def pink(text: str) -> str:
+ return f"{PINK}{text}{_RESET}"
+
+def lilac(text: str) -> str:
+ return f"{LILAC}{text}{_RESET}"
+
+def cyan(text: str) -> str:
+ return f"{CYAN}{text}{_RESET}"
+
+def yellow(text: str) -> str:
+ return f"{YELLOW}{text}{_RESET}"
+
+def white(text: str) -> str:
+ return f"{WHITE}{text}{_RESET}"
+
+def grey(text: str) -> str:
+ return f"{GREY}{text}{_RESET}"
+
+def red(text: str) -> str:
+ return f"{RED}{text}{_RESET}"
+
+def green(text: str) -> str:
+ return f"{GREEN}{text}{_RESET}"
+
+def bold(text: str) -> str:
+ return f"{BOLD}{text}{_RESET}"
+
+def dim(text: str) -> str:
+ return f"{DIM}{text}{_RESET}"
+
+# ─────────────────────────────────────────────
+# Composite helpers
+# ─────────────────────────────────────────────
+def heading(title: str, icon: str = "💖", version: str | None = None) -> str:
+ """Generate a styled Goondex section header."""
+ bar = grey("─" * 45)
+ ver = f" · {grey(version)}" if version else ""
+ return f"\n{bar}\n{pink(icon)} {bold(white(title))}{ver}\n{bar}"
+
+def success(msg: str) -> str:
+ return f"{GREEN}✅ {msg}{_RESET}"
+
+def warning(msg: str) -> str:
+ return f"{YELLOW}⚠️ {msg}{_RESET}"
+
+def error(msg: str) -> str:
+ return f"{RED}❌ {msg}{_RESET}"
+
+def info(msg: str) -> str:
+ return f"{CYAN}ℹ️ {msg}{_RESET}"
+
+def muted(msg: str) -> str:
+ return f"{GREY}{msg}{_RESET}"
diff --git a/src/performers/scraper.py b/src/performers/scraper.py
index 34d351f..e3e059f 100644
--- a/src/performers/scraper.py
+++ b/src/performers/scraper.py
@@ -1,13 +1,30 @@
+"""
+Goondex Performer Scraper
+-------------------------
+Fetches performer data from PornPics and caches results locally.
+Supports both A–Z directory scraping and individual performer profiles.
+
+Author: Leak Technologies
+"""
+
import time
import re
+import datetime
import requests
from pathlib import Path
from bs4 import BeautifulSoup
-from playwright.sync_api import sync_playwright
-from performers.utils import normalize_name, save_json, load_json
-from performers.db_manager import init_db, add_or_update_performer, list_count
-from ml.tagging import assign_tags # import our tag assignment function
-from ml.tagging_config import tags_config # to load our tags configuration
+
+# Optional Playwright support
+try:
+ from playwright.sync_api import sync_playwright
+ PLAYWRIGHT_AVAILABLE = True
+except ImportError:
+ PLAYWRIGHT_AVAILABLE = False
+
+from src.performers.utils import normalize_name, save_json, load_json
+from src.performers.db_manager import init_db, add_or_update_performer, list_count
+from src.ml.tagging import assign_tags # image tag generation
+from src.ml.tagging_config import tags_config # tag definitions
# ─────────────────────────────────────────────
# Configuration
@@ -18,7 +35,6 @@ PROGRESS_PATH = Path(__file__).resolve().parents[1] / "importer" / "reports" / "
CACHE_DIR = Path(__file__).resolve().parents[1] / "importer" / "cache" / "performers"
CACHE_DIR.mkdir(parents=True, exist_ok=True)
-
# ─────────────────────────────────────────────
# Parsing Helpers
# ─────────────────────────────────────────────
@@ -33,33 +49,26 @@ def extract_performers_from_html(html: str):
if not name or not href:
continue
- # only accept direct profile links: /pornstars//
- # (no extra path parts)
if not re.match(r"^/pornstars/[^/]+/$", href):
continue
- # skip junk
lname = name.lower()
if any(bad in lname for bad in ["unknown", "amateur", "couple"]):
continue
- # use the URL slug as the unique id
- slug = href.strip("/").split("/")[1] # ['pornstars', '']
- nid = slug.lower() # already URL-safe; no need to normalize name
+ slug = href.strip("/").split("/")[1]
+ nid = slug.lower()
results.append({
- "id": nid, # unique + stable
- "name": name, # display name
+ "id": nid,
+ "name": name,
"url": f"https://www.pornpics.com{href}",
})
- # Fallback regex (same rules)
if not results:
for href, name in re.findall(r'href="(/pornstars/[^"]+)">([^<]+)', html):
if not re.match(r"^/pornstars/[^/]+/$", href or ""):
continue
- if not name:
- continue
lname = name.lower()
if any(bad in lname for bad in ["unknown", "amateur", "couple"]):
continue
@@ -70,7 +79,6 @@ def extract_performers_from_html(html: str):
"name": name.strip(),
"url": f"https://www.pornpics.com{href}",
})
-
return results
@@ -95,10 +103,7 @@ def fetch_static(letter: str) -> str:
def render_and_cache(letter: str) -> str:
- """
- Use cache → static fetch → Playwright render (fallback) hierarchy.
- Keeps each letter’s HTML cached locally.
- """
+ """Use cache → static fetch → Playwright render (fallback) hierarchy."""
cache_file = CACHE_DIR / f"{letter}.html"
if cache_file.exists():
print(f"[💾] Using cached HTML for '{letter.upper()}'")
@@ -109,10 +114,11 @@ def render_and_cache(letter: str) -> str:
cache_file.write_text(html, encoding="utf-8")
return html
- # Fallback to Playwright only if static fetch failed
- url = f"{BASE_URL}?letter={letter}"
- print(f"[🧠] Falling back to Playwright render for {letter.upper()}")
+ if not PLAYWRIGHT_AVAILABLE:
+ print(f"[⚠] Playwright not installed — skipping render for {letter.upper()}")
+ return ""
+ print(f"[🧠] Falling back to Playwright render for {letter.upper()}")
try:
with sync_playwright() as p:
browser = p.chromium.launch(headless=True, args=["--no-sandbox"])
@@ -122,7 +128,7 @@ def render_and_cache(letter: str) -> str:
)
page = context.new_page()
page.set_default_timeout(10000)
- page.goto(url, wait_until="domcontentloaded")
+ page.goto(f"{BASE_URL}?letter={letter}", wait_until="domcontentloaded")
html = page.content()
browser.close()
except Exception as e:
@@ -139,21 +145,20 @@ def render_and_cache(letter: str) -> str:
# ─────────────────────────────────────────────
-# Scraping Logic
+# Tagging + Scraping Logic
# ─────────────────────────────────────────────
-
def scrape_performer_tags(performer_id, performer_url):
"""Use object detection to tag the performer images."""
- # Placeholder for actual image extraction from the performer page
- image_urls = fetch_performer_images(performer_url) # Function to fetch images from the performer URL
-
+ try:
+ image_urls = fetch_performer_images(performer_url) # hypothetical image extractor
+ except Exception:
+ image_urls = []
tags = []
for image_url in image_urls:
- # Assuming image_url contains an image to be processed for tagging
- tags.extend(assign_tags(image_url)) # Here we use the assign_tags function to generate tags
-
+ tags.extend(assign_tags(image_url))
return tags
+
def scrape_letter(letter: str):
"""Scrape one letter of the performer list, using cached or live data."""
html = render_and_cache(letter)
@@ -162,7 +167,6 @@ def scrape_letter(letter: str):
performers = extract_performers_from_html(html)
- # 🔍 De-duplication diagnostics
seen = set()
unique_performers = []
for p in performers:
@@ -176,17 +180,15 @@ def scrape_letter(letter: str):
print(f" → Found {len(unique_performers)} unique performers for {letter.upper()}")
- # Now assign tags to each performer
for performer in unique_performers:
performer_tags = scrape_performer_tags(performer["id"], performer["url"])
- performer["tags"] = performer_tags # Store the tags with the performer data
-
+ performer["tags"] = performer_tags
return unique_performers
def scrape_all():
"""Scrape entire PornPics performer directory (A–Z) and sync to DB."""
- init_db() # ensure database exists first
+ init_db()
all_performers = {}
progress = load_json(PROGRESS_PATH) or {}
existing_data = load_json(OUTPUT_PATH) or []
@@ -202,22 +204,18 @@ def scrape_all():
for letter in "abcdefghijklmnopqrstuvwxyz"[start_index:]:
performers = scrape_letter(letter)
-
if not performers:
print(f"[⚠] No performers found for {letter.upper()} — skipping DB update.")
continue
- # Save to both memory + DB
for perf in performers:
all_performers.setdefault(perf["id"], perf)
add_or_update_performer(perf)
- # Save JSON + progress checkpoint
save_json(list(all_performers.values()), OUTPUT_PATH)
save_json({"last_letter": letter}, PROGRESS_PATH)
print(f"[💾] Progress saved (last: {letter.upper()}) — total performers: {len(all_performers)}")
-
- time.sleep(2) # polite delay between letters
+ time.sleep(2)
if PROGRESS_PATH.exists():
PROGRESS_PATH.unlink()
@@ -228,6 +226,98 @@ def scrape_all():
print(f"[→] Saved to: {OUTPUT_PATH}")
+# ─────────────────────────────────────────────
+# Individual Performer Profile Scraper
+# ─────────────────────────────────────────────
+import pycountry
+
+def _calculate_age(birthdate: str) -> str:
+ try:
+ dob = datetime.datetime.strptime(birthdate, "%Y-%m-%d").date()
+ today = datetime.date.today()
+ age = today.year - dob.year - ((today.month, today.day) < (dob.month, dob.day))
+ return f"{birthdate} ({age} years old)"
+ except Exception:
+ return birthdate or "Unknown"
+
+
+def _flag_for_country(name: str) -> str:
+ try:
+ country_obj = pycountry.countries.lookup(name)
+ return ''.join(chr(127397 + ord(c)) for c in country_obj.alpha_2.upper())
+ except Exception:
+ return ""
+
+
+def scrape_performer_profile(performer_name: str) -> dict:
+ """Fetch detailed performer metadata from PornPics profile page."""
+ normalized = normalize_name(performer_name)
+ profile_url = f"https://www.pornpics.com/pornstars/{normalized}/"
+ print(f"[🌐] Fetching PornPics profile for {performer_name} → {profile_url}")
+
+ try:
+ resp = requests.get(
+ profile_url,
+ headers={"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) Chrome/128.0"},
+ timeout=10,
+ )
+ if resp.status_code != 200:
+ print(f"[!] Failed to fetch profile ({resp.status_code})")
+ return {}
+ except Exception as e:
+ print(f"[!] Error fetching profile for {performer_name}: {e}")
+ return {}
+
+ soup = BeautifulSoup(resp.text, "html.parser")
+
+ img_tag = soup.select_one(".model-thumb img, .model-info img")
+ profile_image = img_tag["src"] if img_tag and img_tag.get("src") else None
+
+ details = {}
+ for li in soup.select(".model-details li"):
+ txt = li.get_text(strip=True)
+ if ":" not in txt:
+ continue
+ key, val = [x.strip() for x in txt.split(":", 1)]
+ details[key.lower()] = val
+
+ birth = details.get("born")
+ gender = details.get("gender", "Unknown")
+ country = details.get("country") or details.get("nationality")
+ ethnicity = details.get("ethnicity")
+ hair = details.get("hair color")
+ height = details.get("height")
+ weight = details.get("weight")
+ tattoos = details.get("tattoos")
+ breast_size = details.get("breast size")
+ breast_type = details.get("breast type")
+
+ gender_emoji = "♀️" if gender.lower().startswith("f") else ("♂️" if gender.lower().startswith("m") else "")
+ gender_full = f"{gender.capitalize()} {gender_emoji}".strip()
+
+ flag = _flag_for_country(country or "") if country else ""
+ country_display = f"{country} {flag}".strip() if country else None
+
+ performer_data = {
+ "name": performer_name,
+ "normalized_id": normalized,
+ "url": profile_url,
+ "profile_image": profile_image,
+ "gender": gender_full,
+ "country": country_display,
+ "birth_date": _calculate_age(birth) if birth else None,
+ "ethnicity": ethnicity,
+ "hair_color": hair,
+ "height": height,
+ "weight": weight,
+ "tattoos": tattoos,
+ "breast_size": breast_size,
+ "breast_type": breast_type,
+ "source": "PornPics",
+ }
+ return performer_data
+
+
# ─────────────────────────────────────────────
# Entrypoint
# ─────────────────────────────────────────────
diff --git a/src/performers/search.py b/src/performers/search.py
new file mode 100644
index 0000000..b2532f2
--- /dev/null
+++ b/src/performers/search.py
@@ -0,0 +1,336 @@
+#!/usr/bin/env python3
+"""
+search.py
+---------
+Performer Search Interface — Goondex v0.3.11
+
+Unified performer metadata browser with terminal-friendly visuals.
+Fetches from local DB, TPDB, and PornPics with automatic merge + caching.
+
+Usage:
+ gx search-performer "Riley Reid"
+ gx search-performer "Riley Reid" --json
+"""
+
+import os
+import sys
+import json
+import sqlite3
+import pycountry
+from datetime import datetime, date
+from pathlib import Path
+from typing import Optional
+from src.ml.facecrop.image_display import show_image
+from src.performers.utils import normalize_name
+from src.performers.db_manager import add_or_update_performer
+from src.importer.pornpics_bridge import fetch_pornpics_profile
+from src.performers.tpdb_bridge import fetch_tpdb_performers
+
+# ============================================================
+# Paths
+# ============================================================
+BASE_DIR = Path(__file__).resolve().parents[2]
+DATA_DIR = BASE_DIR / "data" / "performers"
+FACES_DIR = BASE_DIR / "data" / "faces"
+DB_PATH = BASE_DIR / "src" / "importer" / "db" / "performers.db"
+GALLERIES_DIR = BASE_DIR / "data" / "galleries"
+
+# ============================================================
+# Colors
+# ============================================================
+COLORS = {
+ "brand": "\033[38;5;205m",
+ "accent": "\033[38;5;219m",
+ "white": "\033[97m",
+ "grey": "\033[38;5;250m",
+ "cyan": "\033[38;5;123m",
+ "reset": "\033[0m",
+}
+def color(txt, c): return f"{COLORS.get(c, COLORS['white'])}{txt}{COLORS['reset']}"
+def divider(): return color("─" * 44, "brand")
+def title_line(t): return f"{divider()}\n{color('💖 ' + t, 'accent')}\n{divider()}"
+
+# ============================================================
+# Utility Helpers
+# ============================================================
+def country_flag(country_name: str) -> str:
+ if not country_name:
+ return ""
+ try:
+ c = pycountry.countries.lookup(country_name)
+ return "".join(chr(127397 + ord(ch)) for ch in c.alpha_2.upper())
+ except Exception:
+ return ""
+
+def calc_age(birth_str: str) -> str:
+ try:
+ birth = datetime.strptime(birth_str, "%Y-%m-%d").date()
+ today = date.today()
+ years = today.year - birth.year - ((today.month, today.day) < (birth.month, birth.day))
+ return f"{birth_str} ({years} years old)"
+ except Exception:
+ return birth_str or "-"
+
+def gender_icon(gender: str) -> str:
+ if not gender:
+ return "-"
+ g = gender.lower()
+ if "female" in g or g == "f":
+ return f"Female ♀️"
+ if "male" in g or g == "m":
+ return f"Male ♂️"
+ return f"{gender.title()} ⚧️"
+
+def format_height(value):
+ if not value:
+ return "-"
+ try:
+ val = str(value).lower().replace("cm", "").strip()
+ cm = float(val)
+ inches = cm / 2.54
+ ft = int(inches // 12)
+ inch = int(round(inches % 12))
+ return f"{cm:.0f} cm ({ft}′{inch}″)"
+ except Exception:
+ return str(value)
+
+def format_weight(value):
+ if not value:
+ return "-"
+ try:
+ val = str(value).lower().replace("kg", "").strip()
+ kg = float(val)
+ lb = kg * 2.20462
+ return f"{kg:.0f} kg ({lb:.0f} lbs)"
+ except Exception:
+ return str(value)
+
+def nonempty(value) -> bool:
+ return value not in (None, "", "-", [], {})
+
+# ============================================================
+# Data Helpers
+# ============================================================
+def fetch_from_db(name: str) -> Optional[dict]:
+ if not DB_PATH.exists():
+ return None
+ conn = sqlite3.connect(DB_PATH)
+ conn.row_factory = sqlite3.Row
+ cur = conn.cursor()
+ cur.execute("""
+ SELECT * FROM performers
+ WHERE LOWER(name) LIKE ? OR id = ?
+ ORDER BY name LIMIT 1;
+ """, (f"%{name.lower()}%", normalize_name(name)))
+ row = cur.fetchone()
+ conn.close()
+ return dict(row) if row else None
+
+def fetch_from_json(name: str) -> Optional[dict]:
+ normalized = normalize_name(name)
+ for fname in (f"{normalized}.json", f"{normalized.replace('_','-')}.json", f"{normalized.replace('-','_')}.json"):
+ path = DATA_DIR / fname
+ if path.exists():
+ try:
+ return json.loads(path.read_text(encoding="utf-8"))
+ except Exception:
+ continue
+ return None
+
+def save_to_json(performer_data: dict):
+ pid = performer_data.get("id") or normalize_name(performer_data.get("name", "unknown"))
+ path = DATA_DIR / f"{pid}.json"
+ try:
+ path.parent.mkdir(parents=True, exist_ok=True)
+ path.write_text(json.dumps(performer_data, indent=2, ensure_ascii=False), encoding="utf-8")
+ print(f"[💾] Cached performer → {path.name}")
+ except Exception as e:
+ print(f"[!] Failed to save JSON cache for {pid}: {e}")
+
+# ============================================================
+# Local Gallery Counter
+# ============================================================
+def count_local_galleries_for_performer(name_or_id: str) -> int:
+ if not GALLERIES_DIR.exists():
+ return 0
+ count = 0
+ query = normalize_name(name_or_id).lower()
+ for meta_path in GALLERIES_DIR.rglob("metadata.json"):
+ try:
+ data = json.loads(meta_path.read_text(encoding="utf-8"))
+ performers = data.get("performers", [])
+ tags = [t.lower() for t in data.get("tags", []) if isinstance(t, str)]
+ if any(query in normalize_name(p).lower() for p in performers if isinstance(p, str)):
+ count += 1
+ continue
+ tag_match = any(query in t.replace("-", "").replace("_", "") for t in tags)
+ if tag_match:
+ count += 1
+ except Exception:
+ continue
+ return count
+
+# ============================================================
+# Fetch + Merge
+# ============================================================
+def _merge_performer_data(tpdb_data: dict | None, pp_data: dict | None) -> dict:
+ if not tpdb_data:
+ return pp_data or {}
+ if not pp_data:
+ return tpdb_data or {}
+ merged = tpdb_data.copy()
+ for k, v in pp_data.items():
+ if not merged.get(k) or merged[k] in ("", "-", None, []):
+ merged[k] = v
+ if "stats" in pp_data:
+ merged.setdefault("stats", {}).update(pp_data["stats"])
+ merged.setdefault("sources", {}).update(pp_data.get("sources", {}))
+ merged["source"] = "TPDB+PornPics"
+ return merged
+
+def fetch_remote_performer(name: str) -> Optional[dict]:
+ print(color(f"[⚠] No local record for '{name}'. Fetching from TPDB…", "brand"))
+ tpdb_data = None
+ results = fetch_tpdb_performers(limit=100)
+ for p in results:
+ if name.lower() in p.get("name", "").lower():
+ tpdb_data = p
+ break
+ if tpdb_data:
+ print(color(f"[✅] TPDB match found → {tpdb_data['name']}", "cyan"))
+ else:
+ print(color("[ℹ] TPDB returned no match.", "grey"))
+ print(color("[ℹ] Checking PornPics profile…", "grey"))
+ pp_data = fetch_pornpics_profile(name)
+ if pp_data:
+ print(color(f"[✅] Found performer on PornPics → {pp_data['name']}", "cyan"))
+ if not tpdb_data and not pp_data:
+ print(color(f"[❌] No results for '{name}'", "brand"))
+ return None
+ merged = _merge_performer_data(tpdb_data, pp_data)
+ save_to_json(merged)
+ add_or_update_performer(merged)
+ return merged
+
+# ============================================================
+# Display Helpers
+# ============================================================
+def print_section(title: str, rows: list[tuple[str, str]]):
+ visible = [r for r in rows if nonempty(r[1])]
+ if not visible:
+ return
+ print(color(f"\n📌 {title}", "accent"))
+ for label, val in visible:
+ print(f"{color(label, 'cyan')} {color(val, 'white')}")
+
+def find_thumbnail(pid: str) -> Optional[Path]:
+ folder = FACES_DIR / pid
+ for ext in (".jpg", ".jpeg", ".png", ".webp"):
+ thumb = folder / f"thumbnail{ext}"
+ if thumb.exists():
+ return thumb
+ alt = next(folder.glob(f"*{ext}"), None)
+ if alt:
+ return alt
+ return None
+
+def display_performer(perf: dict):
+ print(title_line("Performer Profile"))
+ pid = perf.get("id") or normalize_name(perf.get("name", "unknown"))
+ thumb = find_thumbnail(pid)
+ if thumb and os.environ.get("TERM", "").lower().startswith(("xterm-kitty", "wezterm")):
+ print(color("🖼️ Thumbnail:", "grey"))
+ show_image(str(thumb), width=300)
+ print("")
+
+ print_section("Core Information", [
+ ("🧩 ID:", pid),
+ ("🎀 Name:", perf.get("name", "Unknown")),
+ ("🚺 Gender:", gender_icon(perf.get("gender", "-"))),
+ ("🌍 Country:", f"{perf.get('country', perf.get('nationality', '-'))} {country_flag(perf.get('country', perf.get('nationality', '')))}"),
+ ("🎂 Born:", calc_age(perf.get("birthdate", "-"))),
+ ("🧬 Ethnicity:", perf.get("ethnicity", "-")),
+ ])
+
+ print_section("Physical Attributes", [
+ ("💇 Hair:", perf.get("hair_color", "-")),
+ ("👁️ Eye color:", perf.get("eye_color", "-")),
+ ("📏 Height:", format_height(perf.get("height") or perf.get("height_cm"))),
+ ("⚖️ Weight:", format_weight(perf.get("weight") or perf.get("weight_kg"))),
+ ("🏋️ Body type:", perf.get("body_type", "-")),
+ ("📐 Measurements:", perf.get("measurements", "-")),
+ ])
+
+ print_section("Appearance Details", [
+ ("💉 Tattoos:", perf.get("tattoos", "-")),
+ ("💎 Piercings:", perf.get("piercings", "-")),
+ ("🍈 Breast size:", perf.get("breast_size", "-")),
+ ("🧴 Breast type:", perf.get("breast_type", "-")),
+ ])
+
+ print_section("Personal & Identity", [
+ ("⚧️ Orientation:", perf.get("orientation", "-")),
+ ("🧩 Aliases:", ", ".join(perf.get("aliases", [])) if perf.get("aliases") else "-"),
+ ])
+
+ print_section("Career", [
+ ("📅 Career start:", perf.get("career_start", "-")),
+ ("📆 Career end:", perf.get("career_end", "-")),
+ ])
+
+ stats = perf.get("stats") or {}
+ local_galleries = count_local_galleries_for_performer(perf.get("name", ""))
+ known_galleries = (
+ stats.get("total_galleries")
+ or stats.get("galleries")
+ or stats.get("total_scenes")
+ or perf.get("total_galleries")
+ or perf.get("total_scenes")
+ or 0
+ )
+ print_section("Activity Stats", [
+ ("📊 Local Galleries:", str(local_galleries)),
+ ("🖼️ PornPics Galleries:", str(known_galleries)),
+ ])
+
+ sources = perf.get("sources") or {}
+ if sources:
+ print(divider())
+ print(color("🔗 Sources:", "accent"))
+ for src, link in sources.items():
+ print(f" {color(src, 'grey')} → {color(link, 'white')}")
+ print(divider())
+
+# ============================================================
+# CLI Entrypoint
+# ============================================================
+def main():
+ if len(sys.argv) < 2:
+ print("Usage: gx search-performer [--json]")
+ sys.exit(1)
+
+ args = sys.argv[1:]
+ name_parts = [a for a in args if not a.startswith("--")]
+ flags = [a for a in args if a.startswith("--")]
+
+ name = " ".join(name_parts).strip()
+ output_json = "--json" in flags
+
+ db_perf = fetch_from_db(name)
+ json_perf = fetch_from_json(name)
+ def _score(d): return len([v for v in (d or {}).values() if v not in (None, "", "-", [], {})])
+ perf = json_perf if _score(json_perf) >= _score(db_perf) else db_perf
+
+ if not perf:
+ perf = fetch_remote_performer(name)
+ if not perf:
+ print(color(f"[✖] No performer found matching '{name}'", "brand"))
+ sys.exit(1)
+
+ if output_json:
+ print(json.dumps(perf, indent=2, ensure_ascii=False))
+ else:
+ display_performer(perf)
+
+if __name__ == "__main__":
+ main()
diff --git a/src/performers/sync/sync_all.py b/src/performers/sync/sync_all.py
new file mode 100644
index 0000000..ebb4529
--- /dev/null
+++ b/src/performers/sync/sync_all.py
@@ -0,0 +1,145 @@
+#!/usr/bin/env python3
+"""
+sync_all.py
+─────────────────────────────────────────────
+Goondex v0.3.5-r1 — Two-Way Performer Sync Manager
+
+Performs intelligent bidirectional synchronization between
+JSON performer files and the SQLite database:
+
+ • If JSON is newer → import into SQLite
+ • If SQLite is newer → export to JSON
+ • If timestamps match → skip
+
+Supports:
+ --fix-only → perform sync silently (no output except errors)
+ --silent → minimal logging (summary only)
+─────────────────────────────────────────────
+"""
+
+import sys
+import json
+from datetime import datetime
+from pathlib import Path
+from src.performers import db_manager
+
+# Directories
+JSON_DIR = Path("data/performers")
+
+
+# ─────────────────────────────────────────────
+# Helper functions
+# ─────────────────────────────────────────────
+def _parse_timestamp(ts: str | None) -> datetime:
+ """Safely parse an ISO timestamp or return datetime.min."""
+ try:
+ return datetime.fromisoformat(ts.replace("Z", ""))
+ except Exception:
+ return datetime.min
+
+
+def _log(message: str, fix_only: bool, silent: bool):
+ """Conditional logger respecting silent/fix-only flags."""
+ if fix_only:
+ return
+ if not silent:
+ print(message)
+
+
+# ─────────────────────────────────────────────
+# Core Sync Logic
+# ─────────────────────────────────────────────
+def main():
+ # Parse arguments
+ fix_only = "--fix-only" in sys.argv
+ silent = "--silent" in sys.argv or fix_only
+
+ if not silent:
+ print("\n[🔁] Goondex Two-Way Sync (JSON ↔ SQLite)")
+ print("─────────────────────────────────────────────")
+
+ db_manager.init_db()
+
+ # Collect JSON performers
+ json_files = list(JSON_DIR.glob("*/performer.json"))
+ json_map = {}
+ for jf in json_files:
+ try:
+ data = json.loads(jf.read_text(encoding="utf-8"))
+ performer_id = data.get("normalized_id") or data.get("id")
+ json_map[performer_id] = {
+ "path": jf,
+ "timestamp": _parse_timestamp(data.get("last_updated")),
+ }
+ except Exception as e:
+ _log(f"[⚠️] Skipping corrupted JSON: {jf} ({e})", fix_only, silent)
+
+ # Collect SQLite performers
+ with db_manager.get_conn() as conn:
+ cur = conn.execute("SELECT id, last_updated FROM performers;")
+ sql_rows = cur.fetchall()
+ sql_map = {r["id"]: _parse_timestamp(r["last_updated"]) for r in sql_rows}
+
+ synced_json_to_sqlite = []
+ synced_sqlite_to_json = []
+ skipped = []
+
+ # ─── Compare timestamps ─────────────────────────────
+ for pid, jdata in json_map.items():
+ jtime = jdata["timestamp"]
+ stime = sql_map.get(pid, datetime.min)
+
+ if jtime > stime:
+ db_manager.import_from_json(jdata["path"])
+ synced_json_to_sqlite.append(pid)
+ _log(f"[📥] Imported JSON → SQLite : {pid}", fix_only, silent)
+ elif stime > jtime:
+ db_manager.export_to_json(pid)
+ synced_sqlite_to_json.append(pid)
+ _log(f"[📤] Exported SQLite → JSON : {pid}", fix_only, silent)
+ else:
+ skipped.append(pid)
+
+ # ─── Handle DB-only performers ───────────────────────
+ for pid in sql_map.keys():
+ if pid not in json_map:
+ db_manager.export_to_json(pid)
+ synced_sqlite_to_json.append(pid)
+ _log(f"[➕] Created new JSON from DB : {pid}", fix_only, silent)
+
+ # ─── Handle JSON-only performers ─────────────────────
+ for pid in json_map.keys():
+ if pid not in sql_map:
+ db_manager.import_from_json(json_map[pid]["path"])
+ synced_json_to_sqlite.append(pid)
+ _log(f"[🆕] Imported new JSON into DB : {pid}", fix_only, silent)
+
+ # ─── Summary ─────────────────────────────────────────
+ if not fix_only:
+ if not silent:
+ print("─────────────────────────────────────────────")
+ print(f"[📥] JSON → SQLite imports : {len(synced_json_to_sqlite)}")
+ print(f"[📤] SQLite → JSON exports : {len(synced_sqlite_to_json)}")
+ print(f"[⏸] Skipped (no changes) : {len(skipped)}")
+ if not silent:
+ print("─────────────────────────────────────────────")
+ print(f"[📂] Database: {db_manager.DB_PATH}")
+ print(f"[📁] JSON dir: {JSON_DIR}")
+ print("─────────────────────────────────────────────")
+
+ # Optional verification
+ try:
+ db_manager.verify_json_integrity()
+ except Exception:
+ if not fix_only:
+ print("[⚠️] verify_json_integrity() not implemented — skipping check.")
+
+ if not silent:
+ print("[✅] Two-way sync complete.\n")
+
+
+# ─────────────────────────────────────────────
+# Entrypoint
+# ─────────────────────────────────────────────
+if __name__ == "__main__":
+ main()
diff --git a/src/performers/sync/sync_json_to_sqlite.py b/src/performers/sync/sync_json_to_sqlite.py
new file mode 100644
index 0000000..ae6d790
--- /dev/null
+++ b/src/performers/sync/sync_json_to_sqlite.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+"""
+sync_json_to_sqlite.py
+─────────────────────────────────────────────
+Bulk migrator for Goondex v0.3.5-r1
+
+Scans all per-performer JSON files under `data/performers/`
+and imports them into the SQLite database via db_manager.import_from_json().
+
+Usage:
+ python -m src.performers.sync_json_to_sqlite
+"""
+
+import sys
+from pathlib import Path
+from src.performers import db_manager
+
+# Base directory containing performer folders
+PERFORMERS_DIR = Path("data/performers")
+
+def main():
+ print("\n[🔄] Starting JSON → SQLite migration")
+ print("─────────────────────────────────────────────")
+
+ if not PERFORMERS_DIR.exists():
+ print(f"[!] No performer data found at {PERFORMERS_DIR}")
+ sys.exit(1)
+
+ db_manager.init_db()
+
+ json_files = sorted(PERFORMERS_DIR.glob("*/performer.json"))
+ if not json_files:
+ print("[!] No performer.json files detected.")
+ sys.exit(0)
+
+ imported_count = 0
+ for json_file in json_files:
+ try:
+ db_manager.import_from_json(json_file)
+ imported_count += 1
+ except Exception as e:
+ print(f"[ERROR] Failed to import {json_file}: {e}")
+
+ print("─────────────────────────────────────────────")
+ print(f"[✓] Imported {imported_count} performer record(s) into SQLite")
+ print(f"[📂] Database path: {db_manager.DB_PATH}")
+ print("─────────────────────────────────────────────")
+
+ # Optional post-check: list total performer count
+ total = db_manager.list_count()
+ print(f"[📊] Total performers now in DB: {total}\n")
+
+if __name__ == "__main__":
+ main()
diff --git a/src/performers/sync/sync_sqlite_to_json.py b/src/performers/sync/sync_sqlite_to_json.py
new file mode 100644
index 0000000..2b515d0
--- /dev/null
+++ b/src/performers/sync/sync_sqlite_to_json.py
@@ -0,0 +1,69 @@
+#!/usr/bin/env python3
+"""
+sync_sqlite_to_json.py
+─────────────────────────────────────────────
+Bulk exporter for Goondex v0.3.5-r1
+
+Exports all performer records from the SQLite database
+into per-performer JSON files under `data/performers//performer.json`.
+
+Usage:
+ python -m src.performers.sync_sqlite_to_json
+"""
+
+import sys
+from pathlib import Path
+from datetime import datetime
+from src.performers import db_manager
+
+# Base directory for JSON exports
+JSON_DIR = Path("data/performers")
+
+def main():
+ print("\n[💾] Starting SQLite → JSON export")
+ print("─────────────────────────────────────────────")
+
+ db_manager.init_db()
+
+ # Gather all performers from SQLite
+ with db_manager.get_conn() as conn:
+ cur = conn.execute("SELECT * FROM performers ORDER BY name ASC;")
+ rows = cur.fetchall()
+
+ if not rows:
+ print("[!] No performers found in database.")
+ sys.exit(0)
+
+ exported_count = 0
+ for row in rows:
+ try:
+ data = dict(row)
+ performer_id = data.get("id")
+ folder = JSON_DIR / performer_id
+ folder.mkdir(parents=True, exist_ok=True)
+ json_path = folder / "performer.json"
+
+ # Add compatibility metadata
+ data.setdefault("faces", [])
+ data.setdefault("aliases", [])
+ data.setdefault("source_urls", [])
+ data.setdefault("stats", {"known_galleries": 0, "studio_appearances": {}})
+ data["last_updated"] = datetime.utcnow().isoformat()
+
+ json_path.write_text(db_manager.json.dumps(data, indent=2, ensure_ascii=False), encoding="utf-8")
+ exported_count += 1
+ except Exception as e:
+ print(f"[ERROR] Failed to export performer {row.get('id')}: {e}")
+
+ print("─────────────────────────────────────────────")
+ print(f"[✓] Exported {exported_count} performer record(s) to JSON")
+ print(f"[📂] JSON output directory: {JSON_DIR}")
+ print("─────────────────────────────────────────────")
+
+ # Optional verification
+ total = db_manager.list_count()
+ print(f"[📊] Total performers in DB: {total}")
+ print(f"[🧾] Total JSON directories: {len(list(JSON_DIR.glob('*/performer.json')))}\n")
+
+if __name__ == "__main__":
+ main()
diff --git a/src/performers/tpdb_bridge.py b/src/performers/tpdb_bridge.py
index 01cb163..eb79ccd 100644
--- a/src/performers/tpdb_bridge.py
+++ b/src/performers/tpdb_bridge.py
@@ -1,7 +1,8 @@
+#!/usr/bin/env python3
"""
-tpdb_bridge.py — v0.3.8
+tpdb_bridge.py — v0.3.6
─────────────────────────────────────────────
-Bridge between Porndex importer and ThePornDatabase (TPDB).
+Bridge between Goondex importer and ThePornDatabase (TPDB).
Provides:
- fetch → Pull performers from TPDB and import into local DB.
@@ -15,17 +16,27 @@ Provides:
- add-source → Manually link a performer to a source/channel.
- delete-source → Remove a performer-source relationship.
- verify-enrichment → Show enrichment progress or export JSON summary.
+
+Enhancements (v0.3.6):
+ - Integrated cli_colours for branded output.
+ - Streamlined INFO/WARN/ERROR/SAVE/DONE messages.
+ - Header banner for CLI launch.
"""
import json
import requests
import argparse
import time
+import os
from pathlib import Path
from typing import List, Dict, Any
from datetime import datetime, timedelta
+from textwrap import shorten
-from performers.db_manager import (
+# Colour utilities
+from src.utils.cli_colours import heading, pink, cyan, grey, white, yellow
+
+from src.performers.db_manager import (
add_or_update_performer,
init_db,
get_conn,
@@ -34,14 +45,34 @@ from performers.db_manager import (
upgrade_source_channel,
delete_source_link,
)
-from performers.utils import normalize_name
+from src.performers.utils import (
+ normalize_name,
+ ensure_performer_exists,
+ update_performer_record,
+ save_json,
+ get_performer_path,
+)
# ─────────────────────────────────────────────
# API configuration
# ─────────────────────────────────────────────
+
API_BASE = "https://api.theporndb.net"
API_KEY_ENV = "TPDB_API_KEY"
+
+# --- Flexible key file resolution ---
LOCAL_KEY_FILE = Path(__file__).resolve().parents[1] / "importer" / "secrets" / "tpdb_api_key.txt"
+if not LOCAL_KEY_FILE.exists():
+ # Fallback for alternate layout (e.g. Goondex/importer/secrets/)
+ alt_path = Path(__file__).resolve().parents[2] / "importer" / "secrets" / "tpdb_api_key.txt"
+ if alt_path.exists():
+ LOCAL_KEY_FILE = alt_path
+ else:
+ # Final fallback using current working directory
+ cwd_path = Path.cwd() / "src" / "importer" / "secrets" / "tpdb_api_key.txt"
+ if cwd_path.exists():
+ LOCAL_KEY_FILE = cwd_path
+
REPORT_DIR = Path(__file__).resolve().parents[1] / "importer" / "reports"
LOCAL_KEY_FILE.parent.mkdir(parents=True, exist_ok=True)
REPORT_DIR.mkdir(parents=True, exist_ok=True)
@@ -51,12 +82,17 @@ REPORT_DIR.mkdir(parents=True, exist_ok=True)
# Helpers
# ─────────────────────────────────────────────
def _load_api_key() -> str | None:
- import os
+ """Load TPDB API key from environment or local secrets file."""
env_key = os.getenv(API_KEY_ENV)
if env_key:
return env_key.strip()
+
if LOCAL_KEY_FILE.exists():
- return LOCAL_KEY_FILE.read_text().strip()
+ try:
+ return LOCAL_KEY_FILE.read_text(encoding="utf-8").strip()
+ except Exception:
+ return None
+
return None
@@ -72,36 +108,35 @@ def _export_json_report(report: dict):
path = REPORT_DIR / f"enrichment_status_{timestamp}.json"
with open(path, "w", encoding="utf-8") as f:
json.dump(report, f, indent=2, ensure_ascii=False)
- print(f"[💾] Exported JSON report → {path}")
+ print(pink(f"[SAVE] Exported JSON report → {path}"))
# ─────────────────────────────────────────────
# Base Fetch Logic
# ─────────────────────────────────────────────
def fetch_tpdb_performers(limit: int = 100, page: int = 1) -> List[Dict[str, Any]]:
- """Fetch performers from TPDB."""
api_key = _load_api_key()
if not api_key:
- print(f"[!] No API key. Set {API_KEY_ENV}= or put the key in {LOCAL_KEY_FILE}")
+ print(yellow(f"[ERROR] No API key. Set {API_KEY_ENV}= or put it in {LOCAL_KEY_FILE}"))
return []
per_page = min(max(limit, 1), 1000)
- print(f"[🌐] Fetching performers from TPDB (page={page}, per_page={per_page})")
+ print(cyan(f"[INFO] Fetching performers from TPDB (page={page}, per_page={per_page})"))
try:
resp = _http_get("/performers", params={"page": page, "per_page": per_page}, api_key=api_key)
except requests.RequestException as e:
- print(f"[!] Network error contacting TPDB: {e}")
+ print(yellow(f"[WARN] Network error contacting TPDB: {e}"))
return []
if resp.status_code != 200:
- print(f"[!] TPDB API returned {resp.status_code}: {resp.text[:200]}")
+ print(yellow(f"[WARN] TPDB API returned {resp.status_code}: {resp.text[:200]}"))
return []
try:
payload = resp.json()
except json.JSONDecodeError:
- print("[!] TPDB response was not valid JSON")
+ print(yellow("[ERROR] TPDB response was not valid JSON"))
return []
raw_list = payload.get("data") or payload.get("results") or []
@@ -134,24 +169,71 @@ def fetch_tpdb_performers(limit: int = 100, page: int = 1) -> List[Dict[str, Any
return performers
+# ─────────────────────────────────────────────
+# Single Performer Fetch (used by enrichment_bridge)
+# ─────────────────────────────────────────────
+def fetch_tpdb_performer(name: str) -> dict | None:
+ """
+ Fetch a single performer by name from TPDB.
+ Returns a dict of performer data, or None if not found.
+ """
+ api_key = _load_api_key()
+ if not api_key:
+ print(yellow(f"[ERROR] No API key found in {API_KEY_ENV} or {LOCAL_KEY_FILE}"))
+ return None
+
+ try:
+ resp = _http_get("/performers", params={"name": name, "per_page": 1}, api_key=api_key)
+ if resp.status_code != 200:
+ print(yellow(f"[WARN] TPDB returned {resp.status_code} for performer {name}"))
+ return None
+
+ payload = resp.json()
+ data = payload.get("data") or payload.get("results") or []
+ if not data:
+ return None
+
+ p = data[0]
+ performer = {
+ "id": str(p.get("id")),
+ "name": p.get("name"),
+ "url": p.get("url") or f"https://theporndb.net/performer/{p.get('id')}",
+ "aliases": p.get("aliases") or [],
+ "gender": p.get("gender") or "Unknown",
+ "birthdate": p.get("birthdate"),
+ "ethnicity": p.get("ethnicity"),
+ "hair_color": p.get("hair_color"),
+ "eye_color": p.get("eye_color"),
+ "height_cm": p.get("height"),
+ "measurements": p.get("measurements"),
+ "nationality": p.get("nationality"),
+ "country_code": p.get("country"),
+ "image": p.get("image"),
+ "tags": ", ".join(p.get("tags", [])) if isinstance(p.get("tags"), list) else p.get("tags"),
+ }
+ return performer
+ except Exception as e:
+ print(yellow(f"[ERROR] Failed to fetch {name}: {e}"))
+ return None
+
+
+
# ─────────────────────────────────────────────
# Import / Fill Logic
# ─────────────────────────────────────────────
def import_tpdb_to_db(limit: int = 100):
- """Fetch performers from TPDB and store them in the local DB."""
init_db()
performers = fetch_tpdb_performers(limit=limit)
for p in performers:
add_or_update_performer(p)
add_or_update_source(p["id"], source_name="TPDB", channel_name="Unknown")
- print(f"[💾] Imported {len(performers)} performers into local DB (default source: TPDB/Unknown).")
+ print(pink(f"[SAVE] Imported {len(performers)} performers into local DB (TPDB/Unknown)."))
def fill_index(limit: int = 1000):
- """Continuously fetch performers page by page until no more results."""
api_key = _load_api_key()
if not api_key:
- print(f"[!] No API key found in {API_KEY_ENV} or {LOCAL_KEY_FILE}")
+ print(yellow(f"[ERROR] No API key found in {API_KEY_ENV} or {LOCAL_KEY_FILE}"))
return
init_db()
@@ -162,7 +244,7 @@ def fill_index(limit: int = 1000):
for page in range(1, max_pages + 1):
batch = fetch_tpdb_performers(limit=per_page, page=page)
if not batch:
- print(f"[ℹ️] No more performers after page {page}.")
+ print(grey(f"[INFO] No more performers after page {page}."))
break
for p in batch:
@@ -170,20 +252,19 @@ def fill_index(limit: int = 1000):
add_or_update_source(p["id"], source_name="TPDB", channel_name="Unknown")
total_imported += 1
- print(f"[📥] Page {page} imported ({len(batch)} performers) — total so far: {total_imported}")
+ print(cyan(f"[INFO] Page {page} imported ({len(batch)} performers) — total: {total_imported}"))
time.sleep(0.5)
if total_imported >= limit:
break
- print(f"[✅] Fill-index complete. Total imported: {total_imported}")
+ print(white(f"[DONE] Fill-index complete. Total imported: {total_imported}"))
# ─────────────────────────────────────────────
# Scene-based Enrichment Helper
# ─────────────────────────────────────────────
def _fetch_studio_from_scenes(performer_id: str, api_key: str) -> str | None:
- """Try to infer performer’s studio/channel by checking their recent scenes."""
try:
resp = _http_get(f"/performers/{performer_id}/scenes", params={"per_page": 3}, api_key=api_key)
if resp.status_code != 200:
@@ -202,7 +283,7 @@ def _fetch_studio_from_scenes(performer_id: str, api_key: str) -> str | None:
# ─────────────────────────────────────────────
-# Enrichment Logic
+# Enrichment Logic (with optional JSON mirroring)
# ─────────────────────────────────────────────
def enrich_performers(
limit: int = 50,
@@ -212,11 +293,11 @@ def enrich_performers(
debug_channels: bool = False,
use_scenes: bool = False,
export_json: bool = False,
+ mirror_json: bool = False,
):
- """Fetch detailed performer metadata with selective enrichment options."""
api_key = _load_api_key()
if not api_key:
- print(f"[!] No API key found in {API_KEY_ENV} or {LOCAL_KEY_FILE}")
+ print(yellow(f"[ERROR] No API key found in {API_KEY_ENV} or {LOCAL_KEY_FILE}"))
return
init_db()
@@ -229,7 +310,7 @@ def enrich_performers(
"ORDER BY s.last_seen ASC LIMIT ?;"
)
performers = conn.execute(query, (limit,)).fetchall()
- print(f"[🔁] Retrying enrichment for {len(performers)} unknown performers...")
+ print(cyan(f"[INFO] Retrying enrichment for {len(performers)} unknown performers..."))
elif stale_days:
cutoff = (datetime.utcnow() - timedelta(days=stale_days)).isoformat()
query = (
@@ -239,7 +320,7 @@ def enrich_performers(
"ORDER BY s.last_seen ASC LIMIT ?;"
)
performers = conn.execute(query, (cutoff, limit)).fetchall()
- print(f"[🕒] Re-enriching performers older than {stale_days} days ({len(performers)} found)...")
+ print(cyan(f"[INFO] Re-enriching performers older than {stale_days} days ({len(performers)} found)..."))
else:
query = (
"SELECT id, name FROM performers "
@@ -249,7 +330,7 @@ def enrich_performers(
else "SELECT id, name FROM performers ORDER BY last_updated ASC LIMIT ?;"
)
performers = conn.execute(query, (limit,)).fetchall()
- print(f"[🔍] Enriching {len(performers)} performers...")
+ print(cyan(f"[INFO] Enriching {len(performers)} performers..."))
enriched_count = 0
upgraded_count = 0
@@ -261,7 +342,7 @@ def enrich_performers(
resp = _http_get(f"/performers/{pid}", api_key=api_key)
if resp.status_code != 200:
if debug_channels:
- print(f"[⚠️] Skipping {name}: {resp.status_code}")
+ print(yellow(f"[WARN] Skipping {name}: {resp.status_code}"))
continue
pdata = resp.json().get("data") or resp.json()
@@ -286,10 +367,8 @@ def enrich_performers(
add_or_update_performer(perf)
- # detect studio/network
- possible_keys = ["studio", "network", "channel", "label", "production", "site"]
studio = None
- for key in possible_keys:
+ for key in ["studio", "network", "channel", "label", "production", "site"]:
val = pdata.get(key)
if val:
studio = val if isinstance(val, str) else val.get("name")
@@ -304,26 +383,39 @@ def enrich_performers(
upgrade_source_channel(pid, source_name="TPDB", new_channel_name=studio.strip())
upgraded_count += 1
if debug_channels:
- emoji = "🎞" if use_scenes else "🎬"
- print(f"[{emoji}] {name:<30} → '{studio}'")
+ print(grey(f"[INFO] {name:<30} → '{studio}'"))
else:
add_or_update_source(pid, "TPDB", "Unknown")
if debug_channels:
- print(f"[⚫] {name:<30} → no channel info found")
+ print(grey(f"[INFO] {name:<30} → no channel info found"))
+
+ if mirror_json:
+ local_json = ensure_performer_exists(name)
+ updates = {
+ "sources": {"tpdb": perf.get("url")},
+ "gender": perf.get("gender"),
+ "ethnicity": perf.get("ethnicity"),
+ "hair_color": perf.get("hair_color"),
+ "eye_color": perf.get("eye_color"),
+ "height_cm": perf.get("height_cm"),
+ "birth_date": perf.get("birthdate"),
+ "country": perf.get("nationality"),
+ }
+ record = update_performer_record(local_json, updates)
+ save_json(record, get_performer_path(name))
enriched_count += 1
time.sleep(0.25)
except Exception as e:
- print(f"[!] Error enriching {name}: {e}")
+ print(yellow(f"[ERROR] Enrichment failed for {name}: {e}"))
- print(f"[✅] Enrichment complete: {enriched_count}/{len(performers)} updated.")
- print(f"[📈] Upgraded channels: {upgraded_count} (inferred via scenes: {inferred_count})")
+ print(pink(f"[DONE] Enrichment complete: {enriched_count}/{len(performers)} updated."))
+ print(grey(f"[INFO] Upgraded channels: {upgraded_count} (inferred via scenes: {inferred_count})"))
if export_json:
report = verify_enrichment_status(limit=20, return_json=True)
_export_json_report(report)
-
# ─────────────────────────────────────────────
# Sync Logic
# ─────────────────────────────────────────────
@@ -370,7 +462,7 @@ def sync_all(limit: int = 5000, batch_size: int = 100, enrich_every: int = 2):
# ─────────────────────────────────────────────
-# CLI + Verification
+# CLI + Verification / Reports
# ─────────────────────────────────────────────
def list_performers(limit: int = 20):
from textwrap import shorten
@@ -485,7 +577,7 @@ def delete_source(performer_id: str, source_name: str):
# CLI Entrypoint
# ─────────────────────────────────────────────
def main():
- parser = argparse.ArgumentParser(description="TPDB Bridge — Porndex Performer Importer")
+ parser = argparse.ArgumentParser(description="TPDB Bridge — Porndex/Goondex Performer Importer")
sub = parser.add_subparsers(dest="command")
# --- Fetch / Fill ---
@@ -501,6 +593,7 @@ def main():
sync_p.add_argument("--enrich-every", type=int, default=2)
# --- Enrichment ---
+ # Original enrich command
enrich_p = sub.add_parser("enrich", help="Update performer metadata from TPDB")
enrich_p.add_argument("--limit", type=int, default=50)
enrich_p.add_argument("--no-skip", action="store_true", help="Include already enriched performers")
@@ -509,6 +602,18 @@ def main():
enrich_p.add_argument("--debug-channels", action="store_true", help="Print detailed channel resolution output")
enrich_p.add_argument("--use-scenes", action="store_true", help="Infer missing channels from scene listings")
enrich_p.add_argument("--export-json", action="store_true", help="Export a JSON enrichment report after completion")
+ enrich_p.add_argument("--mirror-json", action="store_true", help="Mirror enriched performer data into JSON files")
+
+ # Unified Goondex syntax alias: goondex tpdb-enrich
+ enrich_alias = sub.add_parser("tpdb-enrich", help="Alias of 'enrich' for Goondex CLI consistency")
+ enrich_alias.add_argument("--limit", type=int, default=50)
+ enrich_alias.add_argument("--no-skip", action="store_true")
+ enrich_alias.add_argument("--retry-unknowns", action="store_true")
+ enrich_alias.add_argument("--stale-days", type=int)
+ enrich_alias.add_argument("--debug-channels", action="store_true")
+ enrich_alias.add_argument("--use-scenes", action="store_true")
+ enrich_alias.add_argument("--export-json", action="store_true")
+ enrich_alias.add_argument("--mirror-json", action="store_true")
# --- Listing & Reports ---
list_p = sub.add_parser("list", help="List performers in database")
@@ -541,36 +646,48 @@ def main():
# --- Command Dispatch ---
if args.command == "fetch":
import_tpdb_to_db(args.limit)
+
elif args.command == "fill-index":
fill_index(args.limit)
+
elif args.command == "sync-all":
sync_all(args.limit, args.batch_size, args.enrich_every)
- elif args.command == "enrich":
+
+ elif args.command in ("enrich", "tpdb-enrich"):
enrich_performers(
- limit=args.limit,
- skip_existing=not args.no_skip,
- retry_unknowns=args.retry_unknowns,
- stale_days=args.stale_days,
- debug_channels=args.debug_channels,
- use_scenes=args.use_scenes,
- export_json=args.export_json,
+ limit=getattr(args, "limit", 50),
+ skip_existing=not getattr(args, "no_skip", False),
+ retry_unknowns=getattr(args, "retry_unknowns", False),
+ stale_days=getattr(args, "stale_days", None),
+ debug_channels=getattr(args, "debug_channels", False),
+ use_scenes=getattr(args, "use_scenes", False),
+ export_json=getattr(args, "export_json", False),
+ mirror_json=getattr(args, "mirror_json", False),
)
+
elif args.command == "list":
list_performers(args.limit)
+
elif args.command == "export-json":
export_json(args.limit)
+
elif args.command == "check-key":
check_api_key()
+
elif args.command == "verify-enrichment":
report = verify_enrichment_status(limit=args.limit, return_json=args.export_json)
if args.export_json and report:
_export_json_report(report)
+
elif args.command == "list-sources":
list_all_sources(args.limit)
+
elif args.command == "add-source":
add_source_link(args.performer_id, args.source_name, args.channel_name)
+
elif args.command == "delete-source":
delete_source(args.performer_id, args.source_name)
+
else:
parser.print_help()
diff --git a/src/performers/utils.py b/src/performers/utils.py
index feabf64..003fad0 100644
--- a/src/performers/utils.py
+++ b/src/performers/utils.py
@@ -1,25 +1,178 @@
+#!/usr/bin/env python3
+"""
+utils.py
+---------
+Shared utilities for the Goondex Performer Recognition System.
+
+This module now integrates tightly with schema.py to ensure
+all performer records follow the canonical Goondex performer schema.
+
+Responsibilities:
+ - Name normalization
+ - JSON read/write helpers
+ - Schema validation proxy
+ - Path resolution for performer data
+
+All performer-related modules (scraper, trainer, verifier, TPDB bridge)
+should import from here to guarantee consistent behavior.
+
+Example usage:
+ from src.performers.utils import (
+ normalize_name,
+ ensure_performer_exists,
+ load_json,
+ save_json
+ )
+
+ performer = ensure_performer_exists("Riley Reid")
+"""
+
import re
import json
from pathlib import Path
+from datetime import datetime
+from typing import Optional, Dict, Any
+
+# Import schema utilities
+from src.performers.schema import (
+ ensure_performer_schema,
+ validate_performer_data,
+ create_blank_performer,
+ load_performer_json,
+ save_performer_json,
+ normalize_id
+)
+
+# ============================================================
+# Core Path Constants
+# ============================================================
+
+DATA_DIR = Path("data/performers")
+DATA_DIR.mkdir(parents=True, exist_ok=True)
+
+# ============================================================
+# Utility Functions
+# ============================================================
def normalize_name(name: str) -> str:
"""
Normalizes performer names into lowercase alphanumeric IDs.
Example: 'Lulu Chu' -> 'lulu_chu'
"""
- name = name.strip().lower()
- name = re.sub(r'[^a-z0-9]+', '_', name)
- return name.strip('_')
+ return normalize_id(name)
-def save_json(data, path: Path):
- """Safely saves JSON to disk."""
+
+def get_performer_path(name: str) -> Path:
+ """
+ Returns the expected JSON path for a given performer.
+ Example:
+ get_performer_path("Riley Reid")
+ -> data/performers/riley_reid/performer.json
+ """
+ return DATA_DIR / normalize_name(name) / "performer.json"
+
+
+def save_json(data: Dict[str, Any], path: Path):
+ """
+ Safely saves JSON to disk with UTF-8 encoding and indentation.
+ Creates directories automatically.
+ """
path.parent.mkdir(parents=True, exist_ok=True)
with open(path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=2, ensure_ascii=False)
-def load_json(path: Path):
- """Loads JSON if available, otherwise returns None."""
+
+def load_json(path: Path) -> Optional[Dict[str, Any]]:
+ """
+ Loads JSON from disk if available.
+ Returns None if the file doesn't exist or is unreadable.
+ """
if not path.exists():
return None
- with open(path, "r", encoding="utf-8") as f:
- return json.load(f)
+ try:
+ with open(path, "r", encoding="utf-8") as f:
+ return json.load(f)
+ except json.JSONDecodeError:
+ print(f"[WARN] JSON file corrupted: {path}")
+ return None
+
+
+# ============================================================
+# Performer Schema Integration
+# ============================================================
+
+def create_performer_record(name: str) -> Dict[str, Any]:
+ """
+ Create a new performer record following the standard schema.
+
+ Args:
+ name (str): Performer name (e.g. 'Riley Reid')
+
+ Returns:
+ dict: A fully initialized performer record ready for use.
+ """
+ data = create_blank_performer(name)
+ path = get_performer_path(name)
+ save_performer_json(path, data)
+ return data
+
+
+def update_performer_record(base: dict, updates: dict) -> dict:
+ """
+ Shallow merges updates into a performer record.
+ Used by scraper and TPDB bridge to merge partial data.
+ """
+ for key, value in updates.items():
+ if isinstance(value, dict) and key in base:
+ base[key].update(value)
+ else:
+ base[key] = value
+
+ base["last_updated"] = datetime.utcnow().isoformat(timespec="seconds") + "Z"
+ return base
+
+
+def ensure_performer_exists(name: str) -> Dict[str, Any]:
+ """
+ Ensures performer.json exists, is valid, and follows schema.
+ Returns a validated performer record dictionary.
+ """
+ performer_dir = DATA_DIR / normalize_name(name)
+ performer_file = performer_dir / "performer.json"
+
+ performer_file = ensure_performer_schema(name, DATA_DIR)
+ data = load_performer_json(performer_file)
+ return data
+
+
+def list_all_performers() -> list[str]:
+ """
+ Returns a list of all performer folders currently in data/performers.
+ """
+ if not DATA_DIR.exists():
+ return []
+ return [p.name for p in DATA_DIR.iterdir() if p.is_dir()]
+
+
+# ============================================================
+# Compatibility & Helper Hooks
+# ============================================================
+
+def repair_all_performers():
+ """
+ Validates all performer.json files in data/performers.
+ Repairs structure if necessary.
+ """
+ count = 0
+ for folder in DATA_DIR.iterdir():
+ if not folder.is_dir():
+ continue
+ file = folder / "performer.json"
+ if file.exists():
+ try:
+ data = load_performer_json(file)
+ save_performer_json(file, validate_performer_data(data))
+ count += 1
+ except Exception as e:
+ print(f"[WARN] Skipped invalid performer {folder.name}: {e}")
+ print(f"[OK] Repaired {count} performer record(s).")
diff --git a/src/utils/cli_colours.py b/src/utils/cli_colours.py
new file mode 100644
index 0000000..bfba805
--- /dev/null
+++ b/src/utils/cli_colours.py
@@ -0,0 +1,81 @@
+#!/usr/bin/env python3
+"""
+cli_colours.py — Goondex Terminal Colour Helper
+───────────────────────────────────────────────
+Centralised ANSI colour definitions for Goondex CLI output.
+Keeps all modules visually consistent (importer, TPDB bridge,
+performer search, ML tools, etc.)
+
+Palette — Flamingo Pulse theme:
+ pink → primary accent
+ lilac → secondary accent
+ cyan → highlight / link
+ yellow → warning / info
+ white → base text
+ grey → muted / subtle
+ reset → reset sequence
+"""
+
+# ANSI escape sequences
+_RESET = "\033[0m"
+
+# Brand palette (Flamingo Pulse inspired)
+PINK = "\033[38;5;205m" # vivid magenta-pink
+LILAC = "\033[38;5;177m" # soft violet accent
+CYAN = "\033[38;5;123m" # turquoise-cyan for links
+YELLOW = "\033[38;5;228m" # bright pastel yellow
+WHITE = "\033[38;5;255m" # near-white text
+GREY = "\033[38;5;246m" # neutral soft grey
+BOLD = "\033[1m"
+DIM = "\033[2m"
+
+# ─────────────────────────────────────────────
+# Helper functions for inline use
+# ─────────────────────────────────────────────
+def pink(text: str) -> str:
+ return f"{PINK}{text}{_RESET}"
+
+def lilac(text: str) -> str:
+ return f"{LILAC}{text}{_RESET}"
+
+def cyan(text: str) -> str:
+ return f"{CYAN}{text}{_RESET}"
+
+def yellow(text: str) -> str:
+ return f"{YELLOW}{text}{_RESET}"
+
+def white(text: str) -> str:
+ return f"{WHITE}{text}{_RESET}"
+
+def grey(text: str) -> str:
+ return f"{GREY}{text}{_RESET}"
+
+def bold(text: str) -> str:
+ return f"{BOLD}{text}{_RESET}"
+
+def dim(text: str) -> str:
+ return f"{DIM}{text}{_RESET}"
+
+# ─────────────────────────────────────────────
+# Composite helpers
+# ─────────────────────────────────────────────
+def heading(title: str, icon: str = "💖", version: str | None = None) -> str:
+ """Generate a styled Goondex section header."""
+ bar = grey("─" * 45)
+ ver = f" · {grey(version)}" if version else ""
+ return f"\n{bar}\n{pink(icon)} {bold(white(title))}{ver}\n{bar}"
+
+def success(msg: str) -> str:
+ return f"{WHITE}✅ {msg}{_RESET}"
+
+def warning(msg: str) -> str:
+ return f"{YELLOW}⚠️ {msg}{_RESET}"
+
+def error(msg: str) -> str:
+ return f"{PINK}❌ {msg}{_RESET}"
+
+def info(msg: str) -> str:
+ return f"{CYAN}ℹ️ {msg}{_RESET}"
+
+def muted(msg: str) -> str:
+ return f"{GREY}{msg}{_RESET}"
diff --git a/src/utils/install_alias.fish b/src/utils/install_alias.fish
index 3e555d2..980ab5b 100755
--- a/src/utils/install_alias.fish
+++ b/src/utils/install_alias.fish
@@ -1,70 +1,95 @@
#!/usr/bin/env fish
# ============================================================
-# Goondex CLI Alias Installer (Fish-native)
+# Goondex CLI — Unified Alias Function (Fish)
# ============================================================
-# Creates a persistent 'goondex' command so you can run:
-# goondex import
-# goondex trainer
-# goondex verify [tags]
-# goondex search-performer
+# Supports:
+# Importer / Tagging: goondex import, goondex refresh-all, etc.
+# ML Facecrop Tools: goondex trainer, goondex verify
+# Performer Database: goondex search-performer, goondex tpdb-enrich
# ============================================================
-set project_root (pwd)
-set venv_path "$project_root/.venv/bin/python"
-set config_file "$HOME/.config/fish/config.fish"
-
-echo "Installing Goondex CLI alias for Fish..."
-
-# Verify virtual environment exists
-if not test -f $venv_path
- echo "Error: Virtual environment not found at $venv_path"
- echo "Please create it with: python -m venv .venv"
- exit 1
-end
-
-# ------------------------------------------------------------
-# Define the unified goondex command function
-# ------------------------------------------------------------
-set function_block "
function goondex
- set cmd \$argv[1]
- set args \$argv[2..-1]
+ set cmd $argv[1]
+ set args $argv[2..-1]
+ set project_root /home/stu/Projects/PD/Goondex
+ set venv_path $project_root/.venv/bin/python
+ set -x PYTHONPATH $project_root/src
- switch \$cmd
- case import
- $venv_path -m importer.cli \$args
+ switch $cmd
+ # --- Importer CLI (preserves all original commands) ---
+ case '' -h --help help
+ echo ""
+ echo "Goondex CLI — Unified Interface"
+ echo "────────────────────────────────────────────"
+ echo ""
+ echo "Usage: goondex [args]"
+ echo ""
+ echo "Core Importer Commands:"
+ echo " import Import a new gallery from PornPics"
+ echo " refresh-all Refresh tags for all galleries"
+ echo " refresh-one Refresh tags for a single gallery"
+ echo " validate-tags Validate YAML tag dictionaries"
+ echo " tag-stats Generate tag frequency report"
+ echo " list List all available galleries"
+ echo " list-tags Show tags for one gallery"
+ echo " add Add a tag manually"
+ echo " remove Remove a tag manually"
+ echo " add-multi \"A,B\" Add multiple tags at once"
+ echo " show-metadata Show metadata.json contents"
+ echo " source set Set gallery source"
+ echo ""
+ echo "Machine Learning (Face Recognition):"
+ echo " trainer Train face embeddings from ML/faces_cache/"
+ echo " verify [tags] Verify performer face image similarity"
+ echo ""
+ echo "Performers & Metadata:"
+ echo " search-performer Search local performer records"
+ echo " tpdb-enrich Sync or mirror metadata from ThePornDB"
+ echo ""
+ echo "Utilities:"
+ echo " --help / -h / help Show this help menu"
+ echo " --version / -v / version Show current Goondex version"
+ echo ""
+ echo "Examples:"
+ echo " goondex import \"https://www.pornpics.com/galleries/example/\""
+ echo " goondex refresh-one \"20251106_2041_Madison_Young_ATK_Archives\""
+ echo " goondex trainer"
+ echo " goondex verify ./ML/faces_cache/face_001.jpg \"Riley Reid,Eva Lovia\""
+ echo ""
+ echo "────────────────────────────────────────────"
+ echo "Goondex v0.3.4 — Leak Technologies (2025)"
+ echo ""
+ return
+
+ case import refresh-all refresh-one validate-tags tag-stats list list-tags add remove add-multi show-metadata source
+ $venv_path -m src.importer.cli $cmd $args
+ return
+
+ # --- Machine Learning (Facecrop / Recognition) ---
case trainer
- $venv_path -m src.ml.facecrop.trainer \$args
+ $venv_path -m src.ml.facecrop.trainer $args
+ return
case verify
- $venv_path -m src.ml.facecrop.verifier \$args
+ $venv_path -m src.ml.facecrop.verifier $args
+ return
+
+ # --- Performer Database & Metadata Enrichment ---
case search-performer
- $venv_path -m src.performers.search \$args
- case help '*'
- echo 'Goondex CLI Commands:'
- echo ' goondex import - Import a gallery'
- echo ' goondex trainer - Batch verify cropped faces'
- echo ' goondex verify [tags] - Verify a single face'
- echo ' goondex search-performer - Search performer database'
+ $venv_path -m src.performers.search $args
+ return
+ case tpdb-enrich
+ $venv_path -m src.performers.tpdb_bridge $args
+ return
+
+ # --- Version shortcut ---
+ case -v --version version
+ echo "Goondex v0.3.4 — Leak Technologies"
+ return
+
+ # --- Fallback for unknown commands ---
case '*'
- echo 'Unknown command. Use: goondex help'
+ echo "[!] Unknown command: $cmd"
+ echo "Use 'goondex --help' for full command list."
+ return
end
end
-"
-
-# ------------------------------------------------------------
-# Inject function into config if not already present
-# ------------------------------------------------------------
-if not grep -q "function goondex" $config_file
- echo $function_block >> $config_file
- echo "[+] Added goondex function to $config_file"
-else
- echo "[=] Goondex function already defined in $config_file"
-end
-
-# ------------------------------------------------------------
-# Apply immediately
-# ------------------------------------------------------------
-echo "Reloading Fish config..."
-source $config_file
-
-echo "✅ Setup complete. Try: goondex help"
diff --git a/src/utils/setup_fish_goondex.fish b/src/utils/setup_fish_goondex.fish
index 6ea8fe2..8f3194f 100644
--- a/src/utils/setup_fish_goondex.fish
+++ b/src/utils/setup_fish_goondex.fish
@@ -1,11 +1,13 @@
#!/usr/bin/env fish
# ============================================================
-# Goondex CLI Fish Setup Script
-# Leak Technologies — v0.3.5 (2025-10-07)
-# ============================================================
-# Ensures the Goondex CLI is properly installed, removes old
-# aliases, installs the canonical function, reloads Fish,
-# and verifies environment consistency.
+# File: src/utils/setup_fish_goondex.fish
+# Version: v0.3.5-r2
+# ------------------------------------------------------------
+# Goondex CLI Fish Setup Utility
+# ------------------------------------------------------------
+# Ensures the Goondex CLI is installed, removes old aliases,
+# installs canonical functions, reloads Fish, and guarantees
+# alias persistence for 'goondex' and 'gx'.
# ============================================================
set project_root /home/stu/Projects/PD/Goondex
@@ -22,7 +24,7 @@ if not test -d $fish_func_dir
end
# ------------------------------------------------------------
-# 2. Remove legacy aliases or duplicate definitions
+# 2. Clean up any legacy aliases or function definitions
# ------------------------------------------------------------
echo "[*] Cleaning up old Goondex aliases and inline definitions..."
functions -e goondex 2>/dev/null
@@ -32,25 +34,17 @@ if test -f ~/.config/fish/config.fish
set tmpfile (mktemp)
grep -vE 'alias[[:space:]]+goondex|alias[[:space:]]+gx|function[[:space:]]+goondex' ~/.config/fish/config.fish > $tmpfile
mv $tmpfile ~/.config/fish/config.fish
- echo "[+] Removed any old inline goondex/gx definitions from config.fish"
+ echo "[+] Removed old inline goondex/gx definitions from config.fish"
end
# ------------------------------------------------------------
-# 3. Install canonical Goondex function
+# 3. Install canonical goondex.fish function
# ------------------------------------------------------------
echo "[*] Installing canonical goondex.fish function..."
begin
echo '#!/usr/bin/env fish'
- echo '# ============================================================'
echo '# Goondex CLI — Unified Function (Fish)'
- echo '# ============================================================'
- echo '# Supports:'
- echo '# Importer / Tagging: goondex import, refresh-all, etc.'
- echo '# ML Facecrop Tools: goondex trainer, goondex verify'
- echo '# Performer Database: goondex search-performer, tpdb-enrich'
- echo '# ============================================================'
- echo ''
echo 'function goondex'
echo ' set cmd $argv[1]'
echo ' set args $argv[2..-1]'
@@ -90,21 +84,21 @@ begin
echo ' echo " add-multi \"A,B\" Add multiple tags at once"'
echo ' echo " show-metadata Show metadata.json contents"'
echo ' echo " source set Set gallery source"'
- echo ' echo ""'
+ echo ''
echo ' echo "Machine Learning (Face Recognition):"'
echo ' echo " trainer Train face embeddings from ML/faces_cache/"'
echo ' echo " verify [tags] Verify performer face image similarity"'
- echo ' echo ""'
+ echo ''
echo ' echo "Performers & Metadata:"'
echo ' echo " search-performer Search local performer records"'
echo ' echo " tpdb-enrich Sync or mirror metadata from ThePornDB"'
- echo ' echo ""'
+ echo ''
echo ' echo "Utilities:"'
echo ' echo " --help / -h / help Show this help menu"'
echo ' echo " --version / -v / version Show current Goondex version"'
echo ' echo ""'
echo ' echo "────────────────────────────────────────────"'
- echo ' echo "Goondex $goondex_version — Leak Technologies (2025)"'
+ echo ' echo "Goondex $goondex_version (Fish CLI)"'
echo ' echo ""'
echo ' return'
echo ''
@@ -127,7 +121,7 @@ begin
echo ' return'
echo ''
echo ' case -v --version version'
- echo ' echo "Goondex $goondex_version — Leak Technologies"'
+ echo ' echo "Goondex $goondex_version"'
echo ' return'
echo ''
echo ' case "*"'
@@ -142,18 +136,20 @@ chmod +x $goondex_func
echo "[+] Installed goondex.fish function at: $goondex_func"
# ------------------------------------------------------------
-# 4. Add alias gx as persistent function
+# 4. Create and persist gx alias function (bulletproof)
# ------------------------------------------------------------
+echo "[*] Ensuring gx alias function exists..."
if not functions -q gx
+ echo "[+] Creating gx alias function..."
begin
echo 'function gx --wraps=goondex --description "alias gx goondex"'
echo ' goondex $argv'
echo 'end'
end > $gx_func
funcsave gx 2>/dev/null
- echo "[+] Added gx.fish persistent alias function"
+ echo "[+] Saved gx function persistently → $gx_func"
else
- echo "[=] gx function already exists"
+ echo "[=] gx function already exists — skipping"
end
# ------------------------------------------------------------
@@ -167,11 +163,11 @@ else
end
# ------------------------------------------------------------
-# 6. Reload and verify
+# 6. Reload environment & self-test
# ------------------------------------------------------------
echo "[*] Reloading Fish environment..."
-source $goondex_func
source ~/.config/fish/config.fish
+source $goondex_func
echo ""
echo "[✓] Verifying Goondex CLI setup..."
@@ -184,11 +180,16 @@ end
if functions -q gx
echo "✅ Alias function 'gx' active."
else
- echo "❌ gx function missing."
+ echo "❌ gx function missing — restoring definition."
+ function gx --wraps=goondex --description "alias gx goondex"
+ goondex $argv
+ end
+ funcsave gx
end
echo ""
-echo "🔍 Preview:"
-goondex --help | head -n 15
+echo "🔍 Post-install test:"
+gx --version
+gx --help | head -n 10
echo ""
-echo "[✔] Setup complete — Goondex CLI now stable across versions."
+echo "[✔] Setup complete — Goondex CLI verified and persistent."