Compare commits
2 Commits
experiment
...
old
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4839a3b94c | ||
|
|
d8b641e461 |
52
assets/components/container/container.vue
Normal file → Executable file
@@ -8,35 +8,40 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<transition name="slide">
|
<transition name="slide">
|
||||||
<Sidebar
|
<Sidebar v-if="showSidebar" />
|
||||||
v-if="showSidebar"
|
|
||||||
@toggle-sidebar="(state) => toggleSidebar(state)"
|
|
||||||
@show-filters="(state) => toggleFilters(state)"
|
|
||||||
/>
|
|
||||||
</transition>
|
</transition>
|
||||||
|
|
||||||
<Header
|
<Header />
|
||||||
@toggle-sidebar="(state) => toggleSidebar(state)"
|
|
||||||
@show-filters="(state) => toggleFilters(state)"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<p
|
<p
|
||||||
v-if="config.showDisclaimer"
|
v-if="config.showDisclaimer"
|
||||||
class="disclaimer"
|
class="disclaimer"
|
||||||
>{{ config.disclaimer }}</p>
|
v-html="config.disclaimer"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<p
|
||||||
|
v-if="config.showAnnouncement"
|
||||||
|
class="announcement"
|
||||||
|
v-html="config.announcement"
|
||||||
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
ref="content"
|
ref="content"
|
||||||
class="content"
|
class="content"
|
||||||
@scroll="scroll"
|
@scroll="scroll"
|
||||||
>
|
>
|
||||||
<router-view @scroll="scrollToTop" />
|
<RouterView @scroll="scrollToTop" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Filters
|
<Filters
|
||||||
v-if="showFilters"
|
v-if="showFilters"
|
||||||
@close="toggleFilters(false)"
|
@close="toggleFilters(false)"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Settings
|
||||||
|
v-if="showSettings"
|
||||||
|
@close="toggleSettings(false)"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@@ -45,6 +50,7 @@ import Warning from './warning.vue';
|
|||||||
import Header from '../header/header.vue';
|
import Header from '../header/header.vue';
|
||||||
import Sidebar from '../sidebar/sidebar.vue';
|
import Sidebar from '../sidebar/sidebar.vue';
|
||||||
import Filters from '../filters/filters.vue';
|
import Filters from '../filters/filters.vue';
|
||||||
|
import Settings from '../settings/settings.vue';
|
||||||
|
|
||||||
function toggleSidebar(state) {
|
function toggleSidebar(state) {
|
||||||
this.showSidebar = typeof state === 'boolean' ? state : !this.showSidebar;
|
this.showSidebar = typeof state === 'boolean' ? state : !this.showSidebar;
|
||||||
@@ -55,6 +61,11 @@ function toggleFilters(state) {
|
|||||||
this.showSidebar = false;
|
this.showSidebar = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function toggleSettings(state) {
|
||||||
|
this.showSettings = state;
|
||||||
|
this.showSidebar = false;
|
||||||
|
}
|
||||||
|
|
||||||
async function setConsent(consent, includeQueer) {
|
async function setConsent(consent, includeQueer) {
|
||||||
if (consent) {
|
if (consent) {
|
||||||
this.showWarning = false;
|
this.showWarning = false;
|
||||||
@@ -88,6 +99,9 @@ function scrollToTop() {
|
|||||||
function mounted() {
|
function mounted() {
|
||||||
document.addEventListener('click', this.blur);
|
document.addEventListener('click', this.blur);
|
||||||
window.addEventListener('resize', this.resize);
|
window.addEventListener('resize', this.resize);
|
||||||
|
|
||||||
|
this.events.on('toggleSettings', this.toggleSettings);
|
||||||
|
this.events.on('toggleSidebar', this.toggleSidebar);
|
||||||
}
|
}
|
||||||
|
|
||||||
function beforeUnmount() {
|
function beforeUnmount() {
|
||||||
@@ -101,12 +115,15 @@ export default {
|
|||||||
Sidebar,
|
Sidebar,
|
||||||
Warning,
|
Warning,
|
||||||
Filters,
|
Filters,
|
||||||
|
Settings,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
showSidebar: false,
|
showSidebar: false,
|
||||||
showWarning: localStorage.getItem('consent') !== window.env.sessionId,
|
showWarning: localStorage.getItem('consent') !== window.env.sessionId,
|
||||||
showFilters: false,
|
showFilters: false,
|
||||||
|
showSettings: false,
|
||||||
|
selected: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
mounted,
|
mounted,
|
||||||
@@ -114,6 +131,7 @@ export default {
|
|||||||
methods: {
|
methods: {
|
||||||
toggleSidebar,
|
toggleSidebar,
|
||||||
toggleFilters,
|
toggleFilters,
|
||||||
|
toggleSettings,
|
||||||
setConsent,
|
setConsent,
|
||||||
blur,
|
blur,
|
||||||
resize,
|
resize,
|
||||||
@@ -183,13 +201,21 @@ export default {
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style lang="scss" scoped>
|
<style lang="scss" scoped>
|
||||||
.disclaimer {
|
.disclaimer,
|
||||||
|
.announcement {
|
||||||
padding: .5rem 1rem;
|
padding: .5rem 1rem;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
background: var(--warn);
|
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
box-shadow: inset 0 0 3px var(--darken-weak);
|
box-shadow: inset 0 0 3px var(--darken-weak);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.disclaimer {
|
||||||
|
background: var(--warn);
|
||||||
|
}
|
||||||
|
|
||||||
|
.announcement {
|
||||||
|
background: var(--notice);
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|||||||
@@ -108,7 +108,6 @@
|
|||||||
:fetch-releases="fetchEntity"
|
:fetch-releases="fetchEntity"
|
||||||
:items-total="totalCount"
|
:items-total="totalCount"
|
||||||
:items-per-page="limit"
|
:items-per-page="limit"
|
||||||
:available-tags="entity.tags"
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div class="releases">
|
<div class="releases">
|
||||||
|
|||||||
@@ -102,8 +102,6 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.name {
|
.name {
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
color: var(--text-light);
|
color: var(--text-light);
|
||||||
font-size: 1.25rem;
|
font-size: 1.25rem;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ export default {
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
beforeMount() {
|
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>
|
</script>
|
||||||
|
|||||||
@@ -11,22 +11,8 @@
|
|||||||
class="empty"
|
class="empty"
|
||||||
>No results for "{{ $route.query.query }}"</span>
|
>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
|
<div
|
||||||
|
v-else
|
||||||
class="entity-tiles"
|
class="entity-tiles"
|
||||||
>
|
>
|
||||||
<Entity
|
<Entity
|
||||||
@@ -35,7 +21,6 @@
|
|||||||
:entity="entity"
|
:entity="entity"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
@@ -73,45 +58,6 @@ async function searchEntities() {
|
|||||||
this.done = true;
|
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() {
|
async function mounted() {
|
||||||
this.pageTitle = 'Channels';
|
this.pageTitle = 'Channels';
|
||||||
|
|
||||||
@@ -136,7 +82,6 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
channelCount,
|
channelCount,
|
||||||
popularEntities,
|
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route: fetchEntities,
|
$route: fetchEntities,
|
||||||
@@ -185,10 +130,6 @@ export default {
|
|||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.heading {
|
|
||||||
margin: 1rem 0 0 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media(max-width: $breakpoint2) {
|
@media(max-width: $breakpoint2) {
|
||||||
.entity-tiles {
|
.entity-tiles {
|
||||||
grid-gap: .5rem;
|
grid-gap: .5rem;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
<div class="media-container">
|
<div class="media-container">
|
||||||
<div
|
<div
|
||||||
class="media"
|
class="media"
|
||||||
:class="{ center: (release.photos?.length || 0) + (release.scenesPhotos?.length || 0) < 2, preview: !me }"
|
:class="{ center: release.photos.length < 2, preview: !me }"
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
v-if="release.trailer || release.teaser"
|
v-if="release.trailer || release.teaser"
|
||||||
@@ -71,13 +71,10 @@
|
|||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<template v-if="release.covers?.length > 0">
|
<template v-if="release.covers && release.covers.length > 0">
|
||||||
<div
|
<a
|
||||||
v-for="cover in release.covers"
|
v-for="cover in release.covers"
|
||||||
:key="`cover-${cover.id}`"
|
:key="`cover-${cover.id}`"
|
||||||
class="item-container"
|
|
||||||
>
|
|
||||||
<a
|
|
||||||
:href="getPath(cover)"
|
:href="getPath(cover)"
|
||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noopener noreferrer"
|
rel="noopener noreferrer"
|
||||||
@@ -92,7 +89,6 @@
|
|||||||
@load="$emit('load', $event)"
|
@load="$emit('load', $event)"
|
||||||
>
|
>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -168,8 +164,8 @@ function poster() {
|
|||||||
function photos() {
|
function photos() {
|
||||||
const clips = this.release.clips || [];
|
const clips = this.release.clips || [];
|
||||||
const clipPostersById = clips.reduce((acc, clip) => ({ ...acc, [clip.poster.id]: clip.poster }), {});
|
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 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 photosWithClipPosters = (this.release.photos || []).concat(uniqueClipPosters);
|
||||||
|
|
||||||
if (this.release.trailer || (this.release.teaser && this.release.teaser.mime !== 'image/gif')) {
|
if (this.release.trailer || (this.release.teaser && this.release.teaser.mime !== 'image/gif')) {
|
||||||
// poster will be on trailer video
|
// poster will be on trailer video
|
||||||
|
|||||||
@@ -3,6 +3,12 @@
|
|||||||
<div class="content-inner">
|
<div class="content-inner">
|
||||||
<SearchBar :placeholder="`Search ${totalCount} movies`" />
|
<SearchBar :placeholder="`Search ${totalCount} movies`" />
|
||||||
|
|
||||||
|
<TagFilter
|
||||||
|
class="filters-filter"
|
||||||
|
:filter="filter"
|
||||||
|
:available-tags="availableTags"
|
||||||
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
ref="tiles"
|
ref="tiles"
|
||||||
class="tiles"
|
class="tiles"
|
||||||
@@ -30,6 +36,7 @@
|
|||||||
import MovieTile from './movie-tile.vue';
|
import MovieTile from './movie-tile.vue';
|
||||||
import SearchBar from '../search/bar.vue';
|
import SearchBar from '../search/bar.vue';
|
||||||
import Pagination from '../pagination/pagination.vue';
|
import Pagination from '../pagination/pagination.vue';
|
||||||
|
import TagFilter from '../filters/tag-filter.vue';
|
||||||
|
|
||||||
async function fetchMovies() {
|
async function fetchMovies() {
|
||||||
if (this.$route.query.query) {
|
if (this.$route.query.query) {
|
||||||
@@ -73,6 +80,7 @@ export default {
|
|||||||
MovieTile,
|
MovieTile,
|
||||||
SearchBar,
|
SearchBar,
|
||||||
Pagination,
|
Pagination,
|
||||||
|
TagFilter,
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -21,14 +21,14 @@
|
|||||||
<Details :release="release" />
|
<Details :release="release" />
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="release.photos?.length > 0 || release.scenesPhotos?.length > 0"
|
v-if="release.photos.length > 0"
|
||||||
class="album-toggle"
|
class="album-toggle"
|
||||||
@click="$router.push({ hash: '#album' })"
|
@click="$router.push({ hash: '#album' })"
|
||||||
><Icon icon="grid3" />View album</button>
|
><Icon icon="grid3" />View album</button>
|
||||||
|
|
||||||
<Album
|
<Album
|
||||||
v-if="showAlbum"
|
v-if="showAlbum"
|
||||||
:items="[release.poster, ...(release.photos || []), ...(release.scenesPhotos || [])]"
|
:items="[release.poster, ...release.photos]"
|
||||||
:title="release.title"
|
:title="release.title"
|
||||||
:path="config.media.mediaPath"
|
:path="config.media.mediaPath"
|
||||||
@close="$router.replace({ hash: undefined })"
|
@close="$router.replace({ hash: undefined })"
|
||||||
@@ -79,23 +79,22 @@
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="release.movies?.length > 0 || release.series?.length > 0"
|
v-if="release.movies && release.movies.length > 0"
|
||||||
class="row"
|
class="row"
|
||||||
>
|
>
|
||||||
<span class="row-label">Part of</span>
|
<span class="row-label">Part of</span>
|
||||||
|
|
||||||
<div class="movies">
|
<div class="movies">
|
||||||
<router-link
|
<router-link
|
||||||
v-for="movie in [...release.movies, ...release.series]"
|
v-for="movie in release.movies"
|
||||||
:key="`movie-${movie.id}`"
|
: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"
|
class="movie"
|
||||||
>
|
>
|
||||||
<span class="movie-title">{{ movie.title }}</span>
|
<span class="movie-title">{{ movie.title }}</span>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
v-if="movie.covers.length > 0 || movie.poster"
|
v-if="movie.covers.length > 0"
|
||||||
:src="getPath(movie.covers[0] || movie.poster, 'thumbnail')"
|
:src="getPath(movie.covers[0], 'thumbnail')"
|
||||||
class="movie-cover"
|
class="movie-cover"
|
||||||
>
|
>
|
||||||
</router-link>
|
</router-link>
|
||||||
@@ -244,10 +243,6 @@ async function fetchRelease(scroll = true) {
|
|||||||
this.release = await this.$store.dispatch('fetchMovieById', this.$route.params.releaseId);
|
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) {
|
if (scroll && this.$refs.content) {
|
||||||
this.$refs.content.scrollTop = 0;
|
this.$refs.content.scrollTop = 0;
|
||||||
}
|
}
|
||||||
@@ -287,7 +282,7 @@ function pageTitle() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function showAlbum() {
|
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 {
|
export default {
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ const tagSlugsByCategory = {
|
|||||||
'titty-fucking',
|
'titty-fucking',
|
||||||
'fisting',
|
'fisting',
|
||||||
'anal-fisting',
|
'anal-fisting',
|
||||||
|
'fisting-dp',
|
||||||
],
|
],
|
||||||
group: [
|
group: [
|
||||||
'mfm',
|
'mfm',
|
||||||
@@ -107,31 +108,6 @@ const tagSlugsByCategory = {
|
|||||||
'bukkake',
|
'bukkake',
|
||||||
'fake-cum',
|
'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: [
|
||||||
'toys',
|
'toys',
|
||||||
'toy-anal',
|
'toy-anal',
|
||||||
@@ -142,6 +118,32 @@ const tagSlugsByCategory = {
|
|||||||
'double-dildo-anal',
|
'double-dildo-anal',
|
||||||
'double-dildo-dp',
|
'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: [
|
misc: [
|
||||||
'gaping',
|
'gaping',
|
||||||
'squirting',
|
'squirting',
|
||||||
|
|||||||
@@ -65,23 +65,19 @@ function curateActor(actor, release) {
|
|||||||
return curatedActor;
|
return curatedActor;
|
||||||
}
|
}
|
||||||
|
|
||||||
function curateRelease(release, type = 'scene') {
|
function curateRelease(release) {
|
||||||
const curatedRelease = {
|
const curatedRelease = {
|
||||||
...release,
|
...release,
|
||||||
type: release.type || type,
|
|
||||||
actors: [],
|
actors: [],
|
||||||
poster: release.poster && release.poster.media,
|
poster: release.poster && release.poster.media,
|
||||||
tags: release.tags ? release.tags.map((tag) => tag.tag || tag) : [],
|
tags: release.tags ? release.tags.map((tag) => tag.tag || tag) : [],
|
||||||
};
|
};
|
||||||
|
|
||||||
curatedRelease.scenes = release.scenes?.filter(Boolean).map(({ scene }) => curateRelease(scene, 'scene')) || [];
|
if (release.scenes) curatedRelease.scenes = release.scenes.filter(Boolean).map(({ scene }) => curateRelease(scene));
|
||||||
curatedRelease.movies = release.movies?.filter(Boolean).map(({ movie }) => curateRelease(movie, 'movie')) || [];
|
if (release.movies) curatedRelease.movies = release.movies.filter(Boolean).map(({ movie }) => curateRelease(movie));
|
||||||
curatedRelease.series = release.series?.filter(Boolean).map(({ serie }) => curateRelease(serie, 'serie')) || [];
|
if (release.chapters) curatedRelease.chapters = release.chapters.filter(Boolean).map((chapter) => curateRelease(chapter));
|
||||||
curatedRelease.chapters = release.chapters?.filter(Boolean).map((chapter) => curateRelease(chapter)) || [];
|
if (release.photos) curatedRelease.photos = release.photos.filter(Boolean).map((photo) => photo.media || photo);
|
||||||
curatedRelease.photos = release.photos?.filter(Boolean).map((photo) => photo.media || photo) || [];
|
if (release.covers) curatedRelease.covers = release.covers.filter(Boolean).map(({ media }) => media);
|
||||||
curatedRelease.scenesPhotos = release.scenesPhotos?.filter(Boolean).map((photo) => photo.media || photo) || [];
|
|
||||||
curatedRelease.covers = release.covers?.filter(Boolean).map(({ media }) => media) || [];
|
|
||||||
|
|
||||||
if (release.trailer) curatedRelease.trailer = release.trailer.media;
|
if (release.trailer) curatedRelease.trailer = release.trailer.media;
|
||||||
if (release.teaser) curatedRelease.teaser = release.teaser.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));
|
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.tags) curatedEntity.tags = entity.tags.map(({ tag }) => tag);
|
||||||
if (entity.sceneTags) curatedEntity.sceneTags = entity.sceneTags;
|
|
||||||
|
|
||||||
if (entity.children) {
|
if (entity.children) {
|
||||||
if (entity.children.nodes) {
|
if (entity.children.nodes) {
|
||||||
|
|||||||
@@ -41,11 +41,6 @@ function initEntitiesActions(store, router) {
|
|||||||
slug
|
slug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
sceneTags {
|
|
||||||
id
|
|
||||||
name
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
children: childEntitiesConnection(
|
children: childEntitiesConnection(
|
||||||
orderBy: [PRIORITY_DESC, NAME_ASC],
|
orderBy: [PRIORITY_DESC, NAME_ASC],
|
||||||
filter: {
|
filter: {
|
||||||
@@ -101,7 +96,7 @@ function initEntitiesActions(store, router) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
effectiveDate: {
|
date: {
|
||||||
lessThan: $before,
|
lessThan: $before,
|
||||||
greaterThan: $after
|
greaterThan: $after
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -442,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 = `
|
const releaseFragment = `
|
||||||
release(id: $releaseId) {
|
release(id: $releaseId) {
|
||||||
id
|
id
|
||||||
@@ -559,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
|
isFavorited
|
||||||
isStashed(includeFavorites: false)
|
isStashed(includeFavorites: false)
|
||||||
stashes: stashesScenesBySceneId(
|
stashes: stashesScenesBySceneId(
|
||||||
@@ -660,8 +624,6 @@ export {
|
|||||||
actorFields,
|
actorFields,
|
||||||
actorStashesFields,
|
actorStashesFields,
|
||||||
campaignsFragment,
|
campaignsFragment,
|
||||||
mediaFields,
|
|
||||||
mediaFragment,
|
|
||||||
movieFields,
|
movieFields,
|
||||||
releaseActorsFragment,
|
releaseActorsFragment,
|
||||||
releaseFields,
|
releaseFields,
|
||||||
|
|||||||
@@ -7,22 +7,22 @@ const dateRanges = {
|
|||||||
latest: () => ({
|
latest: () => ({
|
||||||
after: '1900-01-01',
|
after: '1900-01-01',
|
||||||
before: dayjs.utc().toDate(),
|
before: dayjs.utc().toDate(),
|
||||||
orderBy: ['EFFECTIVE_DATE_DESC'],
|
orderBy: ['DATE_DESC'],
|
||||||
}),
|
}),
|
||||||
upcoming: () => ({
|
upcoming: () => ({
|
||||||
after: dayjs.utc().toDate(),
|
after: dayjs.utc().toDate(),
|
||||||
before: '2100-01-01',
|
before: '2100-01-01',
|
||||||
orderBy: ['EFFECTIVE_DATE_DESC'],
|
orderBy: ['DATE_DESC'],
|
||||||
}),
|
}),
|
||||||
new: () => ({
|
new: () => ({
|
||||||
after: '1900-01-01 00:00:00',
|
after: '1900-01-01 00:00:00',
|
||||||
before: '2100-01-01',
|
before: '2100-01-01',
|
||||||
orderBy: ['CREATED_AT_DESC', 'EFFECTIVE_DATE_ASC'],
|
orderBy: ['CREATED_AT_DESC', 'DATE_ASC'],
|
||||||
}),
|
}),
|
||||||
all: () => ({
|
all: () => ({
|
||||||
after: '1900-01-01',
|
after: '1900-01-01',
|
||||||
before: '2100-01-01',
|
before: '2100-01-01',
|
||||||
orderBy: ['EFFECTIVE_DATE_DESC'],
|
orderBy: ['DATE_DESC'],
|
||||||
}),
|
}),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ import {
|
|||||||
releaseFragment,
|
releaseFragment,
|
||||||
releaseFields,
|
releaseFields,
|
||||||
movieFields,
|
movieFields,
|
||||||
mediaFragment,
|
|
||||||
mediaFields,
|
|
||||||
} from '../fragments';
|
} from '../fragments';
|
||||||
import { curateRelease } from '../curate';
|
import { curateRelease } from '../curate';
|
||||||
import getDateRange from '../get-date-range';
|
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 release = await get(`/releases/${releaseId}`);
|
||||||
|
|
||||||
const result = await graphql(`
|
const { movie } = await graphql(`
|
||||||
query Movie(
|
query Movie(
|
||||||
$movieId: Int!
|
$movieId: Int!
|
||||||
$hasAuth: Boolean!
|
$hasAuth: Boolean!
|
||||||
$userId: Int
|
$userId: Int
|
||||||
) {
|
) {
|
||||||
${type}(id: $movieId) {
|
movie(id: $movieId) {
|
||||||
id
|
id
|
||||||
title
|
title
|
||||||
description
|
description
|
||||||
@@ -184,7 +182,7 @@ function initReleasesActions(store, router) {
|
|||||||
isS3
|
isS3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
poster: ${type === 'series' ? 'seriesPosterBySerieId' : 'moviesPoster'} {
|
poster: moviesPoster {
|
||||||
media {
|
media {
|
||||||
id
|
id
|
||||||
path
|
path
|
||||||
@@ -197,7 +195,7 @@ function initReleasesActions(store, router) {
|
|||||||
isS3
|
isS3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
covers: ${type === 'series' ? 'seriesCoversBySerieId' : 'moviesCovers'}(orderBy: MEDIA_BY_MEDIA_ID__INDEX_ASC) {
|
covers: moviesCovers(orderBy: MEDIA_BY_MEDIA_ID__INDEX_ASC) {
|
||||||
media {
|
media {
|
||||||
id
|
id
|
||||||
path
|
path
|
||||||
@@ -210,14 +208,14 @@ function initReleasesActions(store, router) {
|
|||||||
isS3
|
isS3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
trailer: ${type === 'series' ? 'seriesTrailerBySerieId' : 'moviesTrailer'} {
|
trailer: moviesTrailer {
|
||||||
media {
|
media {
|
||||||
id
|
id
|
||||||
path
|
path
|
||||||
isS3
|
isS3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
scenes: ${type === 'series' ? 'seriesScenesBySerieId' : 'moviesScenes'} {
|
scenes: moviesScenes {
|
||||||
scene {
|
scene {
|
||||||
${releaseFields}
|
${releaseFields}
|
||||||
}
|
}
|
||||||
@@ -227,11 +225,25 @@ function initReleasesActions(store, router) {
|
|||||||
slug
|
slug
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
photos: ${type === 'series' ? 'seriesPhotosBySerieId' : 'moviesPhotos'} {
|
photos {
|
||||||
${mediaFragment}
|
id
|
||||||
|
index
|
||||||
|
path
|
||||||
|
thumbnail
|
||||||
|
lazy
|
||||||
|
width
|
||||||
|
height
|
||||||
|
thumbnailWidth
|
||||||
|
thumbnailHeight
|
||||||
|
isS3
|
||||||
|
comment
|
||||||
|
sfw: sfwMedia {
|
||||||
|
id
|
||||||
|
thumbnail
|
||||||
|
lazy
|
||||||
|
path
|
||||||
|
comment
|
||||||
}
|
}
|
||||||
scenesPhotos {
|
|
||||||
${mediaFields}
|
|
||||||
}
|
}
|
||||||
entity {
|
entity {
|
||||||
id
|
id
|
||||||
@@ -247,7 +259,7 @@ function initReleasesActions(store, router) {
|
|||||||
hasLogo
|
hasLogo
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
stashes: ${type === 'series' ? 'stashesSeriesBySerieId' : 'stashesMovies'}(
|
stashes: stashesMovies(
|
||||||
filter: {
|
filter: {
|
||||||
stash: {
|
stash: {
|
||||||
userId: {
|
userId: {
|
||||||
@@ -271,20 +283,12 @@ function initReleasesActions(store, router) {
|
|||||||
userId: store.state.auth.user?.id,
|
userId: store.state.auth.user?.id,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!result[type]) {
|
if (!movie) {
|
||||||
router.replace('/not-found');
|
router.replace('/not-found');
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
return curateRelease(result[type]);
|
return curateRelease(movie);
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchMovieById(context, movieId) {
|
|
||||||
return fetchCollectionById(context, movieId, 'movie');
|
|
||||||
}
|
|
||||||
|
|
||||||
async function fetchSerieById(context, serieId) {
|
|
||||||
return fetchCollectionById(context, serieId, 'series');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -292,7 +296,6 @@ function initReleasesActions(store, router) {
|
|||||||
fetchReleaseById,
|
fetchReleaseById,
|
||||||
fetchMovies,
|
fetchMovies,
|
||||||
fetchMovieById,
|
fetchMovieById,
|
||||||
fetchSerieById,
|
|
||||||
searchMovies,
|
searchMovies,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,11 +71,6 @@ const routes = [
|
|||||||
component: Release,
|
component: Release,
|
||||||
name: 'movie',
|
name: 'movie',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
path: '/serie/:releaseId/:releaseSlug?',
|
|
||||||
component: Release,
|
|
||||||
name: 'serie',
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
path: '/actor/:actorId/:actorSlug',
|
path: '/actor/:actorId/:actorSlug',
|
||||||
name: 'actor',
|
name: 'actor',
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
exports.up = async (knex) => knex.raw(`
|
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)
|
SELECT COUNT(id)
|
||||||
FROM releases
|
FROM releases
|
||||||
WHERE releases.entity_id = entity.id;
|
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;
|
|
||||||
`);
|
|
||||||
23
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.212.9",
|
"version": "1.209.4",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.212.9",
|
"version": "1.209.4",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@casl/ability": "^5.2.2",
|
"@casl/ability": "^5.2.2",
|
||||||
@@ -11650,25 +11650,6 @@
|
|||||||
"webidl-conversions": "^3.0.0"
|
"webidl-conversions": "^3.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/node-fetch/node_modules/tr46": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
|
||||||
"integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o="
|
|
||||||
},
|
|
||||||
"node_modules/node-fetch/node_modules/webidl-conversions": {
|
|
||||||
"version": "3.0.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
|
||||||
"integrity": "sha1-JFNCdeKnvGvnvIZhHMFq4KVlSHE="
|
|
||||||
},
|
|
||||||
"node_modules/node-fetch/node_modules/whatwg-url": {
|
|
||||||
"version": "5.0.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
|
|
||||||
"integrity": "sha1-lmRU6HZUYuN2RNNib2dCzotwll0=",
|
|
||||||
"dependencies": {
|
|
||||||
"tr46": "~0.0.3",
|
|
||||||
"webidl-conversions": "^3.0.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/node-gyp": {
|
"node_modules/node-gyp": {
|
||||||
"version": "7.1.2",
|
"version": "7.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.212.9",
|
"version": "1.209.4",
|
||||||
"description": "All the latest porn releases in one place",
|
"description": "All the latest porn releases in one place",
|
||||||
"main": "src/app.js",
|
"main": "src/app.js",
|
||||||
"scripts": {
|
"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: 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.',
|
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: {
|
parameters: {
|
||||||
actorPath: 'modelprofile',
|
actorPath: 'modelprofile',
|
||||||
forceDeep: true, // Digital Playground has movie and series information not available in the latest updates API
|
|
||||||
},
|
},
|
||||||
parent: 'mindgeek',
|
parent: 'mindgeek',
|
||||||
},
|
},
|
||||||
@@ -412,9 +411,6 @@ const networks = [
|
|||||||
url: 'https://www.milehighmedia.com',
|
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!',
|
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',
|
parent: 'mindgeek',
|
||||||
parameters: {
|
|
||||||
forceDeep: true, // Mile High Media has movie and series information not available in the latest updates API
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
slug: 'mofos',
|
slug: 'mofos',
|
||||||
|
|||||||
@@ -810,13 +810,6 @@ const sites = [
|
|||||||
parameters: { siteId: 3261 },
|
parameters: { siteId: 3261 },
|
||||||
parent: 'bang',
|
parent: 'bang',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
name: 'Bang! Podcast',
|
|
||||||
slug: 'bangpodcast',
|
|
||||||
url: 'https://www.bang.com/videos?in=bang!%20podcast',
|
|
||||||
parameters: { siteId: 6305 },
|
|
||||||
parent: 'bang',
|
|
||||||
},
|
|
||||||
// BANGBROS
|
// BANGBROS
|
||||||
{
|
{
|
||||||
name: 'Ass Parade',
|
name: 'Ass Parade',
|
||||||
@@ -2653,7 +2646,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'digitalplayground',
|
slug: 'digitalplayground',
|
||||||
name: 'Digital Playground',
|
name: 'Digital Playground',
|
||||||
url: 'https://www.digitalplayground.com',
|
url: 'https://www.digitalplayground.com/scenes',
|
||||||
description: '',
|
description: '',
|
||||||
parameters: { extract: true },
|
parameters: { extract: true },
|
||||||
parent: 'digitalplayground',
|
parent: 'digitalplayground',
|
||||||
@@ -2687,13 +2680,6 @@ const sites = [
|
|||||||
description: '',
|
description: '',
|
||||||
parent: 'digitalplayground',
|
parent: 'digitalplayground',
|
||||||
},
|
},
|
||||||
{
|
|
||||||
slug: 'dpstarsexchallenges',
|
|
||||||
name: 'DP Star Sex Challenges',
|
|
||||||
url: 'https://www.digitalplayground.com/scenes?site=210',
|
|
||||||
parent: 'digitalplayground',
|
|
||||||
hasLogo: false,
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
slug: 'blockbuster',
|
slug: 'blockbuster',
|
||||||
name: 'Blockbuster',
|
name: 'Blockbuster',
|
||||||
@@ -5278,7 +5264,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'bigdicksatschool',
|
slug: 'bigdicksatschool',
|
||||||
name: 'Big Dicks At School',
|
name: 'Big Dicks At School',
|
||||||
url: 'https://www.men.com/scenes?site=252',
|
url: 'https://www.bigdicksatschool.com',
|
||||||
description: '',
|
description: '',
|
||||||
parameters: { siteId: 252 },
|
parameters: { siteId: 252 },
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
@@ -5287,7 +5273,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'drillmyhole',
|
slug: 'drillmyhole',
|
||||||
name: 'Drill My Hole',
|
name: 'Drill My Hole',
|
||||||
url: 'https://www.men.com/scenes?site=253',
|
url: 'https://www.drillmyhole.com',
|
||||||
description: '',
|
description: '',
|
||||||
parameters: { siteId: 253 },
|
parameters: { siteId: 253 },
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
@@ -5296,7 +5282,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'str8togay',
|
slug: 'str8togay',
|
||||||
name: 'Str8 to Gay',
|
name: 'Str8 to Gay',
|
||||||
url: 'https://www.men.com/scenes?site=254',
|
url: 'https://www.str8togay.com',
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
parameters: { siteId: 254 },
|
parameters: { siteId: 254 },
|
||||||
parent: 'men',
|
parent: 'men',
|
||||||
@@ -5304,7 +5290,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'thegayoffice',
|
slug: 'thegayoffice',
|
||||||
name: 'The Gay Office',
|
name: 'The Gay Office',
|
||||||
url: 'https://www.men.com/scenes?site=255',
|
url: 'https://www.thegayoffice.com',
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
parameters: { siteId: 255 },
|
parameters: { siteId: 255 },
|
||||||
parent: 'men',
|
parent: 'men',
|
||||||
@@ -5312,7 +5298,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'jizzorgy',
|
slug: 'jizzorgy',
|
||||||
name: 'Jizz Orgy',
|
name: 'Jizz Orgy',
|
||||||
url: 'https://www.men.com/scenes?site=256',
|
url: 'https://www.jizzorgy.com',
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
parameters: { siteId: 256 },
|
parameters: { siteId: 256 },
|
||||||
parent: 'men',
|
parent: 'men',
|
||||||
@@ -5320,7 +5306,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'menofuk',
|
slug: 'menofuk',
|
||||||
name: 'Men of UK',
|
name: 'Men of UK',
|
||||||
url: 'https://www.men.com/scenes?site=258',
|
url: 'https://www.menofuk.com',
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
parameters: { siteId: 258 },
|
parameters: { siteId: 258 },
|
||||||
parent: 'men',
|
parent: 'men',
|
||||||
@@ -5328,7 +5314,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'toptobottom',
|
slug: 'toptobottom',
|
||||||
name: 'Top to Bottom',
|
name: 'Top to Bottom',
|
||||||
url: 'https://www.men.com/scenes?site=259',
|
url: 'https://www.toptobottom.com',
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
parameters: { siteId: 259 },
|
parameters: { siteId: 259 },
|
||||||
parent: 'men',
|
parent: 'men',
|
||||||
@@ -5336,7 +5322,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'godsofmen',
|
slug: 'godsofmen',
|
||||||
name: 'Gods of Men',
|
name: 'Gods of Men',
|
||||||
url: 'https://www.men.com/scenes?site=260',
|
url: 'https://www.godsofmen.com',
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
parameters: { siteId: 260 },
|
parameters: { siteId: 260 },
|
||||||
parent: 'men',
|
parent: 'men',
|
||||||
@@ -5427,10 +5413,7 @@ const sites = [
|
|||||||
name: 'Doghouse Digital',
|
name: 'Doghouse Digital',
|
||||||
url: 'https://www.doghousedigital.com',
|
url: 'https://www.doghousedigital.com',
|
||||||
alias: ['dhd'],
|
alias: ['dhd'],
|
||||||
parameters: {
|
parameters: { siteId: 321 },
|
||||||
siteId: 321,
|
|
||||||
native: true,
|
|
||||||
},
|
|
||||||
parent: 'milehighmedia',
|
parent: 'milehighmedia',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5446,10 +5429,7 @@ const sites = [
|
|||||||
name: 'Reality Junkies',
|
name: 'Reality Junkies',
|
||||||
url: 'https://www.realityjunkies.com',
|
url: 'https://www.realityjunkies.com',
|
||||||
alias: ['rj'],
|
alias: ['rj'],
|
||||||
parameters: {
|
parameters: { siteId: 324 },
|
||||||
siteId: 324,
|
|
||||||
native: true,
|
|
||||||
},
|
|
||||||
parent: 'milehighmedia',
|
parent: 'milehighmedia',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5457,10 +5437,7 @@ const sites = [
|
|||||||
name: 'Sweetheart Video',
|
name: 'Sweetheart Video',
|
||||||
url: 'https://www.sweetheartvideo.com',
|
url: 'https://www.sweetheartvideo.com',
|
||||||
alias: ['shv'],
|
alias: ['shv'],
|
||||||
parameters: {
|
parameters: { siteId: 325 },
|
||||||
siteId: 325,
|
|
||||||
native: true,
|
|
||||||
},
|
|
||||||
parent: 'milehighmedia',
|
parent: 'milehighmedia',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5468,10 +5445,7 @@ const sites = [
|
|||||||
name: 'Sweet Sinner',
|
name: 'Sweet Sinner',
|
||||||
url: 'https://www.sweetsinner.com',
|
url: 'https://www.sweetsinner.com',
|
||||||
alias: ['ss'],
|
alias: ['ss'],
|
||||||
parameters: {
|
parameters: { siteId: 326 },
|
||||||
siteId: 326,
|
|
||||||
native: true,
|
|
||||||
},
|
|
||||||
parent: 'milehighmedia',
|
parent: 'milehighmedia',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5480,10 +5454,7 @@ const sites = [
|
|||||||
alias: ['fs'],
|
alias: ['fs'],
|
||||||
tags: ['family'],
|
tags: ['family'],
|
||||||
url: 'https://www.familysinners.com',
|
url: 'https://www.familysinners.com',
|
||||||
parameters: {
|
parameters: { siteId: 317 },
|
||||||
siteId: 317,
|
|
||||||
native: true,
|
|
||||||
},
|
|
||||||
parent: 'milehighmedia',
|
parent: 'milehighmedia',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -5492,10 +5463,7 @@ const sites = [
|
|||||||
url: 'https://www.iconmale.com',
|
url: 'https://www.iconmale.com',
|
||||||
alias: ['im'],
|
alias: ['im'],
|
||||||
tags: ['gay'],
|
tags: ['gay'],
|
||||||
parameters: {
|
parameters: { native: true, siteId: 328 },
|
||||||
siteId: 328,
|
|
||||||
native: true,
|
|
||||||
},
|
|
||||||
parent: 'milehighmedia',
|
parent: 'milehighmedia',
|
||||||
},
|
},
|
||||||
// MOFOS
|
// MOFOS
|
||||||
@@ -8611,10 +8579,7 @@ const sites = [
|
|||||||
name: 'Dane Jones',
|
name: 'Dane Jones',
|
||||||
alias: ['dnj'],
|
alias: ['dnj'],
|
||||||
url: 'https://www.danejones.com/',
|
url: 'https://www.danejones.com/',
|
||||||
parameters: {
|
parameters: { siteId: 290 },
|
||||||
siteId: 290,
|
|
||||||
native: true,
|
|
||||||
},
|
|
||||||
parent: 'sexyhub',
|
parent: 'sexyhub',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@@ -8622,10 +8587,7 @@ const sites = [
|
|||||||
name: 'Lesbea',
|
name: 'Lesbea',
|
||||||
alias: ['lsb'],
|
alias: ['lsb'],
|
||||||
url: 'https://www.lesbea.com',
|
url: 'https://www.lesbea.com',
|
||||||
parameters: {
|
parameters: { siteId: 291 },
|
||||||
siteId: 291,
|
|
||||||
native: true,
|
|
||||||
},
|
|
||||||
tags: ['lesbian'],
|
tags: ['lesbian'],
|
||||||
parent: 'sexyhub',
|
parent: 'sexyhub',
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -727,6 +727,8 @@ const tagMedia = [
|
|||||||
['da-tp', 7, 'Polly Petrova in YE069', 'analvids'],
|
['da-tp', 7, 'Polly Petrova in YE069', 'analvids'],
|
||||||
['da-tp', 5, 'Venera Maxima in GIO1287'],
|
['da-tp', 5, 'Venera Maxima in GIO1287'],
|
||||||
['da-tp', 6, 'Adriana Chechik in "Gangbang Me"', 'hardx'],
|
['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', 7, 'Adriana Chechik in "DP Masters 6"', 'julesjordan'],
|
||||||
['dap', 10, 'Kira Noir', 'hardx'],
|
['dap', 10, 'Kira Noir', 'hardx'],
|
||||||
['dap', 'emily_pink_legalporno', 'Emily Pink', 'analvids'],
|
['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'],
|
['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', 1, 'Chloe Lamour in "Curives In All The Right Places"', 'wetandpuffy'],
|
||||||
['toys', 'shawna_lenee_sunrisekings', 'Shawna Lenee', 'sunrisekings'],
|
['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', 'angela_white_julesjordan', 'Angela White in "Her Biggest Gangbang Ever"', 'julesjordan'],
|
||||||
['triple-penetration', 'ria_sunn_legalporno', 'Ria Sunn in SZ2082', 'analvids'],
|
['triple-penetration', 'ria_sunn_legalporno', 'Ria Sunn in SZ2082', 'analvids'],
|
||||||
['tvp', 'september_reign_wefuckblackgirls', 'September Reign in "Second Appearance"', 'wefuckblackgirls'],
|
['tvp', 'september_reign_wefuckblackgirls', 'September Reign in "Second Appearance"', 'wefuckblackgirls'],
|
||||||
|
|||||||
@@ -14,6 +14,6 @@
|
|||||||
"prefer-destructuring": "off",
|
"prefer-destructuring": "off",
|
||||||
"template-curly-spacing": "off",
|
"template-curly-spacing": "off",
|
||||||
"object-curly-newline": "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 argv = require('./argv');
|
||||||
const include = require('./utils/argv-include')(argv);
|
const include = require('./utils/argv-include')(argv);
|
||||||
const bulkInsert = require('./utils/bulk-insert');
|
const bulkInsert = require('./utils/bulk-insert');
|
||||||
const chunk = require('./utils/chunk');
|
|
||||||
const logger = require('./logger')(__filename);
|
const logger = require('./logger')(__filename);
|
||||||
|
|
||||||
const { toBaseReleases } = require('./deep');
|
const { toBaseReleases } = require('./deep');
|
||||||
@@ -1049,8 +1048,7 @@ async function flushProfiles(actorIdsOrNames) {
|
|||||||
logger.info(`Removed ${deleteCount} profiles`);
|
logger.info(`Removed ${deleteCount} profiles`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteActors(allActorIdsOrNames) {
|
async function deleteActors(actorIdsOrNames) {
|
||||||
const deleteCounts = await Promise.map(chunk(allActorIdsOrNames), async (actorIdsOrNames) => {
|
|
||||||
const actors = await knex('actors')
|
const actors = await knex('actors')
|
||||||
.whereIn('id', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'number'))
|
.whereIn('id', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'number'))
|
||||||
.orWhere((builder) => {
|
.orWhere((builder) => {
|
||||||
@@ -1074,17 +1072,9 @@ async function deleteActors(allActorIdsOrNames) {
|
|||||||
.delete(),
|
.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);
|
|
||||||
|
|
||||||
await flushOrphanedMedia();
|
await flushOrphanedMedia();
|
||||||
|
|
||||||
logger.info(`Removed ${deletedActorsCount} actors with ${deletedScenesCount} scenes`);
|
logger.info(`Removed ${deletedActorsCount} actors with ${deletedScenesCount} scenes`);
|
||||||
|
|
||||||
return deletedActorsCount;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async function flushActors() {
|
async function flushActors() {
|
||||||
|
|||||||
17
src/app.js
@@ -85,23 +85,6 @@ async function startMemorySample(snapshotTriggers = []) {
|
|||||||
}, config.memorySampling.sampleDuration);
|
}, config.memorySampling.sampleDuration);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function startMemorySample() {
|
|
||||||
await inspector.heap.enable();
|
|
||||||
await inspector.heap.startSampling();
|
|
||||||
|
|
||||||
// monitorMemory();
|
|
||||||
|
|
||||||
logger.info(`Start heap sampling, memory usage: ${process.memoryUsage.rss() / 1000000} MB`);
|
|
||||||
|
|
||||||
setTimeout(async () => {
|
|
||||||
await stopMemorySample();
|
|
||||||
|
|
||||||
if (!done) {
|
|
||||||
await startMemorySample();
|
|
||||||
}
|
|
||||||
}, 30000);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
try {
|
try {
|
||||||
if (argv.server) {
|
if (argv.server) {
|
||||||
|
|||||||
@@ -238,7 +238,6 @@ const { argv } = yargs
|
|||||||
default: false,
|
default: false,
|
||||||
})
|
})
|
||||||
.option('level', {
|
.option('level', {
|
||||||
alias: 'log-level',
|
|
||||||
describe: 'Log level',
|
describe: 'Log level',
|
||||||
type: 'string',
|
type: 'string',
|
||||||
default: process.env.NODE_ENV === 'development' ? 'silly' : 'info',
|
default: process.env.NODE_ENV === 'development' ? 'silly' : 'info',
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ const inquirer = require('inquirer');
|
|||||||
const logger = require('./logger')(__filename);
|
const logger = require('./logger')(__filename);
|
||||||
const argv = require('./argv');
|
const argv = require('./argv');
|
||||||
const knex = require('./knex');
|
const knex = require('./knex');
|
||||||
const { deleteScenes, deleteMovies, deleteSeries } = require('./releases');
|
const { deleteScenes, deleteMovies } = require('./releases');
|
||||||
const { flushOrphanedMedia } = require('./media');
|
const { flushOrphanedMedia } = require('./media');
|
||||||
const { resolveScraper, resolveLayoutScraper } = require('./scrapers/resolve');
|
const { resolveScraper, resolveLayoutScraper } = require('./scrapers/resolve');
|
||||||
|
|
||||||
@@ -359,39 +359,29 @@ async function flushEntities(networkSlugs = [], channelSlugs = []) {
|
|||||||
.leftJoin('movies', 'movies.entity_id', 'selected_entities.id')
|
.leftJoin('movies', 'movies.entity_id', 'selected_entities.id')
|
||||||
.pluck('movies.id');
|
.pluck('movies.id');
|
||||||
|
|
||||||
const serieIds = await entityQuery
|
if (sceneIds.length === 0 && movieIds.length === 0) {
|
||||||
.clone()
|
logger.info(`No scenes or movies found to remove for ${entitySlugs}`);
|
||||||
.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}`);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const confirmed = await inquirer.prompt([{
|
const confirmed = await inquirer.prompt([{
|
||||||
type: 'confirm',
|
type: 'confirm',
|
||||||
name: 'flushEntities',
|
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,
|
default: false,
|
||||||
}]);
|
}]);
|
||||||
|
|
||||||
if (!confirmed.flushEntities) {
|
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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const [deletedScenesCount, deletedMoviesCount, deletedSeriesCount] = await Promise.all([
|
const [deletedScenesCount, deletedMoviesCount] = await Promise.all([
|
||||||
deleteScenes(sceneIds),
|
deleteScenes(sceneIds),
|
||||||
deleteMovies(movieIds),
|
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();
|
await flushOrphanedMedia();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -961,12 +961,9 @@ async function flushOrphanedMedia() {
|
|||||||
await deleteS3Objects(orphanedMedia.filter((media) => media.is_s3));
|
await deleteS3Objects(orphanedMedia.filter((media) => media.is_s3));
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
|
||||||
await fsPromises.rm(path.join(config.media.path, 'temp'), { recursive: true });
|
await fsPromises.rm(path.join(config.media.path, 'temp'), { recursive: true });
|
||||||
|
|
||||||
logger.info('Cleared temporary media directory');
|
logger.info('Cleared temporary media directory');
|
||||||
} catch (error) {
|
|
||||||
logger.warn(`Failed to clear temporary media directory: ${error.message}`);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -325,24 +325,6 @@ async function deleteMovies(movieIds) {
|
|||||||
return deleteCount;
|
return deleteCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteSeries(serieIds) {
|
|
||||||
if (serieIds.length === 0) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
await knex('series_scenes')
|
|
||||||
.whereIn('serie_id', serieIds)
|
|
||||||
.delete();
|
|
||||||
|
|
||||||
const deleteCount = await knex('series')
|
|
||||||
.whereIn('id', serieIds)
|
|
||||||
.delete();
|
|
||||||
|
|
||||||
logger.info(`Removed ${deleteCount}/${serieIds.length} series`);
|
|
||||||
|
|
||||||
return deleteCount;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function flushScenes() {
|
async function flushScenes() {
|
||||||
const sceneIds = await knex('releases').select('id').pluck('id');
|
const sceneIds = await knex('releases').select('id').pluck('id');
|
||||||
|
|
||||||
@@ -385,27 +367,6 @@ async function flushMovies() {
|
|||||||
logger.info(`Removed ${deleteCount}/${movieIds.length} movies`);
|
logger.info(`Removed ${deleteCount}/${movieIds.length} movies`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function flushSeries() {
|
|
||||||
const serieIds = await knex('series').select('id').pluck('id');
|
|
||||||
|
|
||||||
const confirmed = await inquirer.prompt([{
|
|
||||||
type: 'confirm',
|
|
||||||
name: 'flushSeries',
|
|
||||||
message: `You are about to remove ${serieIds.length} series. Are you sure?`,
|
|
||||||
default: false,
|
|
||||||
}]);
|
|
||||||
|
|
||||||
if (!confirmed.flushSeries) {
|
|
||||||
logger.warn('Confirmation rejected, not flushing series');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const deleteCount = await deleteSeries(serieIds);
|
|
||||||
|
|
||||||
await flushOrphanedMedia();
|
|
||||||
|
|
||||||
logger.info(`Removed ${deleteCount}/${serieIds.length} series`);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function flushBatches(batchIds) {
|
async function flushBatches(batchIds) {
|
||||||
const [sceneIds, movieIds] = await Promise.all([
|
const [sceneIds, movieIds] = await Promise.all([
|
||||||
knex('releases')
|
knex('releases')
|
||||||
@@ -446,10 +407,8 @@ module.exports = {
|
|||||||
fetchScenes,
|
fetchScenes,
|
||||||
flushBatches,
|
flushBatches,
|
||||||
flushMovies,
|
flushMovies,
|
||||||
flushSeries,
|
|
||||||
flushScenes,
|
flushScenes,
|
||||||
searchScenes,
|
searchScenes,
|
||||||
deleteScenes,
|
deleteScenes,
|
||||||
deleteMovies,
|
deleteMovies,
|
||||||
deleteSeries,
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -11,12 +11,6 @@ const slugify = require('../utils/slugify');
|
|||||||
const http = require('../utils/http');
|
const http = require('../utils/http');
|
||||||
const { inchesToCm, lbsToKg } = require('../utils/convert');
|
const { inchesToCm, lbsToKg } = require('../utils/convert');
|
||||||
|
|
||||||
function getBasePath(channel, path = '/scene') {
|
|
||||||
return channel.parameters?.scene
|
|
||||||
|| ((channel.parameters?.native || channel.type === 'network') && `${channel.url}${path}`)
|
|
||||||
|| `${channel.parent.url}${path}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getThumbs(scene) {
|
function getThumbs(scene) {
|
||||||
if (scene.images.poster) {
|
if (scene.images.poster) {
|
||||||
return Object.values(scene.images.poster) // can be { 0: {}, 1: {}, ... } instead of array
|
return Object.values(scene.images.poster) // can be { 0: {}, 1: {}, ... } instead of array
|
||||||
@@ -24,7 +18,7 @@ function getThumbs(scene) {
|
|||||||
.map((image) => image.xl.url);
|
.map((image) => image.xl.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Array.isArray(scene.images.card_main_rect)) {
|
if (scene.images.card_main_rect) {
|
||||||
return scene.images.card_main_rect
|
return scene.images.card_main_rect
|
||||||
.concat(scene.images.card_secondary_rect || [])
|
.concat(scene.images.card_secondary_rect || [])
|
||||||
.map((image) => image.xl.url.replace('.thumb', ''));
|
.map((image) => image.xl.url.replace('.thumb', ''));
|
||||||
@@ -33,28 +27,6 @@ function getThumbs(scene) {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
function getCovers(images, target = 'cover') {
|
|
||||||
if (!images[target]) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const covers = [
|
|
||||||
images[target][0].md?.url,
|
|
||||||
images[target][0].sm?.url,
|
|
||||||
images[target][0].xs?.url,
|
|
||||||
// bigger but usually upscaled
|
|
||||||
images[target][0].xx?.url,
|
|
||||||
images[target][0].xl?.url,
|
|
||||||
images[target][0].lg?.url,
|
|
||||||
];
|
|
||||||
|
|
||||||
if (target === 'poster') {
|
|
||||||
return covers;
|
|
||||||
}
|
|
||||||
|
|
||||||
return [covers];
|
|
||||||
}
|
|
||||||
|
|
||||||
function getVideos(data) {
|
function getVideos(data) {
|
||||||
const teaserSources = data.videos.mediabook?.files;
|
const teaserSources = data.videos.mediabook?.files;
|
||||||
const trailerSources = data.children.find((child) => child.type === 'trailer')?.videos.full?.files;
|
const trailerSources = data.children.find((child) => child.type === 'trailer')?.videos.full?.files;
|
||||||
@@ -79,7 +51,9 @@ function scrapeLatestX(data, site, filterChannel) {
|
|||||||
description: data.description,
|
description: data.description,
|
||||||
};
|
};
|
||||||
|
|
||||||
const basepath = getBasePath(site);
|
const basepath = site.parameters?.scene
|
||||||
|
|| (site.parameters?.native && `${site.url}/scene`)
|
||||||
|
|| `${site.parent.url}/scene`;
|
||||||
|
|
||||||
release.url = `${basepath}/${release.entryId}/${slugify(release.title)}`;
|
release.url = `${basepath}/${release.entryId}/${slugify(release.title)}`;
|
||||||
release.date = new Date(data.dateReleased);
|
release.date = new Date(data.dateReleased);
|
||||||
@@ -110,9 +84,6 @@ function scrapeLatestX(data, site, filterChannel) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const siteName = data.collections[0]?.name || data.brand;
|
|
||||||
release.channel = slugify(siteName, '');
|
|
||||||
|
|
||||||
return release;
|
return release;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,7 +96,7 @@ async function scrapeLatest(items, site, filterChannel) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrapeRelease(data, url, channel, networkName) {
|
function scrapeScene(data, url, _site, networkName) {
|
||||||
const release = {};
|
const release = {};
|
||||||
|
|
||||||
const { id: entryId, title, description } = data;
|
const { id: entryId, title, description } = data;
|
||||||
@@ -158,29 +129,6 @@ function scrapeRelease(data, url, channel, networkName) {
|
|||||||
|
|
||||||
release.url = url || `https://www.${networkName || data.brand}.com/scene/${entryId}/`;
|
release.url = url || `https://www.${networkName || data.brand}.com/scene/${entryId}/`;
|
||||||
|
|
||||||
if (data.parent?.type === 'movie' || data.parent?.type === 'serie') {
|
|
||||||
release[data.parent.type] = {
|
|
||||||
entryId: data.parent.id,
|
|
||||||
url: `${getBasePath(channel, data.parent.type === 'movie' ? '/movie' : '/series')}/${data.parent.id}/${slugify(data.parent.title, '-', { removePunctuation: true })}`,
|
|
||||||
title: data.parent.title,
|
|
||||||
description: data.parent.description,
|
|
||||||
date: new Date(data.parent.dateReleased),
|
|
||||||
channel: slugify(data.parent.collections?.name || data.parent.brand),
|
|
||||||
poster: getCovers(data.parent.images, 'poster'),
|
|
||||||
shallow: true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.type === 'movie') {
|
|
||||||
release.covers = getCovers(data.images);
|
|
||||||
release.scenes = data.children?.map((scene) => ({
|
|
||||||
entryId: scene.id,
|
|
||||||
url: `${getBasePath(channel)}/${scene.id}/${slugify(scene.title)}`,
|
|
||||||
title: scene.title,
|
|
||||||
shallow: true,
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
return release;
|
return release;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -222,9 +170,6 @@ async function getSession(site, parameters, url) {
|
|||||||
|
|
||||||
const res = await http.get(sessionUrl, {
|
const res = await http.get(sessionUrl, {
|
||||||
session,
|
session,
|
||||||
headers: {
|
|
||||||
'Accept-Language': 'en-US,en;', // somehow seems essential for some MG sites
|
|
||||||
},
|
|
||||||
interval: parameters?.interval,
|
interval: parameters?.interval,
|
||||||
concurrency: parameters?.concurrency,
|
concurrency: parameters?.concurrency,
|
||||||
parse: false,
|
parse: false,
|
||||||
@@ -285,7 +230,7 @@ function scrapeProfile(data, html, releases = [], networkName) {
|
|||||||
profile.naturalBoobs = false;
|
profile.naturalBoobs = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
profile.releases = releases.map((release) => scrapeRelease(release, null, null, networkName));
|
profile.releases = releases.map((release) => scrapeScene(release, null, null, networkName));
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
@@ -313,7 +258,6 @@ async function fetchLatest(site, page = 1, options) {
|
|||||||
Instance: instanceToken,
|
Instance: instanceToken,
|
||||||
Origin: site.url,
|
Origin: site.url,
|
||||||
Referer: url,
|
Referer: url,
|
||||||
'Accept-Language': 'en-US,en;', // somehow seems essential for some MG sites
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -338,7 +282,6 @@ async function fetchUpcoming(site, page, options) {
|
|||||||
Instance: instanceToken,
|
Instance: instanceToken,
|
||||||
Origin: site.url,
|
Origin: site.url,
|
||||||
Referer: url,
|
Referer: url,
|
||||||
'Accept-Language': 'en-US,en;', // somehow seems essential for some MG sites
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -349,8 +292,8 @@ async function fetchUpcoming(site, page, options) {
|
|||||||
return res.statusCode;
|
return res.statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchRelease(url, site, baseScene, options) {
|
async function fetchScene(url, site, baseScene, options) {
|
||||||
if (baseScene?.entryId && !baseScene.shallow && !options.parameters.forceDeep) {
|
if (baseScene?.entryId) {
|
||||||
// overview and deep data is the same, don't hit server unnecessarily
|
// overview and deep data is the same, don't hit server unnecessarily
|
||||||
return baseScene;
|
return baseScene;
|
||||||
}
|
}
|
||||||
@@ -364,13 +307,12 @@ async function fetchRelease(url, site, baseScene, options) {
|
|||||||
concurrency: options.parameters.concurrency,
|
concurrency: options.parameters.concurrency,
|
||||||
headers: {
|
headers: {
|
||||||
Instance: instanceToken,
|
Instance: instanceToken,
|
||||||
'Accept-Language': 'en-US,en;', // somehow seems essential for some MG sites
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
if (res.status === 200 && res.body.result) {
|
if (res.status === 200 && res.body.result) {
|
||||||
return {
|
return {
|
||||||
scene: scrapeRelease(res.body.result, url, site),
|
scene: scrapeScene(res.body.result, url, site),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -387,7 +329,6 @@ async function fetchProfile({ name: actorName, slug: actorSlug }, { entity, para
|
|||||||
concurrency: parameters.concurrency,
|
concurrency: parameters.concurrency,
|
||||||
headers: {
|
headers: {
|
||||||
Instance: instanceToken,
|
Instance: instanceToken,
|
||||||
'Accept-Language': 'en-US,en;', // somehow seems essential for some MG sites
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -433,7 +374,6 @@ module.exports = {
|
|||||||
scrapeLatestX,
|
scrapeLatestX,
|
||||||
fetchLatest,
|
fetchLatest,
|
||||||
fetchUpcoming,
|
fetchUpcoming,
|
||||||
fetchScene: fetchRelease,
|
fetchScene,
|
||||||
fetchMovie: fetchRelease,
|
|
||||||
fetchProfile,
|
fetchProfile,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -142,7 +142,6 @@ async function getTrailer(scene, channel, url) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
async function getPhotosLegacy(url) {
|
async function getPhotosLegacy(url) {
|
||||||
const htmlRes = await http.get(url, {
|
const htmlRes = await http.get(url, {
|
||||||
extract: {
|
extract: {
|
||||||
@@ -170,7 +169,6 @@ async function getPhotosLegacy(url) {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
||||||
async function getPhotos(url) {
|
async function getPhotos(url) {
|
||||||
const htmlRes = await http.get(url, {
|
const htmlRes = await http.get(url, {
|
||||||
|
|||||||
@@ -146,7 +146,7 @@ function attachReleaseIds(releases, storedReleases, batchId) {
|
|||||||
|
|
||||||
const releasesWithId = releases.map((release) => {
|
const releasesWithId = releases.map((release) => {
|
||||||
if (!release.entity) {
|
if (!release.entity) {
|
||||||
logger.error(`No entity available for ${release.url}`);
|
logger.error(`No entitity available for ${release.url}`);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -315,142 +315,6 @@ async function storeChapters(releases) {
|
|||||||
await associateReleaseMedia(chaptersWithId, 'chapter');
|
await associateReleaseMedia(chaptersWithId, 'chapter');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function associateMovieScenes(movies, movieScenes) {
|
|
||||||
const moviesByEntityIdAndEntryId = movies.reduce((acc, movie) => ({
|
|
||||||
...acc,
|
|
||||||
[movie.entity.id]: {
|
|
||||||
...acc[movie.entity.id],
|
|
||||||
[movie.entryId]: movie,
|
|
||||||
},
|
|
||||||
}), {});
|
|
||||||
|
|
||||||
const associations = movieScenes.map((scene) => {
|
|
||||||
if (!scene.movie) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sceneMovie = moviesByEntityIdAndEntryId[scene.entity.id]?.[scene.movie.entryId]
|
|
||||||
|| moviesByEntityIdAndEntryId[scene.entity.parent?.id]?.[scene.movie.entryId];
|
|
||||||
|
|
||||||
if (sceneMovie?.id) {
|
|
||||||
return {
|
|
||||||
movie_id: sceneMovie.id,
|
|
||||||
scene_id: scene.id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}).filter(Boolean);
|
|
||||||
|
|
||||||
await bulkInsert('movies_scenes', associations, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function associateSerieScenes(series, serieScenes) {
|
|
||||||
const seriesByEntityIdAndEntryId = series.reduce((acc, serie) => ({
|
|
||||||
...acc,
|
|
||||||
[serie.entity.id]: {
|
|
||||||
...acc[serie.entity.id],
|
|
||||||
[serie.entryId]: serie,
|
|
||||||
},
|
|
||||||
}), {});
|
|
||||||
|
|
||||||
const associations = serieScenes.map((scene) => {
|
|
||||||
if (!scene.serie) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const sceneSerie = seriesByEntityIdAndEntryId[scene.entity.id]?.[scene.serie.entryId]
|
|
||||||
|| seriesByEntityIdAndEntryId[scene.entity.parent?.id]?.[scene.serie.entryId];
|
|
||||||
|
|
||||||
if (sceneSerie?.id) {
|
|
||||||
return {
|
|
||||||
serie_id: sceneSerie.id,
|
|
||||||
scene_id: scene.id,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}).filter(Boolean);
|
|
||||||
|
|
||||||
await bulkInsert('series_scenes', associations, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
async function updateMovieSearch(movieIds, target = 'movie') {
|
|
||||||
logger.info(`Updating search documents for ${movieIds ? movieIds.length : 'all' } ${target}s`);
|
|
||||||
|
|
||||||
const documents = await knex.raw(`
|
|
||||||
SELECT
|
|
||||||
${target}s.id AS ${target}_id,
|
|
||||||
TO_TSVECTOR(
|
|
||||||
'english',
|
|
||||||
COALESCE(${target}s.title, '') || ' ' ||
|
|
||||||
entities.name || ' ' ||
|
|
||||||
entities.slug || ' ' ||
|
|
||||||
COALESCE(array_to_string(entities.alias, ' '), '') || ' ' ||
|
|
||||||
COALESCE(parents.name, '') || ' ' ||
|
|
||||||
COALESCE(parents.slug, '') || ' ' ||
|
|
||||||
COALESCE(array_to_string(parents.alias, ' '), '') || ' ' ||
|
|
||||||
COALESCE(TO_CHAR(${target}s.date, 'YYYY YY MM FMMM FMMonth mon DD FMDD'), '') || ' ' ||
|
|
||||||
STRING_AGG(COALESCE(releases.title, ''), ' ') || ' ' ||
|
|
||||||
STRING_AGG(COALESCE(actors.name, ''), ' ') || ' ' ||
|
|
||||||
STRING_AGG(COALESCE(tags.name, ''), ' ')
|
|
||||||
) as document
|
|
||||||
FROM ${target}s
|
|
||||||
LEFT JOIN entities ON ${target}s.entity_id = entities.id
|
|
||||||
LEFT JOIN entities AS parents ON parents.id = entities.parent_id
|
|
||||||
LEFT JOIN ${target}s_scenes ON ${target}s_scenes.${target}_id = ${target}s.id
|
|
||||||
LEFT JOIN releases ON releases.id = ${target}s_scenes.scene_id
|
|
||||||
LEFT JOIN releases_actors ON releases_actors.release_id = ${target}s_scenes.scene_id
|
|
||||||
LEFT JOIN releases_tags ON releases_tags.release_id = releases.id
|
|
||||||
LEFT JOIN actors ON actors.id = releases_actors.actor_id
|
|
||||||
LEFT JOIN tags ON tags.id = releases_tags.tag_id
|
|
||||||
${movieIds ? `WHERE ${target}s.id = ANY(?)` : ''}
|
|
||||||
GROUP BY ${target}s.id, entities.name, entities.slug, entities.alias, parents.name, parents.slug, parents.alias;
|
|
||||||
`, movieIds && [movieIds]);
|
|
||||||
|
|
||||||
if (documents.rows?.length > 0) {
|
|
||||||
await bulkInsert(`${target}s_search`, documents.rows, [`${target}_id`]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async function storeMovies(movies, useBatchId) {
|
|
||||||
if (!movies || movies.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const { uniqueReleases } = await filterDuplicateReleases(movies);
|
|
||||||
const [batchId] = useBatchId ? [useBatchId] : await knex('batches').insert({ comment: null }).returning('id');
|
|
||||||
|
|
||||||
const curatedMovieEntries = await Promise.all(uniqueReleases.map((release) => curateReleaseEntry(release, batchId, null, 'movie')));
|
|
||||||
|
|
||||||
const storedMovies = await bulkInsert('movies', curatedMovieEntries, ['entity_id', 'entry_id'], true);
|
|
||||||
const moviesWithId = attachReleaseIds(movies, storedMovies);
|
|
||||||
|
|
||||||
await updateMovieSearch(moviesWithId.map((movie) => movie.id));
|
|
||||||
await associateReleaseMedia(moviesWithId, 'movie');
|
|
||||||
|
|
||||||
return moviesWithId;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function storeSeries(series, useBatchId) {
|
|
||||||
if (!series || series.length === 0) {
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
|
|
||||||
const { uniqueReleases } = await filterDuplicateReleases(series);
|
|
||||||
const [batchId] = useBatchId ? [useBatchId] : await knex('batches').insert({ comment: null }).returning('id');
|
|
||||||
|
|
||||||
const curatedSerieEntries = await Promise.all(uniqueReleases.map((release) => curateReleaseEntry(release, batchId, null, 'serie')));
|
|
||||||
|
|
||||||
const storedSeries = await bulkInsert('series', curatedSerieEntries, ['entity_id', 'entry_id'], true);
|
|
||||||
const seriesWithId = attachReleaseIds(series, storedSeries);
|
|
||||||
|
|
||||||
await updateMovieSearch(seriesWithId.map((serie) => serie.id), 'serie');
|
|
||||||
await associateReleaseMedia(seriesWithId, 'serie');
|
|
||||||
|
|
||||||
return seriesWithId;
|
|
||||||
}
|
|
||||||
|
|
||||||
async function storeScenes(releases, useBatchId) {
|
async function storeScenes(releases, useBatchId) {
|
||||||
if (!releases || releases.length === 0) {
|
if (!releases || releases.length === 0) {
|
||||||
return [];
|
return [];
|
||||||
@@ -491,14 +355,12 @@ async function storeScenes(releases, useBatchId) {
|
|||||||
scenes: JSON.stringify(duplicateReleasesWithId),
|
scenes: JSON.stringify(duplicateReleasesWithId),
|
||||||
});
|
});
|
||||||
|
|
||||||
const [actors, storedSeries] = await Promise.all([
|
const [actors] = await Promise.all([
|
||||||
associateActors(releasesWithId, batchId),
|
associateActors(releasesWithId, batchId),
|
||||||
storeSeries(releasesWithId.map((release) => release.serie && { ...release.serie, entity: release.entity }).filter(Boolean), batchId),
|
|
||||||
associateReleaseTags(releasesWithId),
|
associateReleaseTags(releasesWithId),
|
||||||
storeChapters(releasesWithId),
|
storeChapters(releasesWithId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
await associateSerieScenes(storedSeries, releasesWithId);
|
|
||||||
await associateDirectors(releasesWithId, batchId); // some directors may also be actors, don't associate at the same time
|
await associateDirectors(releasesWithId, batchId); // some directors may also be actors, don't associate at the same time
|
||||||
await updateSceneSearch(releasesWithId.map((release) => release.id));
|
await updateSceneSearch(releasesWithId.map((release) => release.id));
|
||||||
|
|
||||||
@@ -516,6 +378,92 @@ async function storeScenes(releases, useBatchId) {
|
|||||||
return releasesWithId;
|
return releasesWithId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function associateMovieScenes(movies, movieScenes) {
|
||||||
|
const moviesByEntityIdAndEntryId = movies.reduce((acc, movie) => ({
|
||||||
|
...acc,
|
||||||
|
[movie.entity.id]: {
|
||||||
|
...acc[movie.entity.id],
|
||||||
|
[movie.entryId]: movie,
|
||||||
|
},
|
||||||
|
}), {});
|
||||||
|
|
||||||
|
const associations = movieScenes.map((scene) => {
|
||||||
|
if (!scene.movie) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sceneMovie = moviesByEntityIdAndEntryId[scene.entity.id]?.[scene.movie.entryId];
|
||||||
|
|
||||||
|
if (sceneMovie?.id) {
|
||||||
|
return {
|
||||||
|
movie_id: sceneMovie.id,
|
||||||
|
scene_id: scene.id,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}).filter(Boolean);
|
||||||
|
|
||||||
|
await bulkInsert('movies_scenes', associations, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function updateMovieSearch(movieIds) {
|
||||||
|
logger.info(`Updating search documents for ${movieIds ? movieIds.length : 'all' } movies`);
|
||||||
|
|
||||||
|
const documents = await knex.raw(`
|
||||||
|
SELECT
|
||||||
|
movies.id AS movie_id,
|
||||||
|
TO_TSVECTOR(
|
||||||
|
'english',
|
||||||
|
COALESCE(movies.title, '') || ' ' ||
|
||||||
|
entities.name || ' ' ||
|
||||||
|
entities.slug || ' ' ||
|
||||||
|
COALESCE(array_to_string(entities.alias, ' '), '') || ' ' ||
|
||||||
|
COALESCE(parents.name, '') || ' ' ||
|
||||||
|
COALESCE(parents.slug, '') || ' ' ||
|
||||||
|
COALESCE(array_to_string(parents.alias, ' '), '') || ' ' ||
|
||||||
|
COALESCE(TO_CHAR(movies.date, 'YYYY YY MM FMMM FMMonth mon DD FMDD'), '') || ' ' ||
|
||||||
|
STRING_AGG(COALESCE(releases.title, ''), ' ') || ' ' ||
|
||||||
|
STRING_AGG(COALESCE(actors.name, ''), ' ') || ' ' ||
|
||||||
|
STRING_AGG(COALESCE(tags.name, ''), ' ')
|
||||||
|
) as document
|
||||||
|
FROM movies
|
||||||
|
LEFT JOIN entities ON movies.entity_id = entities.id
|
||||||
|
LEFT JOIN entities AS parents ON parents.id = entities.parent_id
|
||||||
|
LEFT JOIN movies_scenes ON movies_scenes.movie_id = movies.id
|
||||||
|
LEFT JOIN releases ON releases.id = movies_scenes.scene_id
|
||||||
|
LEFT JOIN releases_actors ON releases_actors.release_id = movies_scenes.scene_id
|
||||||
|
LEFT JOIN releases_tags ON releases_tags.release_id = releases.id
|
||||||
|
LEFT JOIN actors ON actors.id = releases_actors.actor_id
|
||||||
|
LEFT JOIN tags ON tags.id = releases_tags.tag_id
|
||||||
|
${movieIds ? 'WHERE movies.id = ANY(?)' : ''}
|
||||||
|
GROUP BY movies.id, entities.name, entities.slug, entities.alias, parents.name, parents.slug, parents.alias;
|
||||||
|
`, movieIds && [movieIds]);
|
||||||
|
|
||||||
|
if (documents.rows?.length > 0) {
|
||||||
|
await bulkInsert('movies_search', documents.rows, ['movie_id']);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function storeMovies(movies, useBatchId) {
|
||||||
|
if (!movies || movies.length === 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const { uniqueReleases } = await filterDuplicateReleases(movies);
|
||||||
|
const [batchId] = useBatchId ? [useBatchId] : await knex('batches').insert({ comment: null }).returning('id');
|
||||||
|
|
||||||
|
const curatedMovieEntries = await Promise.all(uniqueReleases.map((release) => curateReleaseEntry(release, batchId, null, 'movie')));
|
||||||
|
|
||||||
|
const storedMovies = await bulkInsert('movies', curatedMovieEntries, ['entity_id', 'entry_id'], true);
|
||||||
|
const moviesWithId = attachReleaseIds(movies, storedMovies);
|
||||||
|
|
||||||
|
await updateMovieSearch(moviesWithId.map((movie) => movie.id));
|
||||||
|
await associateReleaseMedia(moviesWithId, 'movie');
|
||||||
|
|
||||||
|
return moviesWithId;
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
associateMovieScenes,
|
associateMovieScenes,
|
||||||
storeScenes,
|
storeScenes,
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
'use strict';
|
|
||||||
|
|
||||||
const knex = require('../knex');
|
|
||||||
|
|
||||||
async function update() {
|
|
||||||
const query = knex('bans')
|
|
||||||
.update('type', {
|
|
||||||
type: 'mute',
|
|
||||||
username_original: 'charles',
|
|
||||||
})
|
|
||||||
.where('id', 2754);
|
|
||||||
|
|
||||||
console.log(query.toSQL());
|
|
||||||
|
|
||||||
await query;
|
|
||||||
}
|
|
||||||
|
|
||||||
update();
|
|
||||||