Storing actor avatars. Using 1 second interval queue for location resolve as per OSM code of conduct.

This commit is contained in:
ThePendulum 2020-05-16 04:36:45 +02:00
parent 21d4dd6bfa
commit 05ee57378a
28 changed files with 899 additions and 751 deletions

View File

@ -1,47 +1,47 @@
<template>
<div
class="photos"
:class="{ wide: actor.photos.length > 2 }"
>
<a
v-if="actor.avatar"
:href="`/media/${actor.avatar.path}`"
target="_blank"
rel="noopener noreferrer"
class="avatar-link photo-link"
>
<img
:src="`/media/${actor.avatar.thumbnail}`"
:title="actor.avatar.copyright && `© ${actor.avatar.copyright}`"
class="avatar photo"
>
</a>
<div
class="photos"
:class="{ wide: actor.photos.length > 2 }"
>
<a
v-if="actor.avatar"
:href="`/media/${actor.avatar.path}`"
target="_blank"
rel="noopener noreferrer"
class="avatar-link photo-link"
>
<img
:src="`/media/${actor.avatar.thumbnail}`"
:title="actor.avatar.copyright && `© ${actor.avatar.copyright}`"
class="avatar photo"
>
</a>
<a
v-for="photo in actor.photos"
:key="`photo-${photo.id}`"
:href="`/media/${photo.path}`"
target="_blank"
rel="noopener noreferrer"
class="photo-link"
>
<img
:src="`/media/${photo.thumbnail}`"
:title="photo.copyright && `© ${photo.copyright}`"
class="photo"
>
</a>
</div>
<a
v-for="photo in actor.photos"
:key="`photo-${photo.id}`"
:href="`/media/${photo.path}`"
target="_blank"
rel="noopener noreferrer"
class="photo-link"
>
<img
:src="`/media/${photo.thumbnail}`"
:title="photo.copyright && `© ${photo.copyright}`"
class="photo"
>
</a>
</div>
</template>
<script>
export default {
props: {
actor: {
type: Object,
default: null,
},
},
props: {
actor: {
type: Object,
default: null,
},
},
};
</script>

View File

