Compare commits
2 Commits
a586413240
...
old
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4839a3b94c | ||
|
|
d8b641e461 |
52
assets/components/container/container.vue
Normal file → Executable file
@@ -8,35 +8,40 @@
|
||||
/>
|
||||
|
||||
<transition name="slide">
|
||||
<Sidebar
|
||||
v-if="showSidebar"
|
||||
@toggle-sidebar="(state) => toggleSidebar(state)"
|
||||
@show-filters="(state) => toggleFilters(state)"
|
||||
/>
|
||||
<Sidebar v-if="showSidebar" />
|
||||
</transition>
|
||||
|
||||
<Header
|
||||
@toggle-sidebar="(state) => toggleSidebar(state)"
|
||||
@show-filters="(state) => toggleFilters(state)"
|
||||
/>
|
||||
<Header />
|
||||
|
||||
<p
|
||||
v-if="config.showDisclaimer"
|
||||
class="disclaimer"
|
||||
>{{ config.disclaimer }}</p>
|
||||
v-html="config.disclaimer"
|
||||
/>
|
||||
|
||||
<p
|
||||
v-if="config.showAnnouncement"
|
||||
class="announcement"
|
||||
v-html="config.announcement"
|
||||
/>
|
||||
|
||||
<div
|
||||
ref="content"
|
||||
class="content"
|
||||
@scroll="scroll"
|
||||
>
|
||||
<router-view @scroll="scrollToTop" />
|
||||
<RouterView @scroll="scrollToTop" />
|
||||
</div>
|
||||
|
||||
<Filters
|
||||
v-if="showFilters"
|
||||
@close="toggleFilters(false)"
|
||||
/>
|
||||
|
||||
<Settings
|
||||
v-if="showSettings"
|
||||
@close="toggleSettings(false)"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -45,6 +50,7 @@ import Warning from './warning.vue';
|
||||
import Header from '../header/header.vue';
|
||||
import Sidebar from '../sidebar/sidebar.vue';
|
||||
import Filters from '../filters/filters.vue';
|
||||
import Settings from '../settings/settings.vue';
|
||||
|
||||
function toggleSidebar(state) {
|
||||
this.showSidebar = typeof state === 'boolean' ? state : !this.showSidebar;
|
||||
@@ -55,6 +61,11 @@ function toggleFilters(state) {
|
||||
this.showSidebar = false;
|
||||
}
|
||||
|
||||
function toggleSettings(state) {
|
||||
this.showSettings = state;
|
||||
this.showSidebar = false;
|
||||
}
|
||||
|
||||
async function setConsent(consent, includeQueer) {
|
||||
if (consent) {
|
||||
this.showWarning = false;
|
||||
@@ -88,6 +99,9 @@ function scrollToTop() {
|
||||
function mounted() {
|
||||
document.addEventListener('click', this.blur);
|
||||
window.addEventListener('resize', this.resize);
|
||||
|
||||
this.events.on('toggleSettings', this.toggleSettings);
|
||||
this.events.on('toggleSidebar', this.toggleSidebar);
|
||||
}
|
||||
|
||||
function beforeUnmount() {
|
||||
@@ -101,12 +115,15 @@ export default {
|
||||
Sidebar,
|
||||
Warning,
|
||||
Filters,
|
||||
Settings,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
showSidebar: false,
|
||||
showWarning: localStorage.getItem('consent') !== window.env.sessionId,
|
||||
showFilters: false,
|
||||
showSettings: false,
|
||||
selected: null,
|
||||
};
|
||||
},
|
||||
mounted,
|
||||
@@ -114,6 +131,7 @@ export default {
|
||||
methods: {
|
||||
toggleSidebar,
|
||||
toggleFilters,
|
||||
toggleSettings,
|
||||
setConsent,
|
||||
blur,
|
||||
resize,
|
||||
@@ -183,13 +201,21 @@ export default {
|
||||
</style>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.disclaimer {
|
||||
.disclaimer,
|
||||
.announcement {
|
||||
padding: .5rem 1rem;
|
||||
margin: 0;
|
||||
color: var(--text-light);
|
||||
background: var(--warn);
|
||||
font-weight: bold;
|
||||
box-shadow: inset 0 0 3px var(--darken-weak);
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.disclaimer {
|
||||
background: var(--warn);
|
||||
}
|
||||
|
||||
.announcement {
|
||||
background: var(--notice);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -108,7 +108,6 @@
|
||||
:fetch-releases="fetchEntity"
|
||||
:items-total="totalCount"
|
||||
:items-per-page="limit"
|
||||
:available-tags="entity.tags"
|
||||
/>
|
||||
|
||||
<div class="releases">
|
||||
|
||||
@@ -102,8 +102,6 @@ export default {
|
||||
}
|
||||
|
||||
.name {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
color: var(--text-light);
|
||||
font-size: 1.25rem;
|
||||
font-weight: bold;
|
||||
|
||||
@@ -28,7 +28,7 @@ export default {
|
||||
};
|
||||
},
|
||||
beforeMount() {
|
||||
this.svg = require(`../../img/icons/${this.icon}.svg`).default; // eslint-disable-line global-require, import/no-dynamic-require
|
||||
this.svg = require(`../../img/icons/${this.icon}.svg`).default;
|
||||
},
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -11,31 +11,16 @@
|
||||
class="empty"
|
||||
>No results for "{{ $route.query.query }}"</span>
|
||||
|
||||
<template v-else>
|
||||
<h2 class="heading">Popular</h2>
|
||||
|
||||
<div
|
||||
class="entity-tiles"
|
||||
>
|
||||
<Entity
|
||||
v-for="entity in popularEntities"
|
||||
:key="entity.parent ? `entity-tile-${entity.parent.slug}-${entity.slug}` : `entity-tile-${entity.slug}`"
|
||||
:entity="entity"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<h2 class="heading">All networks</h2>
|
||||
|
||||
<div
|
||||
class="entity-tiles"
|
||||
>
|
||||
<Entity
|
||||
v-for="entity in entities"
|
||||
:key="entity.parent ? `entity-tile-${entity.parent.slug}-${entity.slug}` : `entity-tile-${entity.slug}`"
|
||||
:entity="entity"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
<div
|
||||
v-else
|
||||
class="entity-tiles"
|
||||
>
|
||||
<Entity
|
||||
v-for="entity in entities"
|
||||
:key="entity.parent ? `entity-tile-${entity.parent.slug}-${entity.slug}` : `entity-tile-${entity.slug}`"
|
||||
:entity="entity"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Footer />
|
||||
@@ -73,45 +58,6 @@ async function searchEntities() {
|
||||
this.done = true;
|
||||
}
|
||||
|
||||
function popularEntities() {
|
||||
const entitiesBySlug = Object.fromEntries(this.entities.map((entity) => [entity.slug, entity]));
|
||||
|
||||
return [
|
||||
'21sextury',
|
||||
'amateurallure',
|
||||
'analvids',
|
||||
'bamvisions',
|
||||
'bang',
|
||||
'bangbros',
|
||||
'blowpass',
|
||||
'brazzers',
|
||||
'burningangel',
|
||||
'digitalplayground',
|
||||
'dogfartnetwork',
|
||||
'dorcel',
|
||||
'elegantangel',
|
||||
'evilangel',
|
||||
'fakehub',
|
||||
'girlsway',
|
||||
'hookuphotshot',
|
||||
'hussiepass',
|
||||
'insex',
|
||||
'julesjordan',
|
||||
'kellymadison',
|
||||
'kink',
|
||||
'mofos',
|
||||
'naughtyamerica',
|
||||
'newsensations',
|
||||
'pervcity',
|
||||
'pornpros',
|
||||
'private',
|
||||
'realitykings',
|
||||
'twistys',
|
||||
'vixen',
|
||||
'xempire',
|
||||
].map((slug) => entitiesBySlug[slug]).filter(Boolean);
|
||||
}
|
||||
|
||||
async function mounted() {
|
||||
this.pageTitle = 'Channels';
|
||||
|
||||
@@ -136,7 +82,6 @@ export default {
|
||||
},
|
||||
computed: {
|
||||
channelCount,
|
||||
popularEntities,
|
||||
},
|
||||
watch: {
|
||||
$route: fetchEntities,
|
||||
@@ -185,10 +130,6 @@ export default {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.heading {
|
||||
margin: 1rem 0 0 0;
|
||||
}
|
||||
|
||||
@media(max-width: $breakpoint2) {
|
||||
.entity-tiles {
|
||||
grid-gap: .5rem;
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div class="media-container">
|
||||
<div
|
||||
class="media"
|
||||
:class="{ center: (release.photos?.length || 0) + (release.scenesPhotos?.length || 0) < 2, preview: !me }"
|
||||
:class="{ center: release.photos.length < 2, preview: !me }"
|
||||
>
|
||||
<div
|
||||
v-if="release.trailer || release.teaser"
|
||||
@@ -71,28 +71,24 @@
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<template v-if="release.covers?.length > 0">
|
||||
<div
|
||||
<template v-if="release.covers && release.covers.length > 0">
|
||||
<a
|
||||
v-for="cover in release.covers"
|
||||
:key="`cover-${cover.id}`"
|
||||
class="item-container"
|
||||
:href="getPath(cover)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
<a
|
||||
:href="getPath(cover)"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
<img
|
||||
:src="getPath(cover, 'thumbnail')"
|
||||
:style="{ 'background-image': getBgPath(cover, 'lazy') }"
|
||||
:width="cover.thumbnailWidth"
|
||||
:height="cover.thumbnailHeight"
|
||||
class="item cover"
|
||||
loading="lazy"
|
||||
@load="$emit('load', $event)"
|
||||
>
|
||||
<img
|
||||
:src="getPath(cover, 'thumbnail')"
|
||||
:style="{ 'background-image': getBgPath(cover, 'lazy') }"
|
||||
:width="cover.thumbnailWidth"
|
||||
:height="cover.thumbnailHeight"
|
||||
class="item cover"
|
||||
loading="lazy"
|
||||
@load="$emit('load', $event)"
|
||||
>
|
||||
</a>
|
||||
</div>
|
||||
</a>
|
||||
</template>
|
||||
|
||||
<div
|
||||
@@ -168,8 +164,8 @@ function poster() {
|
||||
function photos() {
|
||||
const clips = this.release.clips || [];
|
||||
const clipPostersById = clips.reduce((acc, clip) => ({ ...acc, [clip.poster.id]: clip.poster }), {});
|
||||
const uniqueClipPosters = Array.from(new Set(clips.map((clip) => clip.poster.id) || [])).map((posterId) => clipPostersById[posterId]);
|
||||
const photosWithClipPosters = (this.release.photos || []).concat(this.release.scenesPhotos || []).concat(uniqueClipPosters);
|
||||
const uniqueClipPosters = Array.from(new Set(clips.map(clip => clip.poster.id) || [])).map(posterId => clipPostersById[posterId]);
|
||||
const photosWithClipPosters = (this.release.photos || []).concat(uniqueClipPosters);
|
||||
|
||||
if (this.release.trailer || (this.release.teaser && this.release.teaser.mime !== 'image/gif')) {
|
||||
// poster will be on trailer video
|
||||
|
||||
@@ -3,6 +3,12 @@
|
||||
<div class="content-inner">
|
||||
<SearchBar :placeholder="`Search ${totalCount} movies`" />
|
||||
|
||||
<TagFilter
|
||||
class="filters-filter"
|
||||
:filter="filter"
|
||||
:available-tags="availableTags"
|
||||
/>
|
||||
|
||||
<div
|
||||
ref="tiles"
|
||||
class="tiles"
|
||||
@@ -30,6 +36,7 @@
|
||||
import MovieTile from './movie-tile.vue';
|
||||
import SearchBar from '../search/bar.vue';
|
||||
import Pagination from '../pagination/pagination.vue';
|
||||
import TagFilter from '../filters/tag-filter.vue';
|
||||
|
||||
async function fetchMovies() {
|
||||
if (this.$route.query.query) {
|
||||
@@ -73,6 +80,7 @@ export default {
|
||||
MovieTile,
|
||||
SearchBar,
|
||||
Pagination,
|
||||
TagFilter,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
||||
@@ -21,14 +21,14 @@
|
||||
<Details :release="release" />
|
||||
|
||||
<button
|
||||
v-if="release.photos?.length > 0 || release.scenesPhotos?.length > 0"
|
||||
v-if="release.photos.length > 0"
|
||||
class="album-toggle"
|
||||
@click="$router.push({ hash: '#album' })"
|
||||
><Icon icon="grid3" />View album</button>
|
||||
|
||||
<Album
|
||||
v-if="showAlbum"
|
||||
:items="[release.poster, ...(release.photos || []), ...(release.scenesPhotos || [])]"
|
||||
:items="[release.poster, ...release.photos]"
|
||||
:title="release.title"
|
||||
:path="config.media.mediaPath"
|
||||
@close="$router.replace({ hash: undefined })"
|
||||
@@ -79,23 +79,22 @@
|
||||
/>
|
||||
|
||||
<div
|
||||
v-if="release.movies?.length > 0 || release.series?.length > 0"
|
||||
v-if="release.movies && release.movies.length > 0"
|
||||
class="row"
|
||||
>
|
||||
<span class="row-label">Part of</span>
|
||||
|
||||
<div class="movies">
|
||||
<router-link
|
||||
v-for="movie in [...release.movies, ...release.series]"
|
||||
v-for="movie in release.movies"
|
||||
:key="`movie-${movie.id}`"
|
||||
:to="{ name: movie.type || 'movie', params: { releaseId: movie.id, releaseSlug: movie.slug } }"
|
||||
:to="{ name: 'movie', params: { releaseId: movie.id, releaseSlug: movie.slug } }"
|
||||
class="movie"
|
||||
>
|
||||
<span class="movie-title">{{ movie.title }}</span>
|
||||
|
||||
<img
|
||||
v-if="movie.covers.length > 0 || movie.poster"
|
||||
:src="getPath(movie.covers[0] || movie.poster, 'thumbnail')"
|
||||
v-if="movie.covers.length > 0"
|
||||
:src="getPath(movie.covers[0], 'thumbnail')"
|
||||
class="movie-cover"
|
||||
>
|
||||
</router-link>
|
||||
@@ -203,19 +202,6 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="release.qualities"
|
||||
class="row"
|
||||
>
|
||||
<span class="row-label">Available qualities</span>
|
||||
|
||||
<span
|
||||
v-for="quality in release.qualities"
|
||||
:key="quality"
|
||||
class="quality"
|
||||
>{{ quality }}</span>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="release.comment"
|
||||
class="row"
|
||||
@@ -257,10 +243,6 @@ async function fetchRelease(scroll = true) {
|
||||
this.release = await this.$store.dispatch('fetchMovieById', this.$route.params.releaseId);
|
||||
}
|
||||
|
||||
if (this.$route.name === 'serie') {
|
||||
this.release = await this.$store.dispatch('fetchSerieById', this.$route.params.releaseId);
|
||||
}
|
||||
|
||||
if (scroll && this.$refs.content) {
|
||||
this.$refs.content.scrollTop = 0;
|
||||
}
|
||||
@@ -300,7 +282,7 @@ function pageTitle() {
|
||||
}
|
||||
|
||||
function showAlbum() {
|
||||
return (this.release.photos?.length > 0 || this.release.scenesPhotos?.length > 0) && this.$route.hash === '#album';
|
||||
return this.release.photos?.length > 0 && this.$route.hash === '#album';
|
||||
}
|
||||
|
||||
export default {
|
||||
@@ -483,16 +465,6 @@ export default {
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.quality {
|
||||
&::after {
|
||||
content: 'p, ';
|
||||
}
|
||||
|
||||
&:last-child::after {
|
||||
content: 'p',
|
||||
}
|
||||
}
|
||||
|
||||
.releases {
|
||||
margin: 0 0 .5rem 0;
|
||||
}
|
||||
|
||||
@@ -87,6 +87,7 @@ const tagSlugsByCategory = {
|
||||
'titty-fucking',
|
||||
'fisting',
|
||||
'anal-fisting',
|
||||
'fisting-dp',
|
||||
],
|
||||
group: [
|
||||
'mfm',
|
||||
@@ -107,31 +108,6 @@ const tagSlugsByCategory = {
|
||||
'bukkake',
|
||||
'fake-cum',
|
||||
],
|
||||
roleplay: [
|
||||
'family',
|
||||
'parody',
|
||||
'schoolgirl',
|
||||
'nurse',
|
||||
'maid',
|
||||
'nun',
|
||||
],
|
||||
extreme: [
|
||||
'dp',
|
||||
'airtight',
|
||||
'dap',
|
||||
'dvp',
|
||||
'triple-penetration',
|
||||
'tap',
|
||||
'tvp',
|
||||
],
|
||||
fetish: [
|
||||
'bdsm',
|
||||
'femdom',
|
||||
'bondage',
|
||||
'free-use',
|
||||
'latex',
|
||||
'blindfold',
|
||||
],
|
||||
toys: [
|
||||
'toys',
|
||||
'toy-anal',
|
||||
@@ -142,6 +118,32 @@ const tagSlugsByCategory = {
|
||||
'double-dildo-anal',
|
||||
'double-dildo-dp',
|
||||
],
|
||||
roleplay: [
|
||||
'family',
|
||||
'parody',
|
||||
'schoolgirl',
|
||||
'nurse',
|
||||
'maid',
|
||||
'nun',
|
||||
],
|
||||
fetish: [
|
||||
'bdsm',
|
||||
'femdom',
|
||||
'bondage',
|
||||
'free-use',
|
||||
'latex',
|
||||
'blindfold',
|
||||
],
|
||||
extreme: [
|
||||
'dp',
|
||||
'airtight',
|
||||
'dap',
|
||||
'dvp',
|
||||
'da-tp',
|
||||
'dv-tp',
|
||||
'tap',
|
||||
'tvp',
|
||||
],
|
||||
misc: [
|
||||
'gaping',
|
||||
'squirting',
|
||||
|
||||
@@ -12,7 +12,6 @@ export default {
|
||||
selectableTags: [
|
||||
'airtight',
|
||||
'anal',
|
||||
'bdsm',
|
||||
'blowbang',
|
||||
'blowjob',
|
||||
'creampie',
|
||||
|
||||
@@ -65,23 +65,19 @@ function curateActor(actor, release) {
|
||||
return curatedActor;
|
||||
}
|
||||
|
||||
function curateRelease(release, type = 'scene') {
|
||||
function curateRelease(release) {
|
||||
const curatedRelease = {
|
||||
...release,
|
||||
type: release.type || type,
|
||||
actors: [],
|
||||
poster: release.poster && release.poster.media,
|
||||
tags: release.tags ? release.tags.map((tag) => tag.tag || tag) : [],
|
||||
};
|
||||
|
||||
curatedRelease.scenes = release.scenes?.filter(Boolean).map(({ scene }) => curateRelease(scene, 'scene')) || [];
|
||||
curatedRelease.movies = release.movies?.filter(Boolean).map(({ movie }) => curateRelease(movie, 'movie')) || [];
|
||||
curatedRelease.series = release.series?.filter(Boolean).map(({ serie }) => curateRelease(serie, 'serie')) || [];
|
||||
curatedRelease.chapters = release.chapters?.filter(Boolean).map((chapter) => curateRelease(chapter)) || [];
|
||||
curatedRelease.photos = release.photos?.filter(Boolean).map((photo) => photo.media || photo) || [];
|
||||
curatedRelease.scenesPhotos = release.scenesPhotos?.filter(Boolean).map((photo) => photo.media || photo) || [];
|
||||
curatedRelease.covers = release.covers?.filter(Boolean).map(({ media }) => media) || [];
|
||||
|
||||
if (release.scenes) curatedRelease.scenes = release.scenes.filter(Boolean).map(({ scene }) => curateRelease(scene));
|
||||
if (release.movies) curatedRelease.movies = release.movies.filter(Boolean).map(({ movie }) => curateRelease(movie));
|
||||
if (release.chapters) curatedRelease.chapters = release.chapters.filter(Boolean).map((chapter) => curateRelease(chapter));
|
||||
if (release.photos) curatedRelease.photos = release.photos.filter(Boolean).map((photo) => photo.media || photo);
|
||||
if (release.covers) curatedRelease.covers = release.covers.filter(Boolean).map(({ media }) => media);
|
||||
if (release.trailer) curatedRelease.trailer = release.trailer.media;
|
||||
if (release.teaser) curatedRelease.teaser = release.teaser.media;
|
||||
if (release.actors) curatedRelease.actors = release.actors.filter(Boolean).map((actor) => curateActor(actor.actor || actor, curatedRelease));
|
||||
@@ -109,7 +105,6 @@ function curateEntity(entity, parent, releases) {
|
||||
};
|
||||
|
||||
if (entity.tags) curatedEntity.tags = entity.tags.map(({ tag }) => tag);
|
||||
if (entity.sceneTags) curatedEntity.sceneTags = entity.sceneTags;
|
||||
|
||||
if (entity.children) {
|
||||
if (entity.children.nodes) {
|
||||
|
||||
@@ -41,11 +41,6 @@ function initEntitiesActions(store, router) {
|
||||
slug
|
||||
}
|
||||
}
|
||||
sceneTags {
|
||||
id
|
||||
name
|
||||
slug
|
||||
}
|
||||
children: childEntitiesConnection(
|
||||
orderBy: [PRIORITY_DESC, NAME_ASC],
|
||||
filter: {
|
||||
@@ -101,7 +96,7 @@ function initEntitiesActions(store, router) {
|
||||
}
|
||||
}
|
||||
]
|
||||
effectiveDate: {
|
||||
date: {
|
||||
lessThan: $before,
|
||||
greaterThan: $after
|
||||
}
|
||||
|
||||
@@ -367,7 +367,6 @@ const releaseFields = `
|
||||
date
|
||||
datePrecision
|
||||
slug
|
||||
qualities
|
||||
shootId
|
||||
productionDate
|
||||
comment
|
||||
@@ -443,29 +442,6 @@ const releasesFragment = `
|
||||
}
|
||||
`;
|
||||
|
||||
const mediaFields = `
|
||||
id
|
||||
index
|
||||
path
|
||||
thumbnail
|
||||
lazy
|
||||
isS3
|
||||
comment
|
||||
sfw: sfwMedia {
|
||||
id
|
||||
thumbnail
|
||||
lazy
|
||||
path
|
||||
comment
|
||||
}
|
||||
`;
|
||||
|
||||
const mediaFragment = `
|
||||
media {
|
||||
${mediaFields}
|
||||
}
|
||||
`;
|
||||
|
||||
const releaseFragment = `
|
||||
release(id: $releaseId) {
|
||||
id
|
||||
@@ -476,7 +452,6 @@ const releaseFragment = `
|
||||
duration
|
||||
createdAt
|
||||
shootId
|
||||
qualities
|
||||
productionDate
|
||||
createdBatchId
|
||||
productionLocation
|
||||
@@ -561,19 +536,6 @@ const releaseFragment = `
|
||||
}
|
||||
}
|
||||
}
|
||||
series: seriesScenesBySceneId {
|
||||
serie {
|
||||
id
|
||||
title
|
||||
slug
|
||||
covers: seriesCoversBySerieId(orderBy: MEDIA_BY_MEDIA_ID__INDEX_ASC) {
|
||||
${mediaFragment}
|
||||
}
|
||||
poster: seriesPosterBySerieId {
|
||||
${mediaFragment}
|
||||
}
|
||||
}
|
||||
}
|
||||
isFavorited
|
||||
isStashed(includeFavorites: false)
|
||||
stashes: stashesScenesBySceneId(
|
||||
@@ -662,8 +624,6 @@ export {
|
||||
actorFields,
|
||||
actorStashesFields,
|
||||
campaignsFragment,
|
||||
mediaFields,
|
||||
mediaFragment,
|
||||
movieFields,
|
||||
releaseActorsFragment,
|
||||
releaseFields,
|
||||
|
||||
@@ -7,22 +7,22 @@ const dateRanges = {
|
||||
latest: () => ({
|
||||
after: '1900-01-01',
|
||||
before: dayjs.utc().toDate(),
|
||||
orderBy: ['EFFECTIVE_DATE_DESC'],
|
||||
orderBy: ['DATE_DESC'],
|
||||
}),
|
||||
upcoming: () => ({
|
||||
after: dayjs.utc().toDate(),
|
||||
before: '2100-01-01',
|
||||
orderBy: ['EFFECTIVE_DATE_DESC'],
|
||||
orderBy: ['DATE_DESC'],
|
||||
}),
|
||||
new: () => ({
|
||||
after: '1900-01-01 00:00:00',
|
||||
before: '2100-01-01',
|
||||
orderBy: ['CREATED_AT_DESC', 'EFFECTIVE_DATE_ASC'],
|
||||
orderBy: ['CREATED_AT_DESC', 'DATE_ASC'],
|
||||
}),
|
||||
all: () => ({
|
||||
after: '1900-01-01',
|
||||
before: '2100-01-01',
|
||||
orderBy: ['EFFECTIVE_DATE_DESC'],
|
||||
orderBy: ['DATE_DESC'],
|
||||
}),
|
||||
};
|
||||
|
||||
|
||||
@@ -4,8 +4,6 @@ import {
|
||||
releaseFragment,
|
||||
releaseFields,
|
||||
movieFields,
|
||||
mediaFragment,
|
||||
mediaFields,
|
||||
} from '../fragments';
|
||||
import { curateRelease } from '../curate';
|
||||
import getDateRange from '../get-date-range';
|
||||
@@ -143,16 +141,16 @@ function initReleasesActions(store, router) {
|
||||
};
|
||||
}
|
||||
|
||||
async function fetchCollectionById({ _commit }, movieId, type = 'movie') {
|
||||
async function fetchMovieById({ _commit }, movieId) {
|
||||
// const release = await get(`/releases/${releaseId}`);
|
||||
|
||||
const result = await graphql(`
|
||||
const { movie } = await graphql(`
|
||||
query Movie(
|
||||
$movieId: Int!
|
||||
$hasAuth: Boolean!
|
||||
$userId: Int
|
||||
) {
|
||||
${type}(id: $movieId) {
|
||||
movie(id: $movieId) {
|
||||
id
|
||||
title
|
||||
description
|
||||
@@ -184,7 +182,7 @@ function initReleasesActions(store, router) {
|
||||
isS3
|
||||
}
|
||||
}
|
||||
poster: ${type === 'series' ? 'seriesPosterBySerieId' : 'moviesPoster'} {
|
||||
poster: moviesPoster {
|
||||
media {
|
||||
id
|
||||
path
|
||||
@@ -197,7 +195,7 @@ function initReleasesActions(store, router) {
|
||||
isS3
|
||||
}
|
||||
}
|
||||
covers: ${type === 'series' ? 'seriesCoversBySerieId' : 'moviesCovers'}(orderBy: MEDIA_BY_MEDIA_ID__INDEX_ASC) {
|
||||
covers: moviesCovers(orderBy: MEDIA_BY_MEDIA_ID__INDEX_ASC) {
|
||||
media {
|
||||
id
|
||||
path
|
||||
@@ -210,14 +208,14 @@ function initReleasesActions(store, router) {
|
||||
isS3
|
||||
}
|
||||
}
|
||||
trailer: ${type === 'series' ? 'seriesTrailerBySerieId' : 'moviesTrailer'} {
|
||||
trailer: moviesTrailer {
|
||||
media {
|
||||
id
|
||||
path
|
||||
isS3
|
||||
}
|
||||
}
|
||||
scenes: ${type === 'series' ? 'seriesScenesBySerieId' : 'moviesScenes'} {
|
||||
scenes: moviesScenes {
|
||||
scene {
|
||||
${releaseFields}
|
||||
}
|
||||
@@ -227,11 +225,25 @@ function initReleasesActions(store, router) {
|
||||
slug
|
||||
name
|
||||
}
|
||||
photos: ${type === 'series' ? 'seriesPhotosBySerieId' : 'moviesPhotos'} {
|
||||
${mediaFragment}
|
||||
}
|
||||
scenesPhotos {
|
||||
${mediaFields}
|
||||
photos {
|
||||
id
|
||||
index
|
||||
path
|
||||
thumbnail
|
||||
lazy
|
||||
width
|
||||
height
|
||||
thumbnailWidth
|
||||
thumbnailHeight
|
||||
isS3
|
||||
comment
|
||||
sfw: sfwMedia {
|
||||
id
|
||||
thumbnail
|
||||
lazy
|
||||
path
|
||||
comment
|
||||
}
|
||||
}
|
||||
entity {
|
||||
id
|
||||
@@ -247,7 +259,7 @@ function initReleasesActions(store, router) {
|
||||
hasLogo
|
||||
}
|
||||
}
|
||||
stashes: ${type === 'series' ? 'stashesSeriesBySerieId' : 'stashesMovies'}(
|
||||
stashes: stashesMovies(
|
||||
filter: {
|
||||
stash: {
|
||||
userId: {
|
||||
@@ -271,20 +283,12 @@ function initReleasesActions(store, router) {
|
||||
userId: store.state.auth.user?.id,
|
||||
});
|
||||
|
||||
if (!result[type]) {
|
||||
if (!movie) {
|
||||
router.replace('/not-found');
|
||||
return null;
|
||||
}
|
||||
|
||||
return curateRelease(result[type]);
|
||||
}
|
||||
|
||||
async function fetchMovieById(context, movieId) {
|
||||
return fetchCollectionById(context, movieId, 'movie');
|
||||
}
|
||||
|
||||
async function fetchSerieById(context, serieId) {
|
||||
return fetchCollectionById(context, serieId, 'series');
|
||||
return curateRelease(movie);
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -292,7 +296,6 @@ function initReleasesActions(store, router) {
|
||||
fetchReleaseById,
|
||||
fetchMovies,
|
||||
fetchMovieById,
|
||||
fetchSerieById,
|
||||
searchMovies,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -71,11 +71,6 @@ const routes = [
|
||||
component: Release,
|
||||
name: 'movie',
|
||||
},
|
||||
{
|
||||
path: '/serie/:releaseId/:releaseSlug?',
|
||||
component: Release,
|
||||
name: 'serie',
|
||||
},
|
||||
{
|
||||
path: '/actor/:actorId/:actorSlug',
|
||||
name: 'actor',
|
||||
|
||||
@@ -89,10 +89,6 @@ module.exports = {
|
||||
'uksinners',
|
||||
// mindgeek
|
||||
'pornhub',
|
||||
// insex
|
||||
'paintoy',
|
||||
'aganmedon',
|
||||
'sensualpain',
|
||||
],
|
||||
networks: [
|
||||
// dummy network for testing
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
exports.up = async (knex) => knex.raw(`
|
||||
CREATE OR REPLACE FUNCTION entities_scene_total(entity entities) RETURNS bigint AS $$
|
||||
CREATE OR REPLACE FUNCTION entities_scene_total(entity entities) RETURNS integer AS $$
|
||||
SELECT COUNT(id)
|
||||
FROM releases
|
||||
WHERE releases.entity_id = entity.id;
|
||||
|
||||
8
migrations/20220209010315_movies_tags.js
Normal file
@@ -0,0 +1,8 @@
|
||||
exports.up = async (knex) => knex.raw(`
|
||||
CREATE VIEW movies_tagged AS
|
||||
SELECT * FROM movies;
|
||||
`);
|
||||
|
||||
exports.down = async (knex) => knex.raw(`
|
||||
DROP VIEW IF EXISTS movies_tagged;
|
||||
`);
|
||||
@@ -1,23 +0,0 @@
|
||||
exports.up = async (knex) => knex.raw(`
|
||||
CREATE FUNCTION entities_scene_tags(entity entities, selectable_tags text[]) RETURNS SETOF tags AS $$
|
||||
SELECT tags.*
|
||||
FROM releases
|
||||
LEFT JOIN
|
||||
releases_tags ON releases_tags.release_id = releases.id
|
||||
LEFT JOIN
|
||||
tags ON tags.id = releases_tags.tag_id
|
||||
WHERE
|
||||
releases.entity_id = entity.id
|
||||
AND
|
||||
CASE WHEN array_length(selectable_tags, 1) IS NOT NULL
|
||||
THEN tags.slug = ANY(selectable_tags)
|
||||
ELSE true
|
||||
END
|
||||
GROUP BY tags.id
|
||||
ORDER BY tags.name;
|
||||
$$ LANGUAGE SQL STABLE;
|
||||
`);
|
||||
|
||||
exports.down = async (knex) => knex.raw(`
|
||||
DROP FUNCTION IF EXISTS entities_scene_tags;
|
||||
`);
|
||||
@@ -1,215 +0,0 @@
|
||||
const config = require('config');
|
||||
|
||||
exports.up = async (knex) => Promise.resolve()
|
||||
.then(() => knex.schema.createTable('series', (table) => {
|
||||
table.increments('id', 16);
|
||||
|
||||
table.integer('entity_id', 12)
|
||||
.references('id')
|
||||
.inTable('entities')
|
||||
.notNullable();
|
||||
|
||||
table.integer('studio_id', 12)
|
||||
.references('id')
|
||||
.inTable('entities');
|
||||
|
||||
table.text('entry_id');
|
||||
table.unique(['entity_id', 'entry_id']);
|
||||
|
||||
table.text('url', 1000);
|
||||
table.text('title');
|
||||
table.text('slug');
|
||||
|
||||
table.timestamp('date');
|
||||
table.index('date');
|
||||
|
||||
table.enum('date_precision', ['year', 'month', 'week', 'day', 'hour', 'minute', 'second'])
|
||||
.defaultTo('day');
|
||||
|
||||
table.text('description');
|
||||
|
||||
table.boolean('deep');
|
||||
table.text('deep_url', 1000);
|
||||
|
||||
table.text('comment');
|
||||
|
||||
table.integer('created_batch_id', 12)
|
||||
.references('id')
|
||||
.inTable('batches')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('updated_batch_id', 12)
|
||||
.references('id')
|
||||
.inTable('batches')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.datetime('created_at')
|
||||
.defaultTo(knex.fn.now());
|
||||
}))
|
||||
.then(() => knex.schema.createTable('series_scenes', (table) => {
|
||||
table.integer('serie_id', 16)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('series')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('scene_id', 16)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('releases')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['serie_id', 'scene_id']);
|
||||
|
||||
table.datetime('created_at')
|
||||
.defaultTo(knex.fn.now());
|
||||
}))
|
||||
.then(() => knex.schema.createTable('series_trailers', (table) => {
|
||||
table.integer('serie_id', 16)
|
||||
.unique()
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('series')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.text('media_id', 21)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('media');
|
||||
}))
|
||||
.then(() => knex.schema.createTable('series_posters', (table) => {
|
||||
table.integer('serie_id', 16)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('series')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.text('media_id', 21)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('media')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique('serie_id');
|
||||
}))
|
||||
.then(() => knex.schema.createTable('series_covers', (table) => {
|
||||
table.integer('serie_id', 16)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('series')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.text('media_id', 21)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('media');
|
||||
|
||||
table.unique(['serie_id', 'media_id']);
|
||||
}))
|
||||
.then(() => knex.schema.createTable('series_search', (table) => {
|
||||
table.integer('serie_id', 16)
|
||||
.references('id')
|
||||
.inTable('series')
|
||||
.onDelete('cascade');
|
||||
}))
|
||||
.then(() => knex.schema.createTable('stashes_series', (table) => {
|
||||
table.integer('stash_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('stashes')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.integer('serie_id')
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('series')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.unique(['stash_id', 'serie_id']);
|
||||
|
||||
table.string('comment');
|
||||
|
||||
table.datetime('created_at')
|
||||
.notNullable()
|
||||
.defaultTo(knex.fn.now());
|
||||
}))
|
||||
.then(() => knex.raw(`
|
||||
ALTER TABLE series_search ADD COLUMN document tsvector;
|
||||
|
||||
CREATE UNIQUE INDEX series_search_unique ON series_search (serie_id);
|
||||
CREATE INDEX series_search_index ON series_search USING GIN (document);
|
||||
|
||||
CREATE FUNCTION series_actors(serie series) RETURNS SETOF actors AS $$
|
||||
SELECT actors.*
|
||||
FROM series_scenes
|
||||
LEFT JOIN
|
||||
releases ON releases.id = series_scenes.scene_id
|
||||
LEFT JOIN
|
||||
releases_actors ON releases_actors.release_id = releases.id
|
||||
LEFT JOIN
|
||||
actors ON actors.id = releases_actors.actor_id
|
||||
WHERE series_scenes.serie_id = serie.id
|
||||
AND actors.id IS NOT NULL
|
||||
GROUP BY actors.id
|
||||
ORDER BY actors.name, actors.gender
|
||||
$$ LANGUAGE SQL STABLE;
|
||||
|
||||
CREATE FUNCTION series_tags(serie series) RETURNS SETOF tags AS $$
|
||||
SELECT tags.*
|
||||
FROM series_scenes
|
||||
LEFT JOIN
|
||||
releases ON releases.id = series_scenes.scene_id
|
||||
LEFT JOIN
|
||||
releases_tags ON releases_tags.release_id = releases.id
|
||||
LEFT JOIN
|
||||
tags ON tags.id = releases_tags.tag_id
|
||||
WHERE series_scenes.serie_id = serie.id
|
||||
AND tags.id IS NOT NULL
|
||||
GROUP BY tags.id
|
||||
ORDER BY tags.priority DESC
|
||||
$$ LANGUAGE SQL STABLE;
|
||||
|
||||
CREATE FUNCTION series_photos(serie series) RETURNS SETOF media AS $$
|
||||
SELECT media.*
|
||||
FROM series_scenes
|
||||
LEFT JOIN
|
||||
releases ON releases.id = series_scenes.scene_id
|
||||
INNER JOIN
|
||||
releases_photos ON releases_photos.release_id = releases.id
|
||||
LEFT JOIN
|
||||
media ON media.id = releases_photos.media_id
|
||||
WHERE series_scenes.serie_id = serie.id
|
||||
GROUP BY media.id
|
||||
ORDER BY media.index ASC
|
||||
$$ LANGUAGE SQL STABLE;
|
||||
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA public TO :visitor;
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO :visitor;
|
||||
|
||||
ALTER TABLE stashes_series ENABLE ROW LEVEL SECURITY;
|
||||
|
||||
CREATE POLICY stashes_policy ON stashes_series
|
||||
USING (EXISTS (
|
||||
SELECT *
|
||||
FROM stashes
|
||||
WHERE stashes.id = stashes_series.stash_id
|
||||
AND (stashes.user_id = current_user_id() OR stashes.public)
|
||||
));
|
||||
`, {
|
||||
visitor: knex.raw(config.database.query.user),
|
||||
}));
|
||||
|
||||
exports.down = async (knex) => Promise.resolve()
|
||||
.then(() => knex.raw(`
|
||||
DROP FUNCTION IF EXISTS series_actors;
|
||||
DROP FUNCTION IF EXISTS series_tags;
|
||||
DROP FUNCTION IF EXISTS series_photos;
|
||||
|
||||
DROP TABLE IF EXISTS stashes_series CASCADE;
|
||||
DROP TABLE IF EXISTS series_scenes CASCADE;
|
||||
DROP TABLE IF EXISTS series_trailers CASCADE;
|
||||
DROP TABLE IF EXISTS series_posters CASCADE;
|
||||
DROP TABLE IF EXISTS series_covers CASCADE;
|
||||
DROP TABLE IF EXISTS series_search CASCADE;
|
||||
DROP TABLE IF EXISTS series CASCADE;
|
||||
`));
|
||||
@@ -1,49 +0,0 @@
|
||||
const config = require('config');
|
||||
|
||||
exports.up = async (knex) => Promise.resolve()
|
||||
.then(() => knex.raw(`
|
||||
ALTER FUNCTION movies_photos(movie movies) RENAME TO movies_scenes_photos;
|
||||
ALTER FUNCTION series_photos(serie series) RENAME TO series_scenes_photos;
|
||||
`))
|
||||
.then(() => knex.schema.createTable('movies_photos', (table) => {
|
||||
table.integer('movie_id', 16)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('movies')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.text('media_id', 21)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('media');
|
||||
|
||||
table.unique(['movie_id', 'media_id']);
|
||||
}))
|
||||
.then(() => knex.schema.createTable('series_photos', (table) => {
|
||||
table.integer('serie_id', 16)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('series')
|
||||
.onDelete('cascade');
|
||||
|
||||
table.text('media_id', 21)
|
||||
.notNullable()
|
||||
.references('id')
|
||||
.inTable('media');
|
||||
|
||||
table.unique(['serie_id', 'media_id']);
|
||||
}))
|
||||
.then(() => knex.raw(`
|
||||
GRANT ALL ON ALL TABLES IN SCHEMA public TO :visitor;
|
||||
GRANT USAGE, SELECT ON ALL SEQUENCES IN SCHEMA public TO :visitor;
|
||||
`, {
|
||||
visitor: knex.raw(config.database.query.user),
|
||||
}));
|
||||
|
||||
exports.down = async (knex) => knex.raw(`
|
||||
DROP TABLE IF EXISTS movies_photos CASCADE;
|
||||
DROP TABLE IF EXISTS series_photos CASCADE;
|
||||
|
||||
ALTER FUNCTION movies_scenes_photos(movie movies) RENAME TO movies_photos;
|
||||
ALTER FUNCTION series_scenes_photos(serie series) RENAME TO series_photos;
|
||||
`);
|
||||
@@ -1,25 +0,0 @@
|
||||
exports.up = async (knex) => knex.raw(`
|
||||
CREATE MATERIALIZED VIEW entities_stats
|
||||
AS
|
||||
WITH RECURSIVE relations AS (
|
||||
SELECT entities.id, entities.parent_id, count(releases.id) AS releases_count, count(releases.id) AS total_count
|
||||
FROM entities
|
||||
LEFT JOIN releases ON releases.entity_id = entities.id
|
||||
GROUP BY entities.id
|
||||
|
||||
UNION ALL
|
||||
|
||||
SELECT entities.id AS entity_id, count(releases.id) AS releases_count, count(releases.id) + relations.total_count AS total_count
|
||||
FROM entities
|
||||
INNER JOIN relations ON relations.id = entities.parent_id
|
||||
LEFT JOIN releases ON releases.entity_id = entities.id
|
||||
GROUP BY entities.id
|
||||
)
|
||||
|
||||
SELECT relations.id AS entity_id, relations.releases_count
|
||||
FROM relations;
|
||||
`);
|
||||
|
||||
exports.down = async (knex) => knex.raw(`
|
||||
DROP MATERIALIZED VIEW entities_stats;
|
||||
`);
|
||||
@@ -1,7 +0,0 @@
|
||||
exports.up = async (knex) => knex.schema.alterTable('releases', (table) => {
|
||||
table.specificType('qualities', 'text[]');
|
||||
});
|
||||
|
||||
exports.down = async (knex) => knex.schema.alterTable('releases', (table) => {
|
||||
table.dropColumn('qualities');
|
||||
});
|
||||
@@ -1,12 +0,0 @@
|
||||
exports.up = async (knex) => knex.raw(`
|
||||
CREATE MATERIALIZED VIEW entities_stats
|
||||
AS
|
||||
SELECT entities.id AS entity_id, count(releases.id) AS releases_count
|
||||
FROM entities
|
||||
LEFT JOIN releases ON releases.entity_id = entities.id
|
||||
GROUP BY entities.id;
|
||||
`);
|
||||
|
||||
exports.down = async (knex) => knex.raw(`
|
||||
DROP MATERIALIZED VIEW entities_stats;
|
||||
`);
|
||||
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "traxxx",
|
||||
"version": "1.213.9",
|
||||
"version": "1.209.4",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "traxxx",
|
||||
"version": "1.213.9",
|
||||
"version": "1.209.4",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@casl/ability": "^5.2.2",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "traxxx",
|
||||
"version": "1.213.9",
|
||||
"version": "1.209.4",
|
||||
"description": "All the latest porn releases in one place",
|
||||
"main": "src/app.js",
|
||||
"scripts": {
|
||||
|
||||
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 2.3 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 1.2 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 3.2 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 2.6 KiB After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 3.4 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 9.9 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 7.1 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 2.1 KiB After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 6.6 KiB |
|
Before Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 6.1 KiB After Width: | Height: | Size: 6.1 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 3.6 KiB After Width: | Height: | Size: 3.6 KiB |
|
Before Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 3.5 KiB After Width: | Height: | Size: 3.5 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 2.4 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 3.7 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
Before Width: | Height: | Size: 6.4 KiB |
|
Before Width: | Height: | Size: 1.3 MiB |
|
Before Width: | Height: | Size: 29 KiB |
@@ -225,7 +225,6 @@ const networks = [
|
||||
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.',
|
||||
parameters: {
|
||||
actorPath: 'modelprofile',
|
||||
forceDeep: true, // Digital Playground has movie and series information not available in the latest updates API
|
||||
},
|
||||
parent: 'mindgeek',
|
||||
},
|
||||
@@ -412,9 +411,6 @@ const networks = [
|
||||
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',
|
||||
parameters: {
|
||||
forceDeep: true, // Mile High Media has movie and series information not available in the latest updates API
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'mofos',
|
||||
|
||||
@@ -810,13 +810,6 @@ const sites = [
|
||||
parameters: { siteId: 3261 },
|
||||
parent: 'bang',
|
||||
},
|
||||
{
|
||||
name: 'Bang! Podcast',
|
||||
slug: 'bangpodcast',
|
||||
url: 'https://www.bang.com/videos?in=bang!%20podcast',
|
||||
parameters: { siteId: 6305 },
|
||||
parent: 'bang',
|
||||
},
|
||||
// BANGBROS
|
||||
{
|
||||
name: 'Ass Parade',
|
||||
@@ -2653,7 +2646,7 @@ const sites = [
|
||||
{
|
||||
slug: 'digitalplayground',
|
||||
name: 'Digital Playground',
|
||||
url: 'https://www.digitalplayground.com',
|
||||
url: 'https://www.digitalplayground.com/scenes',
|
||||
description: '',
|
||||
parameters: { extract: true },
|
||||
parent: 'digitalplayground',
|
||||
@@ -2687,13 +2680,6 @@ const sites = [
|
||||
description: '',
|
||||
parent: 'digitalplayground',
|
||||
},
|
||||
{
|
||||
slug: 'dpstarsexchallenges',
|
||||
name: 'DP Star Sex Challenges',
|
||||
url: 'https://www.digitalplayground.com/scenes?site=210',
|
||||
parent: 'digitalplayground',
|
||||
hasLogo: false,
|
||||
},
|
||||
{
|
||||
slug: 'blockbuster',
|
||||
name: 'Blockbuster',
|
||||
@@ -2714,142 +2700,163 @@ const sites = [
|
||||
{
|
||||
slug: 'blacksonblondes',
|
||||
name: 'Blacks On Blondes',
|
||||
url: 'https://www.blacksonblondes.com',
|
||||
url: 'https://www.blacksonblondes.com/tour',
|
||||
description: 'Blacks On Blondes is the Worlds Largest and Best Interracial Sex and Interracial Porn website. Black Men and White Women. BlacksOnBlondes has 23 years worth of Hardcore Interracial Content. Featuring the entire Legendary Dogfart Movie Archive',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'cuckoldsessions',
|
||||
name: 'Cuckold Sessions',
|
||||
url: 'https://www.cuckoldsessions.com',
|
||||
description: 'Dogfart, the #1 Interracial Network in the World Presents CuckoldSessions.com - Hardcore Cuckold Fetish Videos',
|
||||
url: 'https://www.cuckoldsessions.com/tour',
|
||||
description: 'Dogfart, the #1 Interracial Network in the World Presents CuckoldSessions.com/tour - Hardcore Cuckold Fetish Videos',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'gloryhole',
|
||||
name: 'Glory Hole',
|
||||
url: 'https://www.gloryhole.com',
|
||||
url: 'https://www.gloryhole.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'blacksoncougars',
|
||||
name: 'Blacks On Cougars',
|
||||
url: 'https://www.blacksoncougars.com',
|
||||
url: 'https://www.blacksoncougars.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'wefuckblackgirls',
|
||||
name: 'We Fuck Black Girls',
|
||||
alias: ['wfbg'],
|
||||
url: 'https://www.wefuckblackgirls.com',
|
||||
url: 'https://www.wefuckblackgirls.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'watchingmymomgoblack',
|
||||
name: 'Watching My Mom Go Black',
|
||||
url: 'https://www.watchingmymomgoblack.com',
|
||||
url: 'https://www.watchingmymomgoblack.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'interracialblowbang',
|
||||
name: 'Interracial Blowbang',
|
||||
url: 'https://www.interracialblowbang.com',
|
||||
url: 'https://www.interracialblowbang.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'cumbang',
|
||||
name: 'Cumbang',
|
||||
url: 'https://www.cumbang.com',
|
||||
url: 'https://www.cumbang.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'interracialpickups',
|
||||
name: 'Interracial Pickups',
|
||||
url: 'https://www.interracialpickups.com',
|
||||
url: 'https://www.interracialpickups.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'watchingmydaughtergoblack',
|
||||
name: 'Watching My Daughter Go Black',
|
||||
url: 'https://www.watchingmydaughtergoblack.com',
|
||||
url: 'https://www.watchingmydaughtergoblack.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'zebragirls',
|
||||
name: 'Zebra Girls',
|
||||
url: 'https://www.zebragirls.com',
|
||||
url: 'https://www.zebragirls.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'gloryholeinitiations',
|
||||
name: 'Gloryhole Initiations',
|
||||
url: 'https://www.gloryhole-initiations.com',
|
||||
url: 'https://www.gloryhole-initiations.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'dogfartbehindthescenes',
|
||||
name: 'Dogfart Behind The Scenes',
|
||||
url: 'https://www.dogfartbehindthescenes.com',
|
||||
url: 'https://www.dogfartbehindthescenes.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'blackmeatwhitefeet',
|
||||
name: 'Black Meat White Feet',
|
||||
url: 'https://www.blackmeatwhitefeet.com',
|
||||
url: 'https://www.blackmeatwhitefeet.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'springthomas',
|
||||
name: 'Spring Thomas',
|
||||
url: 'https://www.springthomas.com',
|
||||
url: 'https://www.springthomas.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'katiethomas',
|
||||
name: 'Katie Thomas',
|
||||
url: 'https://www.katiethomas.com',
|
||||
url: 'https://www.katiethomas.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'ruthblackwell',
|
||||
name: 'Ruth Blackwell',
|
||||
url: 'https://www.ruthblackwell.com',
|
||||
url: 'https://www.ruthblackwell.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'candymonroe',
|
||||
name: 'Candy Monroe',
|
||||
url: 'https://www.candymonroe.com',
|
||||
url: 'https://www.candymonroe.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'wifewriting',
|
||||
name: 'Wife Writing',
|
||||
url: 'https://www.wifewriting.com',
|
||||
url: 'https://www.wifewriting.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'barbcummings',
|
||||
name: 'Barb Cummings',
|
||||
url: 'https://www.barbcummings.com',
|
||||
url: 'https://www.barbcummings.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'theminion',
|
||||
name: 'The Minion',
|
||||
url: 'https://www.theminion.com',
|
||||
url: 'https://www.theminion.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'blacksonboys',
|
||||
name: 'Blacks On Boys',
|
||||
url: 'https://www.blacksonboys.com',
|
||||
url: 'https://www.blacksonboys.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
{
|
||||
slug: 'gloryholesandhandjobs',
|
||||
name: 'Gloryholes And Handjobs',
|
||||
url: 'https://www.gloryholesandhandjobs.com',
|
||||
url: 'https://www.gloryholesandhandjobs.com/tour',
|
||||
description: '',
|
||||
parent: 'dogfartnetwork',
|
||||
},
|
||||
// DORCEL
|
||||
@@ -4198,6 +4205,7 @@ const sites = [
|
||||
tags: ['bdsm'],
|
||||
parent: 'insex',
|
||||
parameters: {
|
||||
scraper: 'alt',
|
||||
latest: 'https://www.sexuallybroken.com/sb',
|
||||
},
|
||||
},
|
||||
@@ -4208,20 +4216,13 @@ const sites = [
|
||||
url: 'https://www.infernalrestraints.com',
|
||||
tags: ['bdsm'],
|
||||
parent: 'insex',
|
||||
parameters: {
|
||||
latest: 'https://www.infernalrestraints.com/ir',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'hardtied',
|
||||
name: 'Hardtied',
|
||||
alias: ['ht'],
|
||||
url: 'https://www.hardtied.com',
|
||||
tags: ['bdsm'],
|
||||
parent: 'insex',
|
||||
parameters: {
|
||||
latest: 'https://www.hardtied.com/ht',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'realtimebondage',
|
||||
@@ -4230,9 +4231,6 @@ const sites = [
|
||||
url: 'https://www.realtimebondage.com',
|
||||
tags: ['bdsm', 'live'],
|
||||
parent: 'insex',
|
||||
parameters: {
|
||||
latest: 'https://www.realtimebondage.com/rtb',
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'topgrl',
|
||||
@@ -4242,6 +4240,7 @@ const sites = [
|
||||
tags: ['bdsm', 'femdom'],
|
||||
parent: 'insex',
|
||||
parameters: {
|
||||
scraper: 'alt',
|
||||
latest: 'https://www.topgrl.com/tg',
|
||||
},
|
||||
},
|
||||
@@ -5265,7 +5264,7 @@ const sites = [
|
||||
{
|
||||
slug: 'bigdicksatschool',
|
||||
name: 'Big Dicks At School',
|
||||
url: 'https://www.men.com/scenes?site=252',
|
||||
url: 'https://www.bigdicksatschool.com',
|
||||
description: '',
|
||||
parameters: { siteId: 252 },
|
||||
tags: ['gay'],
|
||||
@@ -5274,7 +5273,7 @@ const sites = [
|
||||
{
|
||||
slug: 'drillmyhole',
|
||||
name: 'Drill My Hole',
|
||||
url: 'https://www.men.com/scenes?site=253',
|
||||
url: 'https://www.drillmyhole.com',
|
||||
description: '',
|
||||
parameters: { siteId: 253 },
|
||||
tags: ['gay'],
|
||||
@@ -5283,7 +5282,7 @@ const sites = [
|
||||
{
|
||||
slug: 'str8togay',
|
||||
name: 'Str8 to Gay',
|
||||
url: 'https://www.men.com/scenes?site=254',
|
||||
url: 'https://www.str8togay.com',
|
||||
tags: ['gay'],
|
||||
parameters: { siteId: 254 },
|
||||
parent: 'men',
|
||||
@@ -5291,7 +5290,7 @@ const sites = [
|
||||
{
|
||||
slug: 'thegayoffice',
|
||||
name: 'The Gay Office',
|
||||
url: 'https://www.men.com/scenes?site=255',
|
||||
url: 'https://www.thegayoffice.com',
|
||||
tags: ['gay'],
|
||||
parameters: { siteId: 255 },
|
||||
parent: 'men',
|
||||
@@ -5299,7 +5298,7 @@ const sites = [
|
||||
{
|
||||
slug: 'jizzorgy',
|
||||
name: 'Jizz Orgy',
|
||||
url: 'https://www.men.com/scenes?site=256',
|
||||
url: 'https://www.jizzorgy.com',
|
||||
tags: ['gay'],
|
||||
parameters: { siteId: 256 },
|
||||
parent: 'men',
|
||||
@@ -5307,7 +5306,7 @@ const sites = [
|
||||
{
|
||||
slug: 'menofuk',
|
||||
name: 'Men of UK',
|
||||
url: 'https://www.men.com/scenes?site=258',
|
||||
url: 'https://www.menofuk.com',
|
||||
tags: ['gay'],
|
||||
parameters: { siteId: 258 },
|
||||
parent: 'men',
|
||||
@@ -5315,7 +5314,7 @@ const sites = [
|
||||
{
|
||||
slug: 'toptobottom',
|
||||
name: 'Top to Bottom',
|
||||
url: 'https://www.men.com/scenes?site=259',
|
||||
url: 'https://www.toptobottom.com',
|
||||
tags: ['gay'],
|
||||
parameters: { siteId: 259 },
|
||||
parent: 'men',
|
||||
@@ -5323,7 +5322,7 @@ const sites = [
|
||||
{
|
||||
slug: 'godsofmen',
|
||||
name: 'Gods of Men',
|
||||
url: 'https://www.men.com/scenes?site=260',
|
||||
url: 'https://www.godsofmen.com',
|
||||
tags: ['gay'],
|
||||
parameters: { siteId: 260 },
|
||||
parent: 'men',
|
||||
@@ -5414,10 +5413,7 @@ const sites = [
|
||||
name: 'Doghouse Digital',
|
||||
url: 'https://www.doghousedigital.com',
|
||||
alias: ['dhd'],
|
||||
parameters: {
|
||||
siteId: 321,
|
||||
native: true,
|
||||
},
|
||||
parameters: { siteId: 321 },
|
||||
parent: 'milehighmedia',
|
||||
},
|
||||
{
|
||||
@@ -5433,10 +5429,7 @@ const sites = [
|
||||
name: 'Reality Junkies',
|
||||
url: 'https://www.realityjunkies.com',
|
||||
alias: ['rj'],
|
||||
parameters: {
|
||||
siteId: 324,
|
||||
native: true,
|
||||
},
|
||||
parameters: { siteId: 324 },
|
||||
parent: 'milehighmedia',
|
||||
},
|
||||
{
|
||||
@@ -5444,10 +5437,7 @@ const sites = [
|
||||
name: 'Sweetheart Video',
|
||||
url: 'https://www.sweetheartvideo.com',
|
||||
alias: ['shv'],
|
||||
parameters: {
|
||||
siteId: 325,
|
||||
native: true,
|
||||
},
|
||||
parameters: { siteId: 325 },
|
||||
parent: 'milehighmedia',
|
||||
},
|
||||
{
|
||||
@@ -5455,10 +5445,7 @@ const sites = [
|
||||
name: 'Sweet Sinner',
|
||||
url: 'https://www.sweetsinner.com',
|
||||
alias: ['ss'],
|
||||
parameters: {
|
||||
siteId: 326,
|
||||
native: true,
|
||||
},
|
||||
parameters: { siteId: 326 },
|
||||
parent: 'milehighmedia',
|
||||
},
|
||||
{
|
||||
@@ -5467,10 +5454,7 @@ const sites = [
|
||||
alias: ['fs'],
|
||||
tags: ['family'],
|
||||
url: 'https://www.familysinners.com',
|
||||
parameters: {
|
||||
siteId: 317,
|
||||
native: true,
|
||||
},
|
||||
parameters: { siteId: 317 },
|
||||
parent: 'milehighmedia',
|
||||
},
|
||||
{
|
||||
@@ -5479,10 +5463,7 @@ const sites = [
|
||||
url: 'https://www.iconmale.com',
|
||||
alias: ['im'],
|
||||
tags: ['gay'],
|
||||
parameters: {
|
||||
siteId: 328,
|
||||
native: true,
|
||||
},
|
||||
parameters: { native: true, siteId: 328 },
|
||||
parent: 'milehighmedia',
|
||||
},
|
||||
// MOFOS
|
||||
@@ -6896,13 +6877,6 @@ const sites = [
|
||||
tourId: 9,
|
||||
},
|
||||
},
|
||||
{
|
||||
slug: 'dpdiva',
|
||||
name: 'DP Diva',
|
||||
url: 'http://dpdiva.com',
|
||||
parent: 'pervcity',
|
||||
tags: ['dp', 'anal'],
|
||||
},
|
||||
// PIERRE WOODMAN
|
||||
{
|
||||
slug: 'woodmancastingx',
|
||||
@@ -8605,10 +8579,7 @@ const sites = [
|
||||
name: 'Dane Jones',
|
||||
alias: ['dnj'],
|
||||
url: 'https://www.danejones.com/',
|
||||
parameters: {
|
||||
siteId: 290,
|
||||
native: true,
|
||||
},
|
||||
parameters: { siteId: 290 },
|
||||
parent: 'sexyhub',
|
||||
},
|
||||
{
|
||||
@@ -8616,10 +8587,7 @@ const sites = [
|
||||
name: 'Lesbea',
|
||||
alias: ['lsb'],
|
||||
url: 'https://www.lesbea.com',
|
||||
parameters: {
|
||||
siteId: 291,
|
||||
native: true,
|
||||
},
|
||||
parameters: { siteId: 291 },
|
||||
tags: ['lesbian'],
|
||||
parent: 'sexyhub',
|
||||
},
|
||||
|
||||
@@ -727,6 +727,8 @@ const tagMedia = [
|
||||
['da-tp', 7, 'Polly Petrova in YE069', 'analvids'],
|
||||
['da-tp', 5, 'Venera Maxima in GIO1287'],
|
||||
['da-tp', 6, 'Adriana Chechik in "Gangbang Me"', 'hardx'],
|
||||
['da-tp', 0, 'Natasha Teen in SZ2164'],
|
||||
['da-tp', 1, 'Francys Belle in SZ1702', 'analvids'],
|
||||
['dap', 7, 'Adriana Chechik in "DP Masters 6"', 'julesjordan'],
|
||||
['dap', 10, 'Kira Noir', 'hardx'],
|
||||
['dap', 'emily_pink_legalporno', 'Emily Pink', 'analvids'],
|
||||
@@ -1047,7 +1049,6 @@ const tagMedia = [
|
||||
['toy-dp', 0, 'Marley Brinx, Ivy Lebelle and Lyra Law in "Marley Brinx First GGDP"', 'lesbianx'],
|
||||
['toys', 1, 'Chloe Lamour in "Curives In All The Right Places"', 'wetandpuffy'],
|
||||
['toys', 'shawna_lenee_sunrisekings', 'Shawna Lenee', 'sunrisekings'],
|
||||
['triple-penetration', 'lucky_bee_analvids', 'Lucky Bee', 'analvids'],
|
||||
['triple-penetration', 'angela_white_julesjordan', 'Angela White in "Her Biggest Gangbang Ever"', 'julesjordan'],
|
||||
['triple-penetration', 'ria_sunn_legalporno', 'Ria Sunn in SZ2082', 'analvids'],
|
||||
['tvp', 'september_reign_wefuckblackgirls', 'September Reign in "Second Appearance"', 'wefuckblackgirls'],
|
||||
|
||||
@@ -14,6 +14,6 @@
|
||||
"prefer-destructuring": "off",
|
||||
"template-curly-spacing": "off",
|
||||
"object-curly-newline": "off",
|
||||
"max-len": [2, {"code": 300, "tabWidth": 4, "ignoreUrls": true}]
|
||||
"max-len": [2, {"code": 300, "tabWidth": 4, "ignoreUrls": true}],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,6 @@ const scrapers = require('./scrapers/scrapers').actors;
|
||||
const argv = require('./argv');
|
||||
const include = require('./utils/argv-include')(argv);
|
||||
const bulkInsert = require('./utils/bulk-insert');
|
||||
const chunk = require('./utils/chunk');
|
||||
const logger = require('./logger')(__filename);
|
||||
|
||||
const { toBaseReleases } = require('./deep');
|
||||
@@ -1049,42 +1048,33 @@ async function flushProfiles(actorIdsOrNames) {
|
||||
logger.info(`Removed ${deleteCount} profiles`);
|
||||
}
|
||||
|
||||
async function deleteActors(allActorIdsOrNames) {
|
||||
const deleteCounts = await Promise.map(chunk(allActorIdsOrNames), async (actorIdsOrNames) => {
|
||||
const actors = await knex('actors')
|
||||
.whereIn('id', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'number'))
|
||||
.orWhere((builder) => {
|
||||
builder
|
||||
.whereIn('name', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'string'))
|
||||
.whereNull('entity_id');
|
||||
});
|
||||
async function deleteActors(actorIdsOrNames) {
|
||||
const actors = await knex('actors')
|
||||
.whereIn('id', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'number'))
|
||||
.orWhere((builder) => {
|
||||
builder
|
||||
.whereIn('name', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'string'))
|
||||
.whereNull('entity_id');
|
||||
});
|
||||
|
||||
const actorIds = actors.map((actor) => actor.id);
|
||||
const actorIds = actors.map((actor) => actor.id);
|
||||
|
||||
const sceneIds = await knex('releases_actors')
|
||||
.select('releases.id')
|
||||
.whereIn('actor_id', actorIds)
|
||||
.leftJoin('releases', 'releases.id', 'releases_actors.release_id')
|
||||
.pluck('id');
|
||||
const sceneIds = await knex('releases_actors')
|
||||
.select('releases.id')
|
||||
.whereIn('actor_id', actorIds)
|
||||
.leftJoin('releases', 'releases.id', 'releases_actors.release_id')
|
||||
.pluck('id');
|
||||
|
||||
const [deletedScenesCount, deletedActorsCount] = await Promise.all([
|
||||
deleteScenes(sceneIds),
|
||||
knex('actors')
|
||||
.whereIn('id', actorIds)
|
||||
.delete(),
|
||||
]);
|
||||
|
||||
return { deletedScenesCount, deletedActorsCount };
|
||||
}, { concurrency: 10 });
|
||||
|
||||
const deletedActorsCount = deleteCounts.reduce((acc, count) => acc + count.deletedActorsCount, 0);
|
||||
const deletedScenesCount = deleteCounts.reduce((acc, count) => acc + count.deletedScenesCount, 0);
|
||||
const [deletedScenesCount, deletedActorsCount] = await Promise.all([
|
||||
deleteScenes(sceneIds),
|
||||
knex('actors')
|
||||
.whereIn('id', actorIds)
|
||||
.delete(),
|
||||
]);
|
||||
|
||||
await flushOrphanedMedia();
|
||||
|
||||
logger.info(`Removed ${deletedActorsCount} actors with ${deletedScenesCount} scenes`);
|
||||
|
||||
return deletedActorsCount;
|
||||
}
|
||||
|
||||
async function flushActors() {
|
||||
|
||||
@@ -194,7 +194,6 @@ const { argv } = yargs
|
||||
alias: 'pics',
|
||||
})
|
||||
.option('videos', {
|
||||
alias: 'video',
|
||||
describe: 'Include any trailers or teasers',
|
||||
type: 'boolean',
|
||||
default: true,
|
||||
@@ -239,7 +238,6 @@ const { argv } = yargs
|
||||
default: false,
|
||||
})
|
||||
.option('level', {
|
||||
alias: 'log-level',
|
||||
describe: 'Log level',
|
||||
type: 'string',
|
||||
default: process.env.NODE_ENV === 'development' ? 'silly' : 'info',
|
||||
|
||||
@@ -6,7 +6,7 @@ const inquirer = require('inquirer');
|
||||
const logger = require('./logger')(__filename);
|
||||
const argv = require('./argv');
|
||||
const knex = require('./knex');
|
||||
const { deleteScenes, deleteMovies, deleteSeries } = require('./releases');
|
||||
const { deleteScenes, deleteMovies } = require('./releases');
|
||||
const { flushOrphanedMedia } = require('./media');
|
||||
const { resolveScraper, resolveLayoutScraper } = require('./scrapers/resolve');
|
||||
|
||||
@@ -359,39 +359,29 @@ async function flushEntities(networkSlugs = [], channelSlugs = []) {
|
||||
.leftJoin('movies', 'movies.entity_id', 'selected_entities.id')
|
||||
.pluck('movies.id');
|
||||
|
||||
const serieIds = await entityQuery
|
||||
.clone()
|
||||
.select('series.id')
|
||||
.distinct('series.id')
|
||||
.whereNotNull('series.id')
|
||||
.from('selected_entities')
|
||||
.leftJoin('series', 'series.entity_id', 'selected_entities.id')
|
||||
.pluck('series.id');
|
||||
|
||||
if (sceneIds.length === 0 && movieIds.length === 0 && serieIds.length === 0) {
|
||||
logger.info(`No scenes, movies or series found to remove for ${entitySlugs}`);
|
||||
if (sceneIds.length === 0 && movieIds.length === 0) {
|
||||
logger.info(`No scenes or movies found to remove for ${entitySlugs}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const confirmed = await inquirer.prompt([{
|
||||
type: 'confirm',
|
||||
name: 'flushEntities',
|
||||
message: `You are about to remove ${sceneIds.length} scenes, ${movieIds.length} movies and ${serieIds.length} series for ${entitySlugs}. Are you sure?`,
|
||||
message: `You are about to remove ${sceneIds.length} scenes and ${movieIds.length} movies for ${entitySlugs}. Are you sure?`,
|
||||
default: false,
|
||||
}]);
|
||||
|
||||
if (!confirmed.flushEntities) {
|
||||
logger.warn(`Confirmation rejected, not flushing scenes, movies or series for: ${entitySlugs}`);
|
||||
logger.warn(`Confirmation rejected, not flushing scenes or movies for: ${entitySlugs}`);
|
||||
return;
|
||||
}
|
||||
|
||||
const [deletedScenesCount, deletedMoviesCount, deletedSeriesCount] = await Promise.all([
|
||||
const [deletedScenesCount, deletedMoviesCount] = await Promise.all([
|
||||
deleteScenes(sceneIds),
|
||||
deleteMovies(movieIds),
|
||||
deleteSeries(serieIds),
|
||||
]);
|
||||
|
||||
logger.info(`Removed ${deletedScenesCount} scenes, ${deletedMoviesCount} movies and ${deletedSeriesCount} series for ${entitySlugs}`);
|
||||
logger.info(`Removed ${deletedScenesCount} scenes and ${deletedMoviesCount} movies for ${entitySlugs}`);
|
||||
|
||||
await flushOrphanedMedia();
|
||||
}
|
||||
|
||||
53
src/media.js
@@ -21,7 +21,6 @@ const argv = require('./argv');
|
||||
const knex = require('./knex');
|
||||
const http = require('./utils/http');
|
||||
const bulkInsert = require('./utils/bulk-insert');
|
||||
const chunk = require('./utils/chunk');
|
||||
const { get } = require('./utils/qu');
|
||||
|
||||
const pipeline = util.promisify(stream.pipeline);
|
||||
@@ -64,10 +63,10 @@ function sampleMedias(medias, limit = argv.mediaLimit, preferLast = true) {
|
||||
? chunks.slice(0, -1).concat(chunks.slice(-1).reverse())
|
||||
: chunks;
|
||||
|
||||
const groupedMedias = lastPreferredChunks.map((mediaChunk) => {
|
||||
const groupedMedias = lastPreferredChunks.map((chunk) => {
|
||||
// merge chunked medias into single media with grouped fallback priorities,
|
||||
// so the first sources of each media is preferred over all second sources, etc.
|
||||
const sources = mediaChunk
|
||||
const sources = chunk
|
||||
.reduce((accSources, media) => {
|
||||
media.sources.forEach((source, index) => {
|
||||
if (!accSources[index]) {
|
||||
@@ -83,8 +82,8 @@ function sampleMedias(medias, limit = argv.mediaLimit, preferLast = true) {
|
||||
.flat();
|
||||
|
||||
return {
|
||||
id: mediaChunk[0].id,
|
||||
role: mediaChunk[0].role,
|
||||
id: chunk[0].id,
|
||||
role: chunk[0].role,
|
||||
sources,
|
||||
};
|
||||
});
|
||||
@@ -236,41 +235,22 @@ async function findSourceDuplicates(baseMedias) {
|
||||
.filter(Boolean);
|
||||
|
||||
const [existingSourceMedia, existingExtractMedia] = await Promise.all([
|
||||
// my try to check thousands of URLs at once, don't pass all of them to a single query
|
||||
chunk(sourceUrls).reduce(async (chain, sourceUrlsChunk) => {
|
||||
const accUrls = await chain;
|
||||
const existingUrls = await knex('media').whereIn('source', sourceUrlsChunk);
|
||||
|
||||
return [...accUrls, ...existingUrls];
|
||||
}, []),
|
||||
chunk(extractUrls).reduce(async (chain, extractUrlsChunk) => {
|
||||
const accUrls = await chain;
|
||||
const existingUrls = await knex('media').whereIn('source_page', extractUrlsChunk);
|
||||
|
||||
return [...accUrls, ...existingUrls];
|
||||
}, []),
|
||||
knex('media').whereIn('source', sourceUrls),
|
||||
knex('media').whereIn('source_page', extractUrls),
|
||||
]);
|
||||
|
||||
const existingSourceMediaByUrl = itemsByKey(existingSourceMedia, 'source');
|
||||
const existingExtractMediaByUrl = itemsByKey(existingExtractMedia, 'source_page');
|
||||
|
||||
return {
|
||||
existingSourceMediaByUrl,
|
||||
existingExtractMediaByUrl,
|
||||
};
|
||||
return { existingSourceMediaByUrl, existingExtractMediaByUrl };
|
||||
}
|
||||
|
||||
async function findHashDuplicates(medias) {
|
||||
const hashes = medias.map((media) => media.meta?.hash || media.entry?.hash).filter(Boolean);
|
||||
|
||||
const existingHashMediaEntries = await chunk(hashes, 2).reduce(async (chain, hashesChunk) => {
|
||||
const accHashes = await chain;
|
||||
const existingHashes = await knex('media').whereIn('hash', hashesChunk);
|
||||
|
||||
return [...accHashes, ...existingHashes];
|
||||
}, []);
|
||||
|
||||
const existingHashMediaEntries = await knex('media').whereIn('hash', hashes);
|
||||
const existingHashMediaEntriesByHash = itemsByKey(existingHashMediaEntries, 'hash');
|
||||
|
||||
const uniqueHashMedias = medias.filter((media) => !media.entry && !existingHashMediaEntriesByHash[media.meta?.hash]);
|
||||
|
||||
const { selfDuplicateMedias, selfUniqueMediasByHash } = uniqueHashMedias.reduce((acc, media) => {
|
||||
@@ -620,11 +600,11 @@ async function fetchSource(source, baseMedia) {
|
||||
const hashStream = new stream.PassThrough();
|
||||
let size = 0;
|
||||
|
||||
hashStream.on('data', (streamChunk) => {
|
||||
size += streamChunk.length;
|
||||
hashStream.on('data', (chunk) => {
|
||||
size += chunk.length;
|
||||
|
||||
if (hasherReady) {
|
||||
hasher.write(streamChunk);
|
||||
hasher.write(chunk);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -981,12 +961,9 @@ async function flushOrphanedMedia() {
|
||||
await deleteS3Objects(orphanedMedia.filter((media) => media.is_s3));
|
||||
}
|
||||
|
||||
try {
|
||||
await fsPromises.rm(path.join(config.media.path, 'temp'), { recursive: true });
|
||||
logger.info('Cleared temporary media directory');
|
||||
} catch (error) {
|
||||
logger.warn(`Failed to clear temporary media directory: ${error.message}`);
|
||||
}
|
||||
await fsPromises.rm(path.join(config.media.path, 'temp'), { recursive: true });
|
||||
|
||||
logger.info('Cleared temporary media directory');
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
|
||||