diff --git a/assets/components/actors/actor.vue b/assets/components/actors/actor.vue index c147fa86..cdde7db2 100644 --- a/assets/components/actors/actor.vue +++ b/assets/components/actors/actor.vue @@ -103,9 +103,7 @@ - -
@@ -296,49 +294,56 @@ export default { background: $profile; color: $highlight-extreme; width: 100%; + height: 18rem; display: flex; flex-direction: row; flex-shrink: 0; + padding: 1rem 0 0 0; .avatar-link { font-size: 0; - padding: 1rem 0 1rem 1rem; + padding: 0 0 1rem 1rem; } .avatar { - height: 15rem; - width: 12rem; + height: 100%; flex-shrink: 0; - margin: 0 1rem 0 0; - object-fit: cover; - object-position: 50% 0; + margin: 0 .5rem 0 0; } } .bio { flex-grow: 1; - min-width: 20rem; + height: 100%; + display: flex; + flex-direction: column; + flex-shrink: 0; + flex-wrap: wrap; box-sizing: border-box; - padding: 1rem; - margin: 0 2rem 0 0; + overflow: hidden; } .bio-header { + width: calc(50% - 2rem); display: flex; justify-content: space-between; align-items: center; - margin: 0 0 1rem 0; + padding: 0 .5rem .5rem 0; + margin: 0 0 0 1rem; } .bio-item { + width: calc(50% - 2rem); display: flex; justify-content: space-between; - padding: 0 0 .25rem 0; - margin: 0 0 .25rem 0; + box-sizing: border-box; + padding: .25rem 0 ; + margin: 0 0 .25rem 1rem; line-height: 1.75; text-align: right; font-size: .9rem; font-weight: 600; + overflow: hidden; &:not(:last-of-type) { border-bottom: solid 1px $highlight-hint; @@ -429,12 +434,12 @@ export default { .scraped { color: $highlight-weak; - margin: 1rem 0 0 0; font-size: .8rem; } .extra { flex-grow: 1; + max-width: 40rem; } .description { @@ -442,7 +447,6 @@ export default { position: relative; display: block; box-sizing: border-box; - padding: 1rem 0 0 0; margin: 0 2rem 0 0; line-height: 1.5; text-overflow: ellipsis; diff --git a/assets/components/tags/photos.vue b/assets/components/tags/photos.vue index e95aab29..852baa3b 100644 --- a/assets/components/tags/photos.vue +++ b/assets/components/tags/photos.vue @@ -70,8 +70,7 @@ export default { .poster, .photo { - height: 10rem; - width: auto; + width: 100%; margin: 0 1rem 0 0; } } diff --git a/assets/components/tags/tag.vue b/assets/components/tags/tag.vue index 6b5548f3..1ee00b0c 100644 --- a/assets/components/tags/tag.vue +++ b/assets/components/tags/tag.vue @@ -24,6 +24,7 @@ - +
-

{{ release.title }}

-
+
    diff --git a/public/css/style.css b/public/css/style.css index 3cd9aaeb..47ff7f0e 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -366,10 +366,16 @@ -o-object-position: 50% 0; object-position: 50% 0; } +.avatar-fallback[data-v-6989dc6f] { + max-height: 75%; + max-width: 80%; + opacity: .1; +} .details[data-v-6989dc6f] { background: rgba(0, 0, 0, 0.5); color: #fff; width: 100%; + height: 1.75rem; display: -webkit-box; display: flex; -webkit-box-align: center; @@ -1026,55 +1032,63 @@ background: #222; color: rgba(255, 255, 255, 0.9); width: 100%; + height: 18rem; display: -webkit-box; display: flex; -webkit-box-orient: horizontal; -webkit-box-direction: normal; flex-direction: row; flex-shrink: 0; + padding: 1rem 0 0 0; } .profile .avatar-link[data-v-ea0483c2] { font-size: 0; - padding: 1rem 0 1rem 1rem; + padding: 0 0 1rem 1rem; } .profile .avatar[data-v-ea0483c2] { - height: 15rem; - width: 12rem; + height: 100%; flex-shrink: 0; - margin: 0 1rem 0 0; - -o-object-fit: cover; - object-fit: cover; - -o-object-position: 50% 0; - object-position: 50% 0; + margin: 0 .5rem 0 0; } .bio[data-v-ea0483c2] { -webkit-box-flex: 1; flex-grow: 1; - min-width: 20rem; + height: 100%; + display: -webkit-box; + display: flex; + -webkit-box-orient: vertical; + -webkit-box-direction: normal; + flex-direction: column; + flex-shrink: 0; + flex-wrap: wrap; box-sizing: border-box; - padding: 1rem; - margin: 0 2rem 0 0; + overflow: hidden; } .bio-header[data-v-ea0483c2] { + width: calc(50% - 2rem); display: -webkit-box; display: flex; -webkit-box-pack: justify; justify-content: space-between; -webkit-box-align: center; align-items: center; - margin: 0 0 1rem 0; + padding: 0 .5rem .5rem 0; + margin: 0 0 0 1rem; } .bio-item[data-v-ea0483c2] { + width: calc(50% - 2rem); display: -webkit-box; display: flex; -webkit-box-pack: justify; justify-content: space-between; - padding: 0 0 .25rem 0; - margin: 0 0 .25rem 0; + box-sizing: border-box; + padding: .25rem 0; + margin: 0 0 .25rem 1rem; line-height: 1.75; text-align: right; font-size: .9rem; font-weight: 600; + overflow: hidden; } .bio-item[data-v-ea0483c2]:not(:last-of-type) { border-bottom: solid 1px rgba(255, 255, 255, 0.075); @@ -1148,19 +1162,18 @@ } .scraped[data-v-ea0483c2] { color: rgba(255, 255, 255, 0.2); - margin: 1rem 0 0 0; font-size: .8rem; } .extra[data-v-ea0483c2] { -webkit-box-flex: 1; flex-grow: 1; + max-width: 40rem; } .description[data-v-ea0483c2] { max-height: 12rem; position: relative; display: block; box-sizing: border-box; - padding: 1rem 0 0 0; margin: 0 2rem 0 0; line-height: 1.5; text-overflow: ellipsis; @@ -1309,8 +1322,7 @@ } .photos.compact .poster[data-v-9d950ba8], .photos.compact .photo[data-v-9d950ba8] { - height: 10rem; - width: auto; + width: 100%; margin: 0 1rem 0 0; } .poster[data-v-9d950ba8], diff --git a/public/img/avatar_female.png b/public/img/avatar_female.png new file mode 100644 index 00000000..df54fe4f Binary files /dev/null and b/public/img/avatar_female.png differ diff --git a/public/img/avatar_female2.png b/public/img/avatar_female2.png new file mode 100644 index 00000000..b7b15710 Binary files /dev/null and b/public/img/avatar_female2.png differ diff --git a/public/img/tags/double-anal/2.jpeg b/public/img/tags/double-anal/2.jpeg new file mode 100644 index 00000000..175ecd3b Binary files /dev/null and b/public/img/tags/double-anal/2.jpeg differ diff --git a/public/img/tags/double-anal/2_thumb.jpeg b/public/img/tags/double-anal/2_thumb.jpeg new file mode 100644 index 00000000..f6327959 Binary files /dev/null and b/public/img/tags/double-anal/2_thumb.jpeg differ diff --git a/public/img/tags/double-anal/3.jpeg b/public/img/tags/double-anal/3.jpeg new file mode 100644 index 00000000..b8d01e1e Binary files /dev/null and b/public/img/tags/double-anal/3.jpeg differ diff --git a/public/img/tags/double-anal/3_thumb.jpeg b/public/img/tags/double-anal/3_thumb.jpeg new file mode 100644 index 00000000..97849b24 Binary files /dev/null and b/public/img/tags/double-anal/3_thumb.jpeg differ diff --git a/public/img/tags/double-anal/4.jpeg b/public/img/tags/double-anal/4.jpeg new file mode 100644 index 00000000..c767f807 Binary files /dev/null and b/public/img/tags/double-anal/4.jpeg differ diff --git a/public/img/tags/double-anal/4_thumb.jpeg b/public/img/tags/double-anal/4_thumb.jpeg new file mode 100644 index 00000000..b9837032 Binary files /dev/null and b/public/img/tags/double-anal/4_thumb.jpeg differ diff --git a/public/img/tags/oral-creampie/1.jpeg b/public/img/tags/oral-creampie/1.jpeg new file mode 100644 index 00000000..ba1e8b80 Binary files /dev/null and b/public/img/tags/oral-creampie/1.jpeg differ diff --git a/public/img/tags/oral-creampie/1_thumb.jpeg b/public/img/tags/oral-creampie/1_thumb.jpeg new file mode 100644 index 00000000..f21e3292 Binary files /dev/null and b/public/img/tags/oral-creampie/1_thumb.jpeg differ diff --git a/public/img/tags/schoolgirl/1.jpeg b/public/img/tags/schoolgirl/1.jpeg new file mode 100644 index 00000000..f893e343 Binary files /dev/null and b/public/img/tags/schoolgirl/1.jpeg differ diff --git a/public/img/tags/schoolgirl/1_thumb.jpeg b/public/img/tags/schoolgirl/1_thumb.jpeg new file mode 100644 index 00000000..d1d130ff Binary files /dev/null and b/public/img/tags/schoolgirl/1_thumb.jpeg differ diff --git a/seeds/04_media.js b/seeds/04_media.js index fb33775a..0a866468 100644 --- a/seeds/04_media.js +++ b/seeds/04_media.js @@ -4,11 +4,11 @@ const tagPosters = Object.entries({ 'anal-creampie': ['poster'], 'ass-to-mouth': ['poster', 'Alysa Gap and Logan in "Anal Buffet 4" for Evil Angel'], 'da-tp': [0, 'Natasha Teen in LegalPorno SZ2164'], - 'double-anal': ['poster', 'Haley Reed in "Young Hot Ass" for Evil Angel'], + 'double-anal': [2, 'Lana Rhoades in "Gangbang Me 3" for HardX'], 'double-penetration': ['poster', 'Mia Malkova in "DP!" for HardX'], 'double-vaginal': ['poster'], 'dv-tp': ['poster', 'Juelz Ventura in "Gangbanged 5" for Elegant Angel'], - 'oral-creampie': ['poster'], + 'oral-creampie': [1, 'Keisha Grey in Brazzers House'], 'triple-anal': ['poster', 'Kristy Black in SZ1986 for LegalPorno'], airtight: [1, 'Jynx Maze in "Pump My Ass Full of Cum 3" for Jules Jordan'], anal: ['poster', 'Jynx Maze in "Anal Buffet 6" for Evil Angel'], @@ -26,6 +26,7 @@ const tagPosters = Object.entries({ mff: ['poster'], mfm: ['poster'], orgy: ['poster'], + schoolgirl: [1, 'Eliza Ibarra for Brazzers'], swallowing: ['poster'], tattoo: ['poster', 'Kali Roses in "Goes All In For Anal" for Hussie Pass'], trainbang: ['poster', 'Kali Roses in "Passing Me Around" for Blacked'], @@ -47,6 +48,7 @@ const tagPhotos = [ ['da-tp', 2, 'Angel Smalls in GIO408 for LegalPorno'], ['da-tp', 3, 'Evelina Darling in GIO294'], ['da-tp', 4, 'Ninel Mojado aka Mira Cuckold in GIO063 for LegalPorno'], + ['double-anal', 'poster', 'Haley Reed in "Young Hot Ass" for Evil Angel'], ['double-anal', 0, 'Nicole Black doing double anal during a gangbang in GIO971 for LegalPorno'], ['double-anal', 1, 'Ria Sunn in SZ1801 for LegalPorno'], ['double-penetration', 0], @@ -60,6 +62,7 @@ const tagPhotos = [ ['trainbang', 0, 'Nicole Black in GIO971 for LegalPorno'], ['triple-anal', 1, 'Natasha Teen in SZ2098 for LegalPorno'], ['triple-anal', 2, 'Kira Thorn in GIO1018 for LegalPorno'], + ['oral-creampie', 'poster', 'Khloe Kapri'], ] .map(([slug, fileIndex, comment], index) => ({ tagSlug: slug, diff --git a/src/actors.js b/src/actors.js index 65918f01..9594df53 100644 --- a/src/actors.js +++ b/src/actors.js @@ -287,6 +287,7 @@ async function mergeProfiles(profiles, actor) { birthdate: Number.isNaN(Number(prevProfile.birthdate)) ? profile.birthdate : prevProfile.birthdate, birthPlace: prevProfile.birthPlace || profile.birthPlace, residencePlace: prevProfile.residencePlace || profile.residencePlace, + nationality: prevProfile.nationality || profile.nationality, // used to derive country when not available ethnicity: prevProfile.ethnicity || profile.ethnicity, bust: prevProfile.bust || profile.bust, waist: prevProfile.waist || profile.waist, @@ -316,6 +317,17 @@ async function mergeProfiles(profiles, actor) { mergedProfile.birthPlace = birthPlace; mergedProfile.residencePlace = residencePlace; + if (!mergedProfile.birthPlace && mergedProfile.nationality) { + const country = await knex('countries') + .where('nationality', 'ilike', `%${mergedProfile.nationality}%`) + .orderBy('priority', 'desc') + .first(); + + mergedProfile.birthPlace = { + country: country.alpha2, + }; + } + return mergedProfile; } diff --git a/src/media.js b/src/media.js index 97e8ca67..b2c1f2eb 100644 --- a/src/media.js +++ b/src/media.js @@ -182,7 +182,8 @@ async function storePhotos(photos, { concurrency: 10, }).filter(photo => photo); - const [hashDuplicates, hashOriginals] = await findDuplicates(metaFiles, 'hash', 'hash', label); + const metaFilesByHash = metaFiles.reduce((acc, photo) => ({ ...acc, [photo.hash]: photo }), {}); // pre-filter hash duplicates within set; may occur through fallbacks + const [hashDuplicates, hashOriginals] = await findDuplicates(Object.values(metaFilesByHash), 'hash', 'hash', label); const savedPhotos = await savePhotos(hashOriginals, { domain, diff --git a/src/scrapers/ddfnetwork.js b/src/scrapers/ddfnetwork.js index 2981fd84..a12017f3 100644 --- a/src/scrapers/ddfnetwork.js +++ b/src/scrapers/ddfnetwork.js @@ -119,17 +119,12 @@ async function scrapeProfile(html, _url, actorName) { const descriptionEl = document.querySelector('.description-box'); const avatarEl = document.querySelector('.pornstar-details .card-img-top'); - const country = await knex('countries') - .where('nationality', 'ilike', `%${bio.Nationality}%`) - .orderBy('priority', 'desc') - .first(); - const profile = { name: actorName, }; profile.birthdate = moment.utc(bio.Birthday, 'MMMM DD, YYYY').toDate(); - if (country) profile.birthPlace = country.name; + if (bio.Nationality) profile.nationality = bio.Nationality; if (bio['Bra size']) [profile.bust] = bio['Bra size'].match(/\d+\w+/); if (bio.Waist) profile.waist = Number(bio.Waist.match(/\d+/)[0]); diff --git a/src/scrapers/gamma.js b/src/scrapers/gamma.js index 76f14e33..7afe3fad 100644 --- a/src/scrapers/gamma.js +++ b/src/scrapers/gamma.js @@ -78,6 +78,11 @@ function scrapeProfile(html, url, actorName, siteSlug) { const avatarEl = document.querySelector('img.actorPicture'); const descriptionEl = document.querySelector('.actorBio p:not(.bioTitle)'); + const hairEl = document.querySelector('.actorProfile .attribute_hair_color'); + const heightEl = document.querySelector('.actorProfile .attribute_height'); + const weightEl = document.querySelector('.actorProfile .attribute_weight'); + const aliasEl = document.querySelector('.actorProfile .attribute_alternate_names'); + const nationalityEl = document.querySelector('.actorProfile .attribute_home'); const profile = { name: actorName, @@ -96,6 +101,11 @@ function scrapeProfile(html, url, actorName, siteSlug) { } if (descriptionEl) profile.description = descriptionEl.textContent.trim(); + if (hairEl) profile.hair = hairEl.textContent.split(':')[1].trim(); + if (heightEl) profile.height = Number(heightEl.textContent.match(/\d+/)[0]); + if (weightEl) profile.weight = Number(weightEl.textContent.match(/\d+/)[0]); + if (aliasEl) profile.aliases = aliasEl.textContent.split(':')[1].trim().split(', '); + if (nationalityEl) profile.nationality = nationalityEl.textContent.split(':')[1].trim(); profile.releases = Array.from(document.querySelectorAll('.sceneList .scene a.imgLink'), el => `https://${siteSlug}.com${el.href}`);