@ -36,18 +36,15 @@ function curateActor(actor) {
updatedAt: new Date(actor.updatedAt),
};
if (actor.avatar) {
curatedActor.avatar = actor.avatar.media;
if (actor.profiles && actor.profiles.length > 0) {
curatedActor.avatar = actor.profiles.slice(0, 1)[0].avatar;
curatedActor.photos = actor.profiles.slice(1).map(profile => profile.avatar);
}
if (actor.releases) {
curatedActor.releases = actor.releases.map(release => curateRelease(release.release));
}
if (actor.photos) {
curatedActor.photos = actor.photos.map(photo => photo.media);
}
return curatedActor;
}
@ -99,23 +96,16 @@ function initActorActions(store, _router) {
name
slug
}
actorsProfiles {
actorsAvatarByProfileId {
media {
path
thumbnail
copyright
}
}
}
photos: actorsPhotos {
media {
id
thumbnail
path
index
copyright
}
profiles: actorsProfiles {
description
avatar: avatarMedia {
id
path
thumbnail
lazy
comment
copyright
}
}
birthCity
birthState
@ -239,6 +229,7 @@ function initActorActions(store, _router) {
actorsProfiles {
actorsAvatarByProfileId {
media {
id
path
thumbnail
copyright

View File

@ -59,13 +59,16 @@ exports.up = knex => Promise.resolve()
.inTable('media')
.unique();
}))
.then(() => knex.raw(`
CREATE FUNCTION get_random_sfw_media_id() RETURNS varchar AS $$
SELECT media_id FROM media_sfw
ORDER BY random()
LIMIT 1;
$$ LANGUAGE sql STABLE;
`))
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
CREATE FUNCTION get_random_sfw_media_id() RETURNS varchar AS $$
SELECT media_id FROM media_sfw
ORDER BY random()
LIMIT 1;
$$ LANGUAGE sql STABLE;
`);
})
.then(() => knex.schema.alterTable('media', (table) => {
table.string('sfw_media_id', 21)
.references('id')
@ -140,6 +143,7 @@ exports.up = knex => Promise.resolve()
table.increments('id', 12);
table.string('name');
table.string('alias');
table.string('url');
table.text('description');
table.json('parameters');
@ -322,6 +326,7 @@ exports.up = knex => Promise.resolve()
table.increments('id', 12);
table.integer('actor_id', 12)
.notNullable()
.references('id')
.inTable('actors');
@ -371,6 +376,10 @@ exports.up = knex => Promise.resolve()
table.string('piercings');
table.string('tattoos');
table.string('avatar_media_id', 21)
.references('id')
.inTable('media');
table.datetime('scraped_at');
table.boolean('scrape_success');
@ -386,122 +395,125 @@ exports.up = knex => Promise.resolve()
table.string('name');
}))
.then(() => knex('body').insert([
// head
{ slug: 'head', name: 'head' },
{ slug: 'face', name: 'face' },
{ slug: 'scalp', name: 'scalp' },
{ slug: 'forehead', name: 'forehead' },
{ slug: 'temple', name: 'temple' },
{ slug: 'cheek', name: 'cheek' },
{ slug: 'jaw', name: 'jaw' },
{ slug: 'chin', name: 'chin' },
{ slug: 'neck', name: 'neck' },
{ slug: 'throat', name: 'throat' },
// eyes
{ slug: 'eyelid', name: 'eyelid' },
{ slug: 'eyeball', name: 'eyeball' },
{ slug: 'eyebrow', name: 'eyebrow' },
// mouth
{ slug: 'tongue', name: 'tongue' },
{ slug: 'lip', name: 'lip' },
{ slug: 'upper-lip', name: 'upper lip' },
{ slug: 'lower-lip', name: 'lower lip' },
{ slug: 'inner-lip', name: 'inner lip' },
{ slug: 'inner-lower-lip', name: 'inner lower lip' },
{ slug: 'inner-upper-lip', name: 'inner upper lip' },
{ slug: 'philtrum', name: 'philtrum' },
{ slug: 'above-lip', name: 'above lip' },
{ slug: 'below-lip', name: 'below lip' },
// nose
{ slug: 'nose', name: 'nose' },
{ slug: 'third-eye', name: 'third eye' },
{ slug: 'bridge', name: 'bridge' },
{ slug: 'nostril', name: 'nostril' },
{ slug: 'septum', name: 'septum' },
{ slug: 'septril', name: 'septril' },
// ear
{ slug: 'ear', name: 'ear' },
{ slug: 'earlobe', name: 'earlobe' },
{ slug: 'helix', name: 'helix' },
{ slug: 'tragus', name: 'tragus' },
{ slug: 'conch', name: 'conch' },
{ slug: 'rook', name: 'rook' },
{ slug: 'behind-ear', name: 'behind ear' },
// arms
{ slug: 'arm', name: 'arm' },
{ slug: 'upper-arm', name: 'upper arm' },
{ slug: 'forearm', name: 'forearm' },
{ slug: 'elbow', name: 'elbow' },
{ slug: 'inner-elbow', name: 'inner elbow' },
{ slug: 'outer-elbow', name: 'outer elbow' },
// hands
{ slug: 'hand', name: 'hand' },
{ slug: 'fingers', name: 'fingers' },
{ slug: 'knuckles', name: 'knuckles' },
{ slug: 'thumb', name: 'thumb' },
{ slug: 'index-finger', name: 'index finger' },
{ slug: 'middle-finger', name: 'middle finger' },
{ slug: 'ring-finger', name: 'ring finger' },
{ slug: 'pinky', name: 'pinky' },
{ slug: 'back-of-hand', name: 'back of hand' },
{ slug: 'inner-wrist', name: 'inner wrist' },
{ slug: 'outer-wrist', name: 'outer wrist' },
// torso
{ slug: 'shoulder', name: 'shoulder' },
{ slug: 'collarbone', name: 'collarbone' },
{ slug: 'chest', name: 'chest' },
{ slug: 'rib-cage', name: 'rib cage' },
{ slug: 'breastbone', name: 'breastbone' },
{ slug: 'underboob', name: 'underboob' },
{ slug: 'sideboob', name: 'sideboob' },
{ slug: 'boob', name: 'boob' },
{ slug: 'nipple', name: 'nipple' },
{ slug: 'abdomen', name: 'abdomen' },
{ slug: 'navel', name: 'navel' },
{ slug: 'pelvis', name: 'pelvis' },
// back
{ slug: 'back', name: 'back' },
{ slug: 'upper-back', name: 'upper back' },
{ slug: 'middle-back', name: 'lower back' },
{ slug: 'lower-back', name: 'lower back' },
{ slug: 'spine', name: 'spine' },
// bottom
{ slug: 'butt', name: 'butt' },
{ slug: 'hip', name: 'hip' },
{ slug: 'anus', name: 'anus' },
// genitals
{ slug: 'pubic-mound', name: 'pubic mound' },
{ slug: 'vagina', name: 'vagina' },
{ slug: 'outer-labia', name: 'outer labia' },
{ slug: 'inner-labia', name: 'inner labia' },
{ slug: 'clitoris', name: 'clitoris' },
{ slug: 'penis', name: 'penis' },
{ slug: 'glans', name: 'glans' },
{ slug: 'foreskin', name: 'foreskin' },
{ slug: 'shaft', name: 'shaft' },
{ slug: 'scrotum', name: 'scrotum' },
// legs
{ slug: 'leg', name: 'leg' },
{ slug: 'groin', name: 'groin' },
{ slug: 'upper-leg', name: 'upper leg' },
{ slug: 'thigh', name: 'thigh' },
{ slug: 'lower-leg', name: 'lower leg' },
{ slug: 'shin', name: 'shin' },
{ slug: 'calf', name: 'calf' },
{ slug: 'knee', name: 'knee' },
{ slug: 'inner-knee', name: 'inner knee' },
// feet
{ slug: 'inner-ankle', name: 'inner ankle' },
{ slug: 'outer-ankle', name: 'outer ankle' },
{ slug: 'foot', name: 'foot' },
{ slug: 'toes', name: 'toes' },
{ slug: 'big-toe', name: 'big toe' },
{ slug: 'index-toe', name: 'index toe' },
{ slug: 'middle-toe', name: 'middle toe' },
{ slug: 'fourth-toe', name: 'fourth toe' },
{ slug: 'little-toe', name: 'little toe' },
]))
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex('body').insert([
// head
{ slug: 'head', name: 'head' },
{ slug: 'face', name: 'face' },
{ slug: 'scalp', name: 'scalp' },
{ slug: 'forehead', name: 'forehead' },
{ slug: 'temple', name: 'temple' },
{ slug: 'cheek', name: 'cheek' },
{ slug: 'jaw', name: 'jaw' },
{ slug: 'chin', name: 'chin' },
{ slug: 'neck', name: 'neck' },
{ slug: 'throat', name: 'throat' },
// eyes
{ slug: 'eyelid', name: 'eyelid' },
{ slug: 'eyeball', name: 'eyeball' },
{ slug: 'eyebrow', name: 'eyebrow' },
// mouth
{ slug: 'tongue', name: 'tongue' },
{ slug: 'lip', name: 'lip' },
{ slug: 'upper-lip', name: 'upper lip' },
{ slug: 'lower-lip', name: 'lower lip' },
{ slug: 'inner-lip', name: 'inner lip' },
{ slug: 'inner-lower-lip', name: 'inner lower lip' },
{ slug: 'inner-upper-lip', name: 'inner upper lip' },
{ slug: 'philtrum', name: 'philtrum' },
{ slug: 'above-lip', name: 'above lip' },
{ slug: 'below-lip', name: 'below lip' },
// nose
{ slug: 'nose', name: 'nose' },
{ slug: 'third-eye', name: 'third eye' },
{ slug: 'bridge', name: 'bridge' },
{ slug: 'nostril', name: 'nostril' },
{ slug: 'septum', name: 'septum' },
{ slug: 'septril', name: 'septril' },
// ear
{ slug: 'ear', name: 'ear' },
{ slug: 'earlobe', name: 'earlobe' },
{ slug: 'helix', name: 'helix' },
{ slug: 'tragus', name: 'tragus' },
{ slug: 'conch', name: 'conch' },
{ slug: 'rook', name: 'rook' },
{ slug: 'behind-ear', name: 'behind ear' },
// arms
{ slug: 'arm', name: 'arm' },
{ slug: 'upper-arm', name: 'upper arm' },
{ slug: 'forearm', name: 'forearm' },
{ slug: 'elbow', name: 'elbow' },
{ slug: 'inner-elbow', name: 'inner elbow' },
{ slug: 'outer-elbow', name: 'outer elbow' },
// hands
{ slug: 'hand', name: 'hand' },
{ slug: 'fingers', name: 'fingers' },
{ slug: 'knuckles', name: 'knuckles' },
{ slug: 'thumb', name: 'thumb' },
{ slug: 'index-finger', name: 'index finger' },
{ slug: 'middle-finger', name: 'middle finger' },
{ slug: 'ring-finger', name: 'ring finger' },
{ slug: 'pinky', name: 'pinky' },
{ slug: 'back-of-hand', name: 'back of hand' },
{ slug: 'inner-wrist', name: 'inner wrist' },
{ slug: 'outer-wrist', name: 'outer wrist' },
// torso
{ slug: 'shoulder', name: 'shoulder' },
{ slug: 'collarbone', name: 'collarbone' },
{ slug: 'chest', name: 'chest' },
{ slug: 'rib-cage', name: 'rib cage' },
{ slug: 'breastbone', name: 'breastbone' },
{ slug: 'underboob', name: 'underboob' },
{ slug: 'sideboob', name: 'sideboob' },
{ slug: 'boob', name: 'boob' },
{ slug: 'nipple', name: 'nipple' },
{ slug: 'abdomen', name: 'abdomen' },
{ slug: 'navel', name: 'navel' },
{ slug: 'pelvis', name: 'pelvis' },
// back
{ slug: 'back', name: 'back' },
{ slug: 'upper-back', name: 'upper back' },
{ slug: 'middle-back', name: 'lower back' },
{ slug: 'lower-back', name: 'lower back' },
{ slug: 'spine', name: 'spine' },
// bottom
{ slug: 'butt', name: 'butt' },
{ slug: 'hip', name: 'hip' },
{ slug: 'anus', name: 'anus' },
// genitals
{ slug: 'pubic-mound', name: 'pubic mound' },
{ slug: 'vagina', name: 'vagina' },
{ slug: 'outer-labia', name: 'outer labia' },
{ slug: 'inner-labia', name: 'inner labia' },
{ slug: 'clitoris', name: 'clitoris' },
{ slug: 'penis', name: 'penis' },
{ slug: 'glans', name: 'glans' },
{ slug: 'foreskin', name: 'foreskin' },
{ slug: 'shaft', name: 'shaft' },
{ slug: 'scrotum', name: 'scrotum' },
// legs
{ slug: 'leg', name: 'leg' },
{ slug: 'groin', name: 'groin' },
{ slug: 'upper-leg', name: 'upper leg' },
{ slug: 'thigh', name: 'thigh' },
{ slug: 'lower-leg', name: 'lower leg' },
{ slug: 'shin', name: 'shin' },
{ slug: 'calf', name: 'calf' },
{ slug: 'knee', name: 'knee' },
{ slug: 'inner-knee', name: 'inner knee' },
// feet
{ slug: 'inner-ankle', name: 'inner ankle' },
{ slug: 'outer-ankle', name: 'outer ankle' },
{ slug: 'foot', name: 'foot' },
{ slug: 'toes', name: 'toes' },
{ slug: 'big-toe', name: 'big toe' },
{ slug: 'index-toe', name: 'index toe' },
{ slug: 'middle-toe', name: 'middle toe' },
{ slug: 'fourth-toe', name: 'fourth toe' },
{ slug: 'little-toe', name: 'little toe' },
]);
})
.then(() => knex.schema.createTable('actors_tattoos', (table) => {
table.increments('id');
@ -769,114 +781,120 @@ exports.up = knex => Promise.resolve()
.references('id')
.inTable('releases');
}))
.then(() => knex.raw(`
ALTER TABLE releases
ADD CONSTRAINT ensure_site_or_network CHECK (site_id IS NOT NULL OR network_id IS NOT NULL);
.then(() => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
ALTER TABLE releases
ADD CONSTRAINT ensure_site_or_network CHECK (site_id IS NOT NULL OR network_id IS NOT NULL);
ALTER TABLE releases_search
ADD COLUMN document tsvector;
ALTER TABLE releases_search
ADD COLUMN document tsvector;
CREATE TEXT SEARCH DICTIONARY traxxx_dict (
TEMPLATE = pg_catalog.simple,
stopwords = traxxx
);
CREATE TEXT SEARCH DICTIONARY traxxx_dict (
TEMPLATE = pg_catalog.simple,
stopwords = traxxx
);
CREATE TEXT SEARCH CONFIGURATION traxxx (
COPY = english
);
CREATE TEXT SEARCH CONFIGURATION traxxx (
COPY = english
);
ALTER TEXT SEARCH CONFIGURATION traxxx
ALTER MAPPING FOR word, numword, hword, numhword, hword_part, hword_numpart, asciiword, asciihword, hword_asciipart WITH traxxx_dict, simple, english_stem;
ALTER TEXT SEARCH CONFIGURATION traxxx
ALTER MAPPING FOR word, numword, hword, numhword, hword_part, hword_numpart, asciiword, asciihword, hword_asciipart WITH traxxx_dict, simple, english_stem;
CREATE UNIQUE INDEX releases_search_unique ON releases_search (release_id);
CREATE INDEX releases_search_index ON releases_search USING GIN (document);
CREATE UNIQUE INDEX releases_search_unique ON releases_search (release_id);
CREATE INDEX releases_search_index ON releases_search USING GIN (document);
CREATE FUNCTION search_releases(query text) RETURNS SETOF releases AS $$
SELECT * FROM releases WHERE releases.id IN (
SELECT release_id FROM releases_search AS search
WHERE search.document @@ plainto_tsquery('traxxx', regexp_replace(query, '\\.|-|(XXX\\.[\\d+|hd|sd].*$)', ' ', 'ig'))
ORDER BY ts_rank(search.document, plainto_tsquery('traxxx', regexp_replace(query, '\\.|-|(XXX\\.[\\d+|hd|sd].*$)', ' ', 'ig'))) DESC
);
$$ LANGUAGE SQL STABLE;
CREATE FUNCTION search_releases(query text) RETURNS SETOF releases AS $$
SELECT * FROM releases WHERE releases.id IN (
SELECT release_id FROM releases_search AS search
WHERE search.document @@ plainto_tsquery('traxxx', regexp_replace(query, '\\.|-|(XXX\\.[\\d+|hd|sd].*$)', ' ', 'ig'))
ORDER BY ts_rank(search.document, plainto_tsquery('traxxx', regexp_replace(query, '\\.|-|(XXX\\.[\\d+|hd|sd].*$)', ' ', 'ig'))) DESC
);
$$ LANGUAGE SQL STABLE;
CREATE FUNCTION search_sites(search text) RETURNS SETOF sites AS $$
SELECT * FROM sites
WHERE
name ILIKE ('%' || search || '%') OR
slug ILIKE ('%' || search || '%') OR
url ILIKE ('%' || search || '%')
$$ LANGUAGE SQL STABLE;
CREATE FUNCTION search_sites(search text) RETURNS SETOF sites AS $$
SELECT * FROM sites
WHERE
name ILIKE ('%' || search || '%') OR
slug ILIKE ('%' || search || '%') OR
url ILIKE ('%' || search || '%')
$$ LANGUAGE SQL STABLE;
CREATE FUNCTION releases_is_new(release releases) RETURNS boolean AS $$
SELECT NOT EXISTS(SELECT true FROM batches WHERE batches.id = release.created_batch_id + 1 LIMIT 1);
$$ LANGUAGE sql STABLE;
CREATE FUNCTION releases_is_new(release releases) RETURNS boolean AS $$
SELECT NOT EXISTS(SELECT true FROM batches WHERE batches.id = release.created_batch_id + 1 LIMIT 1);
$$ LANGUAGE sql STABLE;
CREATE VIEW movie_actors AS
SELECT releases_movies.movie_id, releases_actors.actor_id FROM releases_movies
LEFT JOIN releases ON releases.id = releases_movies.scene_id
LEFT JOIN releases_actors ON releases_actors.release_id = releases.id
GROUP BY movie_id, actor_id;
CREATE VIEW movie_actors AS
SELECT releases_movies.movie_id, releases_actors.actor_id FROM releases_movies
LEFT JOIN releases ON releases.id = releases_movies.scene_id
LEFT JOIN releases_actors ON releases_actors.release_id = releases.id
GROUP BY movie_id, actor_id;
CREATE VIEW movie_tags AS
SELECT releases_movies.movie_id, releases_tags.tag_id FROM releases_movies
LEFT JOIN releases ON releases.id = releases_movies.scene_id
LEFT JOIN releases_tags ON releases_tags.release_id = releases.id
GROUP BY movie_id, tag_id;
CREATE VIEW movie_tags AS
SELECT releases_movies.movie_id, releases_tags.tag_id FROM releases_movies
LEFT JOIN releases ON releases.id = releases_movies.scene_id
LEFT JOIN releases_tags ON releases_tags.release_id = releases.id
GROUP BY movie_id, tag_id;
COMMENT ON VIEW movie_actors IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (actor_id) references actors (id)';
COMMENT ON VIEW movie_tags IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (tag_id) references tags (id)';
COMMENT ON VIEW movie_actors IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (actor_id) references actors (id)';
COMMENT ON VIEW movie_tags IS E'@foreignKey (movie_id) references releases (id)\n@foreignKey (tag_id) references tags (id)';
COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many';
COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many';
`));
COMMENT ON COLUMN actors.height IS E'@omit read,update,create,delete,all,many';
COMMENT ON COLUMN actors.weight IS E'@omit read,update,create,delete,all,many';
`);
});
exports.down = knex => knex.raw(`
DROP VIEW IF EXISTS movie_actors;
DROP VIEW IF EXISTS movie_tags;
exports.down = (knex) => { // eslint-disable-line arrow-body-style
// allow vim fold
return knex.raw(`
DROP VIEW IF EXISTS movie_actors;
DROP VIEW IF EXISTS movie_tags;
DROP TABLE IF EXISTS releases_actors CASCADE;
DROP TABLE IF EXISTS releases_movies CASCADE;
DROP TABLE IF EXISTS releases_directors CASCADE;
DROP TABLE IF EXISTS releases_posters CASCADE;
DROP TABLE IF EXISTS releases_photos CASCADE;
DROP TABLE IF EXISTS releases_covers CASCADE;
DROP TABLE IF EXISTS releases_trailers CASCADE;
DROP TABLE IF EXISTS releases_teasers CASCADE;
DROP TABLE IF EXISTS releases_tags CASCADE;
DROP TABLE IF EXISTS releases_search CASCADE;
DROP TABLE IF EXISTS releases_actors CASCADE;
DROP TABLE IF EXISTS releases_movies CASCADE;
DROP TABLE IF EXISTS releases_directors CASCADE;
DROP TABLE IF EXISTS releases_posters CASCADE;
DROP TABLE IF EXISTS releases_photos CASCADE;
DROP TABLE IF EXISTS releases_covers CASCADE;
DROP TABLE IF EXISTS releases_trailers CASCADE;
DROP TABLE IF EXISTS releases_teasers CASCADE;
DROP TABLE IF EXISTS releases_tags CASCADE;
DROP TABLE IF EXISTS releases_search CASCADE;
DROP TABLE IF EXISTS batches CASCADE;
DROP TABLE IF EXISTS batches CASCADE;
DROP TABLE IF EXISTS actors_avatars CASCADE;
DROP TABLE IF EXISTS actors_photos CASCADE;
DROP TABLE IF EXISTS actors_social CASCADE;
DROP TABLE IF EXISTS actors_profiles CASCADE;
DROP TABLE IF EXISTS actors_tattoos CASCADE;
DROP TABLE IF EXISTS actors_piercings CASCADE;
DROP TABLE IF EXISTS body CASCADE;
DROP TABLE IF EXISTS actors_avatars CASCADE;
DROP TABLE IF EXISTS actors_photos CASCADE;
DROP TABLE IF EXISTS actors_social CASCADE;
DROP TABLE IF EXISTS actors_profiles CASCADE;
DROP TABLE IF EXISTS actors_tattoos CASCADE;
DROP TABLE IF EXISTS actors_piercings CASCADE;
DROP TABLE IF EXISTS body CASCADE;
DROP TABLE IF EXISTS sites_tags CASCADE;
DROP TABLE IF EXISTS sites_social CASCADE;
DROP TABLE IF EXISTS networks_social CASCADE;
DROP TABLE IF EXISTS tags_posters CASCADE;
DROP TABLE IF EXISTS tags_photos CASCADE;
DROP TABLE IF EXISTS releases CASCADE;
DROP TABLE IF EXISTS actors CASCADE;
DROP TABLE IF EXISTS directors CASCADE;
DROP TABLE IF EXISTS tags CASCADE;
DROP TABLE IF EXISTS tags_groups CASCADE;
DROP TABLE IF EXISTS social CASCADE;
DROP TABLE IF EXISTS sites CASCADE;
DROP TABLE IF EXISTS studios CASCADE;
DROP TABLE IF EXISTS media_sfw CASCADE;
DROP TABLE IF EXISTS media CASCADE;
DROP TABLE IF EXISTS countries CASCADE;
DROP TABLE IF EXISTS networks CASCADE;
DROP TABLE IF EXISTS sites_tags CASCADE;
DROP TABLE IF EXISTS sites_social CASCADE;
DROP TABLE IF EXISTS networks_social CASCADE;
DROP TABLE IF EXISTS tags_posters CASCADE;
DROP TABLE IF EXISTS tags_photos CASCADE;
DROP TABLE IF EXISTS releases CASCADE;
DROP TABLE IF EXISTS actors CASCADE;
DROP TABLE IF EXISTS directors CASCADE;
DROP TABLE IF EXISTS tags CASCADE;
DROP TABLE IF EXISTS tags_groups CASCADE;
DROP TABLE IF EXISTS social CASCADE;
DROP TABLE IF EXISTS sites CASCADE;
DROP TABLE IF EXISTS studios CASCADE;
DROP TABLE IF EXISTS media_sfw CASCADE;
DROP TABLE IF EXISTS media CASCADE;
DROP TABLE IF EXISTS countries CASCADE;
DROP TABLE IF EXISTS networks CASCADE;
DROP FUNCTION IF EXISTS releases_by_tag_slugs;
DROP FUNCTION IF EXISTS search_sites;
DROP FUNCTION IF EXISTS get_random_sfw_media_id;
DROP FUNCTION IF EXISTS releases_by_tag_slugs;
DROP FUNCTION IF EXISTS search_sites;
DROP FUNCTION IF EXISTS get_random_sfw_media_id;
DROP TEXT SEARCH CONFIGURATION IF EXISTS traxxx;
DROP TEXT SEARCH DICTIONARY IF EXISTS traxxx_dict;
`);
DROP TEXT SEARCH CONFIGURATION IF EXISTS traxxx;
DROP TEXT SEARCH DICTIONARY IF EXISTS traxxx_dict;
`);
};

Binary file not shown.

After

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@ -0,0 +1,84 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 18.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 547 112" enable-background="new 0 0 547 112" xml:space="preserve">
<radialGradient id="SVGID_1_" cx="171.1188" cy="60.5308" r="34.3229" gradientUnits="userSpaceOnUse">
<stop offset="0.1989" style="stop-color:#EE2724"/>
<stop offset="0.3065" style="stop-color:#EE2424"/>
<stop offset="1" style="stop-color:#CD2027"/>
</radialGradient>
<polygon fill="url(#SVGID_1_)" points="182.1,18.6 171.2,39 158.3,14.3 135.6,14.3 159.9,60.5 135.6,106.7 158.3,106.7 171.2,82.1
184.2,106.7 191.1,106.7 199,91.7 182.6,60.5 193.5,39.6 "/>
<radialGradient id="SVGID_2_" cx="257.2801" cy="60.5308" r="31.5337" gradientTransform="matrix(-1 0 0 1 540.7146 0)" gradientUnits="userSpaceOnUse">
<stop offset="0.1989" style="stop-color:#EE2724"/>
<stop offset="0.3065" style="stop-color:#EE2424"/>
<stop offset="1" style="stop-color:#CD2027"/>
</radialGradient>
<polygon fill="url(#SVGID_2_)" points="272.4,18.4 283.3,39 296.3,14.3 319,14.3 294.7,60.5 319,106.7 296.3,106.7 283.3,82.1
270.3,106.7 263.5,106.7 255.6,91.7 272,60.5 260.9,39.4 "/>
<linearGradient id="SVGID_3_" gradientUnits="userSpaceOnUse" x1="43.4116" y1="15.5743" x2="43.4116" y2="380.5575">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_3_)" d="M9.3,35h18.8l15.3,27.6L58.7,35h18.8v71.2H59.8V65.3L43.5,93.2h-0.4L26.8,65.5v40.7H9.3V35z"/>
<linearGradient id="SVGID_4_" gradientUnits="userSpaceOnUse" x1="108.1806" y1="15.5743" x2="108.1806" y2="380.5575">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_4_)" d="M99.3,79.5L74.9,35h20.2l13.2,25.9L121.6,35h19.9l-24.4,44.3v27H99.3V79.5z"/>
<linearGradient id="SVGID_5_" gradientUnits="userSpaceOnUse" x1="349.3989" y1="15.5743" x2="349.3989" y2="380.5575">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_5_)" d="M322.3,35h27.5c4,0,7.7,0.6,11,1.7c3.3,1.1,6.1,2.7,8.4,4.9c2.3,2.1,4.1,4.8,5.4,7.9
c1.3,3.1,1.9,6.6,1.9,10.6v0.2c0,4.2-0.7,7.9-2.1,11.1c-1.4,3.2-3.3,5.9-5.7,8c-2.4,2.2-5.4,3.8-8.7,4.9c-3.4,1.1-7.1,1.6-11,1.6
h-8.8v20.4h-17.8V35z M348.5,70.4c3.2,0,5.7-0.8,7.5-2.5c1.8-1.7,2.7-3.9,2.7-6.8v-0.2c0-3.1-0.9-5.4-2.7-7
c-1.8-1.6-4.3-2.4-7.6-2.4h-8.3v18.9H348.5z"/>
<linearGradient id="SVGID_6_" gradientUnits="userSpaceOnUse" x1="402.2677" y1="15.5743" x2="402.2677" y2="380.5575">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_6_)" d="M393.7,34.5h17.1l27.3,71.7h-19l-4.7-12.7h-24.7l-4.6,12.7h-18.7L393.7,34.5z M409.3,78.3L402.1,58
l-7.2,20.3H409.3z"/>
<linearGradient id="SVGID_7_" gradientUnits="userSpaceOnUse" x1="460.045" y1="15.5743" x2="460.045" y2="380.5575">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_7_)" d="M462.1,107.5c-5.7,0-11.2-1-16.3-3c-5.2-2-9.7-5-13.7-8.9l9.9-13.2c6.4,5.7,13.3,8.5,20.8,8.5
c2.4,0,4.2-0.4,5.4-1.3c1.3-0.8,1.9-2,1.9-3.6v-0.2c0-0.7-0.2-1.4-0.5-2c-0.3-0.6-0.9-1.1-1.7-1.7c-0.8-0.5-1.9-1.1-3.3-1.6
c-1.4-0.5-3.2-1-5.4-1.6c-3.4-0.9-6.6-1.8-9.5-2.9c-2.9-1-5.5-2.4-7.6-4.1c-2.2-1.7-3.9-3.7-5.1-6.2c-1.3-2.5-1.9-5.5-1.9-9.2v-0.2
c0-3.3,0.6-6.4,1.7-9.1c1.1-2.8,2.8-5.2,4.9-7.2c2.2-2,4.8-3.6,7.8-4.7c3.1-1.1,6.5-1.7,10.3-1.7c5.5,0,10.4,0.8,14.7,2.4
c4.3,1.6,8.2,4,11.7,7.1l-8.9,14c-2.9-2.3-5.9-4.1-9-5.2c-3.1-1.2-6.1-1.8-8.9-1.8c-2.1,0-3.7,0.4-4.8,1.3c-1.1,0.9-1.6,2-1.6,3.2
v0.2c0,0.8,0.2,1.5,0.5,2.1c0.3,0.6,0.9,1.2,1.7,1.7c0.8,0.5,2,1,3.4,1.5c1.4,0.5,3.3,1,5.4,1.6c3.7,0.9,7,1.9,9.9,3.1
c3,1.2,5.5,2.6,7.6,4.3c2.1,1.7,3.7,3.7,4.8,6.1s1.6,5.3,1.6,8.6v0.2c0,3.7-0.6,6.9-1.9,9.8c-1.3,2.8-3,5.3-5.3,7.3
c-2.3,2-5,3.5-8.2,4.6C469.6,106.9,466,107.5,462.1,107.5z"/>
<linearGradient id="SVGID_8_" gradientUnits="userSpaceOnUse" x1="512.3254" y1="15.5743" x2="512.3254" y2="380.5575">
<stop offset="0" style="stop-color:#FFFFFF"/>
<stop offset="1" style="stop-color:#000000"/>
</linearGradient>
<path fill="url(#SVGID_8_)" d="M514.4,107.5c-5.7,0-11.2-1-16.3-3c-5.2-2-9.7-5-13.7-8.9l9.9-13.2c6.4,5.7,13.3,8.5,20.8,8.5
c2.4,0,4.2-0.4,5.4-1.3c1.3-0.8,1.9-2,1.9-3.6v-0.2c0-0.7-0.2-1.4-0.5-2c-0.3-0.6-0.9-1.1-1.7-1.7c-0.8-0.5-1.9-1.1-3.3-1.6
c-1.4-0.5-3.2-1-5.4-1.6c-3.4-0.9-6.6-1.8-9.5-2.9s-5.5-2.4-7.6-4.1c-2.2-1.7-3.9-3.7-5.1-6.2c-1.3-2.5-1.9-5.5-1.9-9.2v-0.2
c0-3.3,0.6-6.4,1.7-9.1c1.1-2.8,2.8-5.2,4.9-7.2c2.2-2,4.8-3.6,7.8-4.7c3.1-1.1,6.5-1.7,10.3-1.7c5.5,0,10.4,0.8,14.7,2.4
c4.3,1.6,8.2,4,11.7,7.1l-8.9,14c-2.9-2.3-5.9-4.1-9-5.2c-3.1-1.2-6.1-1.8-8.9-1.8c-2.1,0-3.7,0.4-4.8,1.3c-1.1,0.9-1.6,2-1.6,3.2
v0.2c0,0.8,0.2,1.5,0.5,2.1c0.3,0.6,0.9,1.2,1.7,1.7c0.8,0.5,2,1,3.4,1.5c1.4,0.5,3.3,1,5.4,1.6c3.7,0.9,7,1.9,9.9,3.1
c3,1.2,5.5,2.6,7.6,4.3c2.1,1.7,3.7,3.7,4.8,6.1s1.6,5.3,1.6,8.6v0.2c0,3.7-0.6,6.9-1.9,9.8c-1.3,2.8-3,5.3-5.3,7.3
c-2.3,2-5,3.5-8.2,4.6C521.8,106.9,518.3,107.5,514.4,107.5z"/>
<g>
<radialGradient id="SVGID_9_" cx="227.409" cy="56.389" r="44.9787" gradientUnits="userSpaceOnUse">
<stop offset="0.5744" style="stop-color:#E82325"/>
<stop offset="1" style="stop-color:#ED1C24"/>
</radialGradient>
<path fill="url(#SVGID_9_)" d="M215,56.4L188.5,6h24.7l14.1,26.9L241.5,6h24.7l-26.5,50.3l26.5,50.4h-24.7l-14.1-26.9l-14.1,26.9
h-24.7L215,56.4z"/>
</g>
<radialGradient id="SVGID_10_" cx="270.4181" cy="60.5308" r="41.2772" gradientTransform="matrix(-1 0 0 1 556.5228 0)" gradientUnits="userSpaceOnUse">
<stop offset="0.3863" style="stop-color:#E81D25"/>
<stop offset="0.5804" style="stop-color:#E21E25"/>
<stop offset="0.7696" style="stop-color:#D51E25"/>
<stop offset="0.9564" style="stop-color:#C12025"/>
<stop offset="1" style="stop-color:#BB2025"/>
</radialGradient>
<polygon fill="url(#SVGID_10_)" points="261.9,14.3 256.2,25.2 256.2,25.2 261.9,14.3 "/>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -2,444 +2,446 @@
const upsert = require('../src/utils/upsert');
const parentNetworks = [
{
slug: 'gamma',
name: 'Gamma Entertainment',
url: 'https://www.gammaentertainment.com',
},
{
slug: 'hush',
name: 'Hush',
},
{
slug: 'mindgeek',
name: 'Mind Geek',
url: 'https://www.mindgeek.com',
description: '',
},
{
slug: 'whalemember',
name: 'Whale Member',
},
{
slug: 'gamma',
name: 'Gamma Entertainment',
url: 'https://www.gammaentertainment.com',
},
{
slug: 'hush',
name: 'Hush',
},
{
slug: 'mindgeek',
name: 'Mind Geek',
url: 'https://www.mindgeek.com',
description: '',
},
{
slug: 'whalemember',
name: 'Whale Member',
},
];
const networks = [
{
slug: '21sextury',
name: '21Sextury',
url: 'https://www.21sextury.com',
description: 'Watch all the latest scenes and porn video updates on 21Sextury.com, the best European porn site with the hottest pornstars from all over the world! Watch porn videos from the large network here.',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: '21sextreme',
name: '21Sextreme',
url: 'https://www.21sextreme.com',
description: 'Welcome to 21Sextreme.com, your portal to fisting porn, old and young lesbians, horny grannies & extreme BDSM featuring the best Euro & American Pornstars',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: '21naturals',
name: '21Naturals',
url: 'https://www.21naturals.com',
description: 'Welcome to 21Naturals.com, the porn network featuring the hottest pornstars from all over the world in all natural porn and erotic sex videos. Watch thousands of girls with natural tits',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: 'adulttime',
name: 'Adult Time',
url: 'https://www.adulttime.com',
description: 'Adult Time is a premium streaming service for adults! Watch adult movies, series, and channels from the top names in the industry.',
parent: 'gamma',
},
{
slug: 'amateurallure',
name: 'Amateur Allure',
url: 'https://www.amateurallure.com',
},
{
slug: 'assylum',
name: 'Assylum',
url: 'https://www.assylum.com',
description: 'At Assylum, submissive girls get dominated with rough anal sex, ass to mouth, hard BDSM, and sexual humiliation and degradation.',
},
{
slug: 'aziani',
name: 'Aziani',
url: 'https://www.aziani.com',
},
{
slug: 'babes',
name: 'Babes',
url: 'https://www.babes.com',
parent: 'mindgeek',
},
{
slug: 'bamvisions',
name: 'BAM Visions',
url: 'https://www.bamvisions.com',
},
{
slug: 'bang',
name: 'Bang!',
url: 'https://bang.com',
},
{
slug: 'bangbros',
name: 'Bang Bros',
url: 'https://bangbros.com',
description: 'Here at Bang Bros, we only film the best highest quality porn with the sexiest Amateur girls and the top pornstars. Updated daily on Bangbros.com.',
},
{
slug: 'blowpass',
name: 'Blowpass',
url: 'https://www.blowpass.com',
description: 'Welcome to Blowpass.com, your ultimate source for deepthroat porn, MILF and teen blowjob videos, big cumshots and any and everything oral!',
parameters: {
mobile: 'https://m.blowpass.com/en/video/v/%d', // v can be any string, %d will be scene ID
},
parent: 'gamma',
},
{
slug: 'brazzers',
name: 'Brazzers',
url: 'https://www.brazzers.com',
description: 'Brazzers homepage is updated daily with official HD porn scenes. Our hottest videos and sex series are filled with big tits, sexy milf, top pornstars and special events.',
},
{
slug: 'boobpedia',
name: 'Boobpedia',
url: 'https://www.boobpedia.com',
},
{
slug: 'burningangel',
name: 'Burning Angel',
url: 'https://www.burningangel.com',
description: 'BurningAngel.com features tattoo porn with punk girls, goths, emo and the best scene girl porn online! View Joanna Angel and all of her alt pornstars in rough sex videos and hardcore porn',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: 'cherrypimps',
name: 'Cherry Pimps',
url: 'https://www.cherrypimps.com',
description: 'CherryPimps your premium porn site to Download and Stream the hottest and most exclusive 4K HD videos and pictures on your phone, tablet, TV or console.',
},
{
slug: 'freeones',
name: 'FreeOnes',
url: 'https://www.freeones.com',
},
{
slug: 'ddfnetwork',
name: 'DDF Network',
url: 'https://ddfnetwork.com',
description: 'European porn videos hub with exclusive VR, 4K and full HD XXX videos and hot sex photos of Europes finest porn star babes.',
},
{
slug: 'digitalplayground',
name: 'Digital Playground',
url: 'https://www.digitalplayground.com',
description: 'DigitalPlayground.com is the leader in high quality adult blockbuster movies and award winning sex parodies that feature the most exclusive pornstars online! Adult Film Database of adult movies.',
parent: 'mindgeek',
},
{
slug: 'dogfartnetwork',
name: 'Dogfart Network',
url: 'https://dogfartnetwork.com',
description: 'The world famous Dogfart Interracial series. Online since 1996, we have the largest collection of Interracial videos, pictures and content on the web.',
},
{
slug: 'evilangel',
name: 'Evil Angel',
url: 'https://evilangel.com',
description: 'Welcome to the award winning Evil Angel website, home to the most popular pornstars of today, yesterday and tomorrow in their most extreme and hardcore porn scenes to date. We feature almost 30 years of rough sex videos and hardcore anal porn like you\'ve never seen before, and have won countless AVN and XBiz awards including \'Best Site\' and \'Best Studio\'.',
parent: 'gamma',
},
{
slug: 'fantasymassage',
name: 'Fantasy Massage',
url: 'https://www.fantasymassage.com',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: 'famedigital',
name: 'Fame Digital',
url: 'https://www.famedigital.com',
description: 'Watch and download thousands of the best porn videos at FameDigital.com, the largest porn network on the web! The hottest teens, MILFs and more pornstars are all here!',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: 'fakehub',
name: 'Fake Hub',
url: 'https://www.fakehub.com',
description: 'Wherever they go, there is porn. Hospital, Taxis, Casting… Maybe fucking to a fake cop, fake agent or fake taxi driver. And we record it all.',
parent: 'mindgeek',
},
{
slug: 'fullpornnetwork',
name: 'Full Porn Network',
url: 'https://www.fullpornnetwork.com',
description: 'FullPornNetwork.com is the latest and greatest for one stop shop porn sites. Check out the expanding library of the multi-site network. All of fan\'s favorite content from ANALIZED.COM, DTFsluts.com, YourMomDoesPorn.com and many more. Give die hard porn fans access to an array of premium content available in 4k and 1080p. Full access included streaming hd and unlimited downloads. Be exclusive, be a member to FullPornNetwork.com Today.',
},
{
slug: 'girlsway',
name: 'Girlsway',
url: 'https://www.girlsway.com',
description: 'Girlsway.com has the best lesbian porn videos online! The hottest pornstars & first time lesbians in real girl on girl sex, tribbing, squirting & pussy licking action right HERE!',
parent: 'gamma',
},
{
slug: 'hussiepass',
name: 'Hussie Pass',
url: 'http://www.hussiepass.com',
parent: 'hush',
},
{
slug: 'hushpass',
name: 'Hush Pass',
url: 'http://www.hushpass.com',
parent: 'hush',
parameters: {
sequential: true,
},
},
{
slug: 'interracialpass',
name: 'Interracial Pass',
url: 'http://www.interracialpass.com',
parent: 'hush',
parameters: {
sequential: true,
},
},
{
slug: 'insex',
name: 'Insex',
description: 'The original bondage and BDSM transgression.',
url: 'http://www.insex.com',
},
{
slug: 'jayrock',
name: 'JayRock Productions',
url: 'http://jayrockcontent.com',
parent: 'gamma',
},
{
slug: 'jesseloadsmonsterfacials',
name: 'Jesse Loads Monster Facials',
url: 'http://www.jesseloadsmonsterfacials.com',
},
{
slug: 'julesjordan',
name: 'Jules Jordan',
url: 'https://www.julesjordan.com',
},
{
slug: 'kellymadison',
name: 'Kelly Madison Media',
url: 'https://www.kellymadison.com',
description: 'Home of Kelly Madison and Ryan Madison',
},
{
slug: 'kink',
name: 'Kink',
url: 'https://www.kink.com',
description: 'Authentic Bondage & Real BDSM Porn Videos. Demystifying and celebrating alternative sexuality by providing the most authentic kinky videos. Experience the other side of porn.',
},
{
slug: 'legalporno',
name: 'LegalPorno',
url: 'https://www.legalporno.com',
description: 'The Best HD Porn For You!',
},
{
slug: 'men',
name: 'Men',
url: 'https://www.men.com',
description: 'Check out the best gay porn site on the net with daily updates, award-winning original series, exclusive Men.com models and over 800 of the hottest guys in gay porn.',
parent: 'mindgeek',
},
{
slug: 'metrohd',
name: 'Metro HD',
url: 'https://www.metrohd.com',
description: 'Checkout MetroHD official pornsite featuring top rated pornstars and XXX videos.',
parent: 'mindgeek',
},
{
slug: 'mikeadriano',
name: 'Mike Adriano',
url: null,
description: null,
},
{
slug: 'milehighmedia',
name: 'Mile High Media',
url: 'https://www.milehighmedia.com',
description: 'MileHighMedia.com is the only niche porn network you need! Watch lesbian sex, hardcore fucking and family porn stories with the hottest teens & MILFs!',
parent: 'mindgeek',
},
{
slug: 'mofos',
name: 'MOFOS',
url: 'https://www.mofos.com',
description: 'Check out the Official Mofos Network of best amateur pornsites. Girlfriend voyeur - college girls - first anal & more. Bonus Milf sites for wifey lovers.',
parent: 'mindgeek',
},
{
slug: 'naughtyamerica',
name: 'Naughty America',
url: 'https://www.naughtyamerica.com',
description: 'The best porn movies daily at Naughty America! Experience the most seductive porn stars in stunning virtual reality, 4K and HD porn videos!',
},
{
slug: 'newsensations',
name: 'New Sensations',
url: 'https://www.newsensations.com',
description: 'Home to multiple award-winning studios New Sensations & Digital Sin with over 7,000 HQ porn movies! Take the free tour now!',
},
{
slug: 'nubiles',
name: 'Nubiles',
url: 'https://www.nubiles.com',
description: 'Welcome to the teen megasite that started it all! Browse our massive HD collection of fresh legal hotties at Nubiles.net.',
},
{
slug: 'perfectgonzo',
name: 'Perfect Gonzo',
url: 'https://www.perfectgonzo.com',
description: '',
},
{
slug: 'pervcity',
name: 'Perv City',
url: 'https://www.pervcity.com',
description: '',
},
{
slug: 'pimpxxx',
name: 'Pimp.XXX',
url: 'https://www.pimp.xxx',
description: 'PIMP.XXX is the NEWEST and HOTTEST site featuring Exclusive Ultra High Definition 4k videos updated daily! Featuring the newest and the biggest pornstars with Big Tits, Tight Asses, and more!',
},
{
slug: 'pornpros',
name: 'Porn Pros',
url: 'https://pornpros.com',
description: 'Watch the best HD exclusive movies and videos on Porn Pros. All the hottest new Pornstar and amateur girls in High Definition updated daily.',
parent: 'whalemember',
},
{
slug: 'private',
name: 'Private',
url: 'https://www.private.com',
description: 'Private is the best source for adult movies and videos. Featuring the most popular hardcore adult stars in hundreds of porn movies, Private.com delivers...',
},
{
slug: 'puretaboo',
name: 'Pure Taboo',
url: 'https://www.puretaboo.com',
description: 'PureTaboo.com is the ultimate site for family taboo porn, featuring submissive teens & virgins in rough sex videos in ultra 4k HD.',
parent: 'gamma',
},
{
slug: 'realitykings',
name: 'Reality Kings',
url: 'https://www.realitykings.com',
description: 'Home of HD reality porn featuring the nicest tits and ass online! The hottest curvy girls in real amateur sex stories are only on REALITYkings.com',
parent: 'mindgeek',
},
{
slug: 'score',
name: 'SCORE',
url: 'https://www.scorepass.com',
description: '',
},
{
slug: 'sexyhub',
name: 'Sexy Hub',
url: 'https://www.sexyhub.com',
parent: 'mindgeek',
},
{
slug: 'teamskeet',
name: 'Team Skeet',
url: 'https://www.teamskeet.com',
description: 'Welcome to teamskeet.com, the largest collection of exclusive teen porn sites and videos on the web. Check out our TeamSkeet porn sites now.',
},
{
slug: 'twistys',
name: 'Twistys',
url: 'https://www.twistys.com',
description: 'The hottest high quality glamour porn for over 18 years! Over 3700+ models and 46000+ scenes. TWISTYS.com',
parent: 'mindgeek',
},
{
slug: 'vivid',
name: 'Vivid',
url: 'https://www.vivid.com',
description: 'Home of the Kim Kardashian Sex Tape, Porn Parodies, and over 30,000 XXX Movies from The World Leader In Adult Entertainment.',
parent: 'gamma',
},
{
slug: 'vixen',
name: 'Vixen',
url: 'https://www.vixen.com',
description: 'Vixen.com features the worlds finest cinematic adult films with 4K quality and high-end erotic photography.',
},
{
slug: 'vogov',
name: 'VogoV',
url: 'https://www.vogov.com',
description: 'Fantastic collection of exclusive porn movies with the most beautiful porn models in leading roles saisfies the most picky visitor of the site.',
},
{
slug: 'wicked',
name: 'Wicked',
url: 'https://www.wicked.com',
description: 'Welcome to the new Wicked.com! Watch over 25 years of Wicked Pictures\' brand of award-winning porn for couples and women in 4k HD movies & xxx videos',
parent: 'gamma',
},
{
slug: 'xempire',
name: 'XEmpire',
url: 'https://www.xempire.com',
description: 'XEmpire.com brings you today\'s top pornstars in beautifully shot, HD sex scenes across 4 unique porn sites of gonzo porn, interracial, lesbian & erotica!',
parent: 'gamma',
},
{
slug: '21sextury',
name: '21Sextury',
url: 'https://www.21sextury.com',
description: 'Watch all the latest scenes and porn video updates on 21Sextury.com, the best European porn site with the hottest pornstars from all over the world! Watch porn videos from the large network here.',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: '21sextreme',
name: '21Sextreme',
url: 'https://www.21sextreme.com',
description: 'Welcome to 21Sextreme.com, your portal to fisting porn, old and young lesbians, horny grannies & extreme BDSM featuring the best Euro & American Pornstars',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: '21naturals',
name: '21Naturals',
url: 'https://www.21naturals.com',
description: 'Welcome to 21Naturals.com, the porn network featuring the hottest pornstars from all over the world in all natural porn and erotic sex videos. Watch thousands of girls with natural tits',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: 'adulttime',
name: 'Adult Time',
url: 'https://www.adulttime.com',
description: 'Adult Time is a premium streaming service for adults! Watch adult movies, series, and channels from the top names in the industry.',
parent: 'gamma',
},
{
slug: 'amateurallure',
name: 'Amateur Allure',
url: 'https://www.amateurallure.com',
},
{
slug: 'assylum',
name: 'Assylum',
url: 'https://www.assylum.com',
description: 'At Assylum, submissive girls get dominated with rough anal sex, ass to mouth, hard BDSM, and sexual humiliation and degradation.',
},
{
slug: 'aziani',
name: 'Aziani',
url: 'https://www.aziani.com',
},
{
slug: 'babes',
name: 'Babes',
url: 'https://www.babes.com',
parent: 'mindgeek',
},
{
slug: 'bamvisions',
name: 'BAM Visions',
url: 'https://www.bamvisions.com',
},
{
slug: 'bang',
name: 'Bang!',
url: 'https://bang.com',
},
{
slug: 'bangbros',
name: 'Bang Bros',
url: 'https://bangbros.com',
description: 'Here at Bang Bros, we only film the best highest quality porn with the sexiest Amateur girls and the top pornstars. Updated daily on Bangbros.com.',
},
{
slug: 'blowpass',
name: 'Blowpass',
alias: ['myxxxpass'],
url: 'https://www.blowpass.com',
description: 'Welcome to Blowpass.com, your ultimate source for deepthroat porn, MILF and teen blowjob videos, big cumshots and any and everything oral!',
parameters: {
mobile: 'https://m.blowpass.com/en/video/v/%d', // v can be any string, %d will be scene ID
},
parent: 'gamma',
},
{
slug: 'brazzers',
name: 'Brazzers',
url: 'https://www.brazzers.com',
description: 'Brazzers homepage is updated daily with official HD porn scenes. Our hottest videos and sex series are filled with big tits, sexy milf, top pornstars and special events.',
},
{
slug: 'boobpedia',
name: 'Boobpedia',
url: 'https://www.boobpedia.com',
},
{
slug: 'burningangel',
name: 'Burning Angel',
url: 'https://www.burningangel.com',
description: 'BurningAngel.com features tattoo porn with punk girls, goths, emo and the best scene girl porn online! View Joanna Angel and all of her alt pornstars in rough sex videos and hardcore porn',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: 'cherrypimps',
name: 'Cherry Pimps',
url: 'https://www.cherrypimps.com',
description: 'CherryPimps your premium porn site to Download and Stream the hottest and most exclusive 4K HD videos and pictures on your phone, tablet, TV or console.',
},
{
slug: 'freeones',
name: 'FreeOnes',
url: 'https://www.freeones.com',
},
{
slug: 'ddfnetwork',
name: 'DDF Network',
url: 'https://ddfnetwork.com',
description: 'European porn videos hub with exclusive VR, 4K and full HD XXX videos and hot sex photos of Europes finest porn star babes.',
},
{
slug: 'digitalplayground',
name: 'Digital Playground',
url: 'https://www.digitalplayground.com',
description: 'DigitalPlayground.com is the leader in high quality adult blockbuster movies and award winning sex parodies that feature the most exclusive pornstars online! Adult Film Database of adult movies.',
parent: 'mindgeek',
},
{
slug: 'dogfartnetwork',
name: 'Dogfart Network',
url: 'https://dogfartnetwork.com',
description: 'The world famous Dogfart Interracial series. Online since 1996, we have the largest collection of Interracial videos, pictures and content on the web.',
},
{
slug: 'evilangel',
name: 'Evil Angel',
url: 'https://evilangel.com',
description: 'Welcome to the award winning Evil Angel website, home to the most popular pornstars of today, yesterday and tomorrow in their most extreme and hardcore porn scenes to date. We feature almost 30 years of rough sex videos and hardcore anal porn like you\'ve never seen before, and have won countless AVN and XBiz awards including \'Best Site\' and \'Best Studio\'.',
parent: 'gamma',
},
{
slug: 'fantasymassage',
name: 'Fantasy Massage',
url: 'https://www.fantasymassage.com',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: 'famedigital',
name: 'Fame Digital',
url: 'https://www.famedigital.com',
description: 'Watch and download thousands of the best porn videos at FameDigital.com, the largest porn network on the web! The hottest teens, MILFs and more pornstars are all here!',
parameters: {
mobile: 'https://m.dpfanatics.com/en/video',
},
parent: 'gamma',
},
{
slug: 'fakehub',
name: 'Fake Hub',
url: 'https://www.fakehub.com',
description: 'Wherever they go, there is porn. Hospital, Taxis, Casting… Maybe fucking to a fake cop, fake agent or fake taxi driver. And we record it all.',
parent: 'mindgeek',
},
{
slug: 'fullpornnetwork',
name: 'Full Porn Network',
url: 'https://www.fullpornnetwork.com',
description: 'FullPornNetwork.com is the latest and greatest for one stop shop porn sites. Check out the expanding library of the multi-site network. All of fan\'s favorite content from ANALIZED.COM, DTFsluts.com, YourMomDoesPorn.com and many more. Give die hard porn fans access to an array of premium content available in 4k and 1080p. Full access included streaming hd and unlimited downloads. Be exclusive, be a member to FullPornNetwork.com Today.',
},
{
slug: 'girlsway',
name: 'Girlsway',
url: 'https://www.girlsway.com',
description: 'Girlsway.com has the best lesbian porn videos online! The hottest pornstars & first time lesbians in real girl on girl sex, tribbing, squirting & pussy licking action right HERE!',
parent: 'gamma',
},
{
slug: 'hussiepass',
name: 'Hussie Pass',
url: 'http://www.hussiepass.com',
parent: 'hush',
},
{
slug: 'hushpass',
name: 'Hush Pass',
url: 'http://www.hushpass.com',
parent: 'hush',
parameters: {
sequential: true,
},
},
{
slug: 'interracialpass',
name: 'Interracial Pass',
url: 'http://www.interracialpass.com',
parent: 'hush',
parameters: {
sequential: true,
},
},
{
slug: 'insex',
name: 'Insex',
description: 'The original bondage and BDSM transgression.',
url: 'http://www.insex.com',
},
{
slug: 'jayrock',
name: 'JayRock Productions',
url: 'http://jayrockcontent.com',
parent: 'gamma',
},
{
slug: 'jesseloadsmonsterfacials',
name: 'Jesse Loads Monster Facials',
url: 'http://www.jesseloadsmonsterfacials.com',
},
{
slug: 'julesjordan',
name: 'Jules Jordan',
url: 'https://www.julesjordan.com',
},
{
slug: 'kellymadison',
name: 'Kelly Madison Media',
url: 'https://www.kellymadison.com',
description: 'Home of Kelly Madison and Ryan Madison',
},
{
slug: 'kink',
name: 'Kink',
url: 'https://www.kink.com',
description: 'Authentic Bondage & Real BDSM Porn Videos. Demystifying and celebrating alternative sexuality by providing the most authentic kinky videos. Experience the other side of porn.',
},
{
slug: 'legalporno',
name: 'LegalPorno',
url: 'https://www.legalporno.com',
description: 'The Best HD Porn For You!',
},
{
slug: 'men',
name: 'Men',
url: 'https://www.men.com',
description: 'Check out the best gay porn site on the net with daily updates, award-winning original series, exclusive Men.com models and over 800 of the hottest guys in gay porn.',
parent: 'mindgeek',
},
{
slug: 'metrohd',
name: 'Metro HD',
url: 'https://www.metrohd.com',
description: 'Checkout MetroHD official pornsite featuring top rated pornstars and XXX videos.',
parent: 'mindgeek',
},
{
slug: 'mikeadriano',
name: 'Mike Adriano',
url: null,
description: null,
},
{
slug: 'milehighmedia',
name: 'Mile High Media',
url: 'https://www.milehighmedia.com',
description: 'MileHighMedia.com is the only niche porn network you need! Watch lesbian sex, hardcore fucking and family porn stories with the hottest teens & MILFs!',
parent: 'mindgeek',
},
{
slug: 'mofos',
name: 'MOFOS',
url: 'https://www.mofos.com',
description: 'Check out the Official Mofos Network of best amateur pornsites. Girlfriend voyeur - college girls - first anal & more. Bonus Milf sites for wifey lovers.',
parent: 'mindgeek',
},
{
slug: 'naughtyamerica',
name: 'Naughty America',
url: 'https://www.naughtyamerica.com',
description: 'The best porn movies daily at Naughty America! Experience the most seductive porn stars in stunning virtual reality, 4K and HD porn videos!',
},
{
slug: 'newsensations',
name: 'New Sensations',
url: 'https://www.newsensations.com',
description: 'Home to multiple award-winning studios New Sensations & Digital Sin with over 7,000 HQ porn movies! Take the free tour now!',
},
{
slug: 'nubiles',
name: 'Nubiles',
url: 'https://www.nubiles.com',
description: 'Welcome to the teen megasite that started it all! Browse our massive HD collection of fresh legal hotties at Nubiles.net.',
},
{
slug: 'perfectgonzo',
name: 'Perfect Gonzo',
url: 'https://www.perfectgonzo.com',
description: '',
},
{
slug: 'pervcity',
name: 'Perv City',
url: 'https://www.pervcity.com',
description: '',
},
{
slug: 'pimpxxx',
name: 'Pimp.XXX',
url: 'https://www.pimp.xxx',
description: 'PIMP.XXX is the NEWEST and HOTTEST site featuring Exclusive Ultra High Definition 4k videos updated daily! Featuring the newest and the biggest pornstars with Big Tits, Tight Asses, and more!',
},
{
slug: 'pornpros',
name: 'Porn Pros',
url: 'https://pornpros.com',
description: 'Watch the best HD exclusive movies and videos on Porn Pros. All the hottest new Pornstar and amateur girls in High Definition updated daily.',
parent: 'whalemember',
},
{
slug: 'private',
name: 'Private',
url: 'https://www.private.com',
description: 'Private is the best source for adult movies and videos. Featuring the most popular hardcore adult stars in hundreds of porn movies, Private.com delivers...',
},
{
slug: 'puretaboo',
name: 'Pure Taboo',
url: 'https://www.puretaboo.com',
description: 'PureTaboo.com is the ultimate site for family taboo porn, featuring submissive teens & virgins in rough sex videos in ultra 4k HD.',
parent: 'gamma',
},
{
slug: 'realitykings',
name: 'Reality Kings',
url: 'https://www.realitykings.com',
description: 'Home of HD reality porn featuring the nicest tits and ass online! The hottest curvy girls in real amateur sex stories are only on REALITYkings.com',
parent: 'mindgeek',
},
{
slug: 'score',
name: 'SCORE',
url: 'https://www.scorepass.com',
description: '',
},
{
slug: 'sexyhub',
name: 'Sexy Hub',
url: 'https://www.sexyhub.com',
parent: 'mindgeek',
},
{
slug: 'teamskeet',
name: 'Team Skeet',
url: 'https://www.teamskeet.com',
description: 'Welcome to teamskeet.com, the largest collection of exclusive teen porn sites and videos on the web. Check out our TeamSkeet porn sites now.',
},
{
slug: 'twistys',
name: 'Twistys',
url: 'https://www.twistys.com',
description: 'The hottest high quality glamour porn for over 18 years! Over 3700+ models and 46000+ scenes. TWISTYS.com',
parent: 'mindgeek',
},
{
slug: 'vivid',
name: 'Vivid',
url: 'https://www.vivid.com',
description: 'Home of the Kim Kardashian Sex Tape, Porn Parodies, and over 30,000 XXX Movies from The World Leader In Adult Entertainment.',
parent: 'gamma',
},
{
slug: 'vixen',
name: 'Vixen',
url: 'https://www.vixen.com',
description: 'Vixen.com features the worlds finest cinematic adult films with 4K quality and high-end erotic photography.',
},
{
slug: 'vogov',
name: 'VogoV',
url: 'https://www.vogov.com',
description: 'Fantastic collection of exclusive porn movies with the most beautiful porn models in leading roles saisfies the most picky visitor of the site.',
},
{
slug: 'wicked',
name: 'Wicked',
url: 'https://www.wicked.com',
description: 'Welcome to the new Wicked.com! Watch over 25 years of Wicked Pictures\' brand of award-winning porn for couples and women in 4k HD movies & xxx videos',
parent: 'gamma',
},
{
slug: 'xempire',
name: 'XEmpire',
url: 'https://www.xempire.com',
description: 'XEmpire.com brings you today\'s top pornstars in beautifully shot, HD sex scenes across 4 unique porn sites of gonzo porn, interracial, lesbian & erotica!',
parent: 'gamma',
},
];
exports.seed = knex => Promise.resolve()
.then(async () => {
const { inserted, updated } = await upsert('networks', parentNetworks, 'slug', knex);
const parentNetworksBySlug = [].concat(inserted, updated).reduce((acc, network) => ({ ...acc, [network.slug]: network.id }), {});
.then(async () => {
const { inserted, updated } = await upsert('networks', parentNetworks, 'slug', knex);
const parentNetworksBySlug = [].concat(inserted, updated).reduce((acc, network) => ({ ...acc, [network.slug]: network.id }), {});
const networksWithParent = networks.map(network => ({
slug: network.slug,
name: network.name,
url: network.url,
description: network.description,
parameters: network.parameters,
parent_id: parentNetworksBySlug[network.parent] || null,
}));
const networksWithParent = networks.map(network => ({
slug: network.slug,
name: network.name,
alias: (network.alias || []).join(','),
url: network.url,
description: network.description,
parameters: network.parameters,
parent_id: parentNetworksBySlug[network.parent] || null,
}));
return upsert('networks', networksWithParent, 'slug', knex);
});
return upsert('networks', networksWithParent, 'slug', knex);
});

View File

@ -13,6 +13,7 @@ const logger = require('./logger')(__filename);
const slugify = require('./utils/slugify');
const capitalize = require('./utils/capitalize');
const resolvePlace = require('./utils/resolve-place');
const { associateAvatars } = require('./media');
const { toBaseReleases } = require('./deep');
@ -80,6 +81,7 @@ function curateProfileEntry(profile) {
has_piercings: profile.hasPiercings,
piercings: profile.piercings,
tattoos: profile.tattoos,
avatar_media_id: profile.avatarMediaId || null,
};
return curatedProfileEntry;
@ -91,6 +93,7 @@ async function curateProfile(profile) {
id: profile.id,
name: profile.name,
avatar: profile.avatar,
scraper: profile.scraper,
};
curatedProfile.site = profile.site.isNetwork ? null : profile.site;
@ -198,6 +201,7 @@ async function scrapeProfiles(actor, sources, networksBySlug, sitesBySlug) {
return {
...actor,
...profile,
scraper: scraperSlug,
site: siteOrNetwork,
};
}), Promise.reject(new Error()));
@ -256,16 +260,16 @@ async function upsertProfiles(curatedProfileEntries) {
}
if (argv.force && updatingProfileEntries.length > 0) {
knex.transaction(async (transaction) => {
const queries = updatingProfileEntries.map(profileEntry => knex('actors_profiles')
.where('id', profileEntry.id)
.update(profileEntry)
.transacting(transaction));
const transaction = await knex.transaction();
const queries = updatingProfileEntries.map(profileEntry => knex('actors_profiles')
.where('id', profileEntry.id)
.update(profileEntry)
.returning(['id', 'actor_id'])
.transacting(transaction));
return Promise.all(queries)
.then(transaction.commit)
.catch(transaction.rollback);
});
await Promise.all(queries)
.then(transaction.commit)
.catch(transaction.rollback);
}
}
@ -305,7 +309,9 @@ async function scrapeActors(actorNames) {
);
const profiles = await Promise.all(profilesPerActor.flat().map(profile => curateProfile(profile)));
const curatedProfileEntries = profiles.map(profile => curateProfileEntry(profile));
const profilesWithAvatarIds = await associateAvatars(profiles);
const curatedProfileEntries = profilesWithAvatarIds.map(profile => curateProfileEntry(profile));
await upsertProfiles(curatedProfileEntries);
}
@ -350,7 +356,7 @@ async function associateActors(releases, batchId) {
const baseActors = Object.values(baseActorsByReleaseId).flat();
if (baseActors.length === 0) {
return;
return null;
}
const baseActorsBySlugAndNetworkId = baseActors.reduce((acc, baseActor) => ({
@ -382,6 +388,8 @@ async function associateActors(releases, batchId) {
.flat();
await knex.raw(`${knex('releases_actors').insert(releaseActorAssociations).toString()} ON CONFLICT DO NOTHING;`);
return actors;
}
module.exports = {

View File

@ -106,10 +106,11 @@ function toBaseSource(rawSource) {
return null;
}
function baseSourceToBaseMedia(baseSource, role) {
function baseSourceToBaseMedia(baseSource, role, metadata) {
if (Array.isArray(baseSource)) {
if (baseSource.length > 0) {
return {
...metadata,
id: nanoid(),
role,
sources: baseSource,
@ -121,6 +122,7 @@ function baseSourceToBaseMedia(baseSource, role) {
if (baseSource) {
return {
...metadata,
id: nanoid(),
role,
sources: [baseSource],
@ -130,15 +132,15 @@ function baseSourceToBaseMedia(baseSource, role) {
return null;
}
function fallbackMediaToBaseMedia(rawMedia, role) {
function fallbackMediaToBaseMedia(rawMedia, role, metadata) {
const baseSources = rawMedia
.map(source => toBaseSource(source))
.filter(Boolean);
return baseSourceToBaseMedia(baseSources, role);
return baseSourceToBaseMedia(baseSources, role, metadata);
}
function toBaseMedias(rawMedias, role) {
function toBaseMedias(rawMedias, role, metadata) {
if (!rawMedias || rawMedias.length === 0) {
return [];
}
@ -150,12 +152,12 @@ function toBaseMedias(rawMedias, role) {
if (Array.isArray(rawMedia)) {
// fallback sources provided
return fallbackMediaToBaseMedia(rawMedia, role);
return fallbackMediaToBaseMedia(rawMedia, role, metadata);
}
const baseSource = toBaseSource(rawMedia);
return baseSourceToBaseMedia(baseSource, role);
return baseSourceToBaseMedia(baseSource, role, metadata);
}).filter(Boolean);
const sampledBaseMedias = sampleMedias(baseMedias);
@ -604,6 +606,44 @@ async function associateReleaseMedia(releases) {
}, Promise.resolve());
}
async function associateAvatars(profiles) {
if (!argv.media) {
return profiles;
}
const profilesWithBaseMedias = profiles.map(profile => (profile.avatar
? {
...profile,
avatarBaseMedia: toBaseMedias([profile.avatar], 'avatars', {
copyright: profile.network?.name || null,
scraper: profile.scraper || null,
})[0],
}
: profile
));
const baseMedias = profilesWithBaseMedias.map(profile => profile.avatarBaseMedia).filter(Boolean);
const storedMedias = await storeMedias(baseMedias);
const storedMediasById = itemsByKey(storedMedias, 'id');
const profilesWithAvatarIds = profilesWithBaseMedias.map((profile) => {
const media = storedMediasById[profile.avatarBaseMedia?.id];
if (media) {
return {
...profile,
avatarMediaId: media.use || media.entry.id,
};
}
return profile;
});
return profilesWithAvatarIds;
}
module.exports = {
associateAvatars,
associateReleaseMedia,
};

View File

@ -365,8 +365,8 @@ function scrapeApiProfile(data, releases, siteSlug) {
if (data.attributes.eye_color) profile.eyes = data.attributes.eye_color;
if (data.attributes.hair_color) profile.hair = data.attributes.hair_color;
const avatarPath = Object.values(data.pictures).reverse()[0];
if (avatarPath) profile.avatar = `https://images01-evilangel.gammacdn.com/actors${avatarPath}`;
const avatarPaths = Object.values(data.pictures).reverse();
if (avatarPaths.length > 0) profile.avatar = avatarPaths.map(avatarPath => `https://images01-evilangel.gammacdn.com/actors${avatarPath}`);
profile.releases = releases.map(release => `https://${siteSlug}.com/en/video/${release.url_title}/${release.clip_id}`);

View File

@ -342,8 +342,6 @@ function scrapeProfile(html, url, actorName) {
profile.releases = Array.from(document.querySelectorAll('.category_listing_block .update_details > a:first-child'), el => el.href);
console.log(profile);
return profile;
}

View File

@ -5,7 +5,7 @@ const config = require('config');
const logger = require('./logger')(__filename);
const knex = require('./knex');
const slugify = require('./utils/slugify');
const { associateActors } = require('./actors');
const { associateActors, scrapeActors } = require('./actors');
const { associateReleaseTags } = require('./tags');
const { curateSite } = require('./sites');
const { associateReleaseMedia } = require('./media');
@ -226,18 +226,19 @@ async function storeReleases(releases) {
const storedReleaseEntries = Array.isArray(storedReleases) ? storedReleases : [];
const releasesWithId = attachReleaseIds([].concat(uniqueReleases, duplicateReleases), [].concat(storedReleaseEntries, duplicateReleaseEntries));
await Promise.all([
const [actors] = await Promise.all([
associateActors(releasesWithId, batchId),
associateReleaseTags(releasesWithId),
]);
await updateReleasesSearch(releasesWithId.map(release => release.id));
// media is more error-prone, associate separately
await associateReleaseMedia(releasesWithId);
await scrapeActors(actors.map(actor => actor.name));
logger.info(`Stored ${storedReleaseEntries.length} releases`);
await updateReleasesSearch(releasesWithId.map(release => release.id));
return releasesWithId;
}

View File

@ -36,17 +36,13 @@ function useProxy(url) {
const queue = taskQueue();
queue.on('concurrencyReached:http', () => {
logger.silly('Queueing requests');
});
queue.define('http', async ({
async function handler({
url,
method = 'GET',
body,
headers = {},
options = {},
}) => {
}) {
if (body) {
logger.silly(`${method.toUpperCase()} ${url} with ${JSON.stringify(body)}`);
} else {
@ -55,12 +51,12 @@ queue.define('http', async ({
const reqOptions = {
headers: {
...(options.defaultHeaders !== false && defaultHeaders),
...(options?.defaultHeaders !== false && defaultHeaders),
...headers,
},
...defaultOptions,
...options,
...(options.timeout && { responseTimeout: options.timeout }),
...(options?.timeout && { responseTimeout: options?.timeout }),
};
if (useProxy(url)) {
@ -71,8 +67,8 @@ queue.define('http', async ({
? await bhttp[method.toLowerCase()](url, body, reqOptions)
: await bhttp[method.toLowerCase()](url, reqOptions);
if (options.stream && options.destination) {
await pipeline(res, ...(options.transforms || []), options.destination);
if (options?.stream && options?.destination) {
await pipeline(res, ...(options?.transforms || []), options?.destination);
}
const html = Buffer.isBuffer(res.body) ? res.body.toString() : null;
@ -88,12 +84,22 @@ queue.define('http', async ({
code: res.statusCode,
status: res.statusCode,
};
}, {
}
queue.on('concurrencyReached:http', () => {
logger.silly('Queueing requests');
});
queue.define('20p', handler, {
concurrency: 20,
});
async function get(url, headers, options) {
return queue.push('http', {
queue.define('1s', handler, {
interval: 1,
});
async function get(url, headers, options, queueMethod = '20p') {
return queue.push(queueMethod, {
method: 'GET',
url,
headers,
@ -101,8 +107,8 @@ async function get(url, headers, options) {
});
}
async function post(url, body, headers, options) {
return queue.push('http', {
async function post(url, body, headers, options, queueMethod = '20p') {
return queue.push(queueMethod, {
method: 'POST',
url,
body,

View File

@ -12,7 +12,7 @@ async function resolvePlace(query) {
// https://operations.osmfoundation.org/policies/nominatim/
const res = await http.get(`https://nominatim.openstreetmap.org/search/${encodeURI(query)}?format=json&accept-language=en&addressdetails=1`, {
'User-Agent': 'contact at moonloop.adult@protonmail.com',
});
}, null, '1s');
const [item] = res.body;

View File

@ -12,7 +12,7 @@ const schemaExtender = makeExtendSchemaPlugin(_build => ({
}
extend type Actor {
age: Int @requires(columns: ["birthdate"])
age: Int @requires(columns: ["date_of_birth"])
height(units:Units): String @requires(columns: ["height"])
weight(units:Units): String @requires(columns: ["weight"])
}