Compare commits
6 Commits
old
...
661b8b716b
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
661b8b716b | ||
|
|
5ff076cac3 | ||
|
|
41c100ac4e | ||
|
|
c6e977f842 | ||
|
|
50b7f521b5 | ||
|
|
f0d0ee3acc |
@@ -108,6 +108,7 @@
|
|||||||
: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,6 +102,8 @@ 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;
|
||||||
|
|||||||
@@ -11,16 +11,31 @@
|
|||||||
class="empty"
|
class="empty"
|
||||||
>No results for "{{ $route.query.query }}"</span>
|
>No results for "{{ $route.query.query }}"</span>
|
||||||
|
|
||||||
<div
|
<template v-else>
|
||||||
v-else
|
<h2 class="heading">Popular</h2>
|
||||||
class="entity-tiles"
|
|
||||||
>
|
<div
|
||||||
<Entity
|
class="entity-tiles"
|
||||||
v-for="entity in entities"
|
>
|
||||||
:key="entity.parent ? `entity-tile-${entity.parent.slug}-${entity.slug}` : `entity-tile-${entity.slug}`"
|
<Entity
|
||||||
:entity="entity"
|
v-for="entity in popularEntities"
|
||||||
/>
|
:key="entity.parent ? `entity-tile-${entity.parent.slug}-${entity.slug}` : `entity-tile-${entity.slug}`"
|
||||||
</div>
|
: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>
|
</div>
|
||||||
|
|
||||||
<Footer />
|
<Footer />
|
||||||
@@ -58,6 +73,45 @@ 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';
|
||||||
|
|
||||||
@@ -82,6 +136,7 @@ export default {
|
|||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
channelCount,
|
channelCount,
|
||||||
|
popularEntities,
|
||||||
},
|
},
|
||||||
watch: {
|
watch: {
|
||||||
$route: fetchEntities,
|
$route: fetchEntities,
|
||||||
@@ -130,6 +185,10 @@ 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;
|
||||||
|
|||||||
@@ -3,12 +3,6 @@
|
|||||||
<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"
|
||||||
@@ -36,7 +30,6 @@
|
|||||||
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) {
|
||||||
@@ -80,7 +73,6 @@ export default {
|
|||||||
MovieTile,
|
MovieTile,
|
||||||
SearchBar,
|
SearchBar,
|
||||||
Pagination,
|
Pagination,
|
||||||
TagFilter,
|
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
|
|||||||
@@ -87,7 +87,6 @@ const tagSlugsByCategory = {
|
|||||||
'titty-fucking',
|
'titty-fucking',
|
||||||
'fisting',
|
'fisting',
|
||||||
'anal-fisting',
|
'anal-fisting',
|
||||||
'fisting-dp',
|
|
||||||
],
|
],
|
||||||
group: [
|
group: [
|
||||||
'mfm',
|
'mfm',
|
||||||
@@ -108,16 +107,6 @@ const tagSlugsByCategory = {
|
|||||||
'bukkake',
|
'bukkake',
|
||||||
'fake-cum',
|
'fake-cum',
|
||||||
],
|
],
|
||||||
toys: [
|
|
||||||
'toys',
|
|
||||||
'toy-anal',
|
|
||||||
'toy-dp',
|
|
||||||
'double-dildo',
|
|
||||||
'double-dildo-blowjob',
|
|
||||||
'double-dildo-kiss',
|
|
||||||
'double-dildo-anal',
|
|
||||||
'double-dildo-dp',
|
|
||||||
],
|
|
||||||
roleplay: [
|
roleplay: [
|
||||||
'family',
|
'family',
|
||||||
'parody',
|
'parody',
|
||||||
@@ -126,6 +115,15 @@ const tagSlugsByCategory = {
|
|||||||
'maid',
|
'maid',
|
||||||
'nun',
|
'nun',
|
||||||
],
|
],
|
||||||
|
extreme: [
|
||||||
|
'dp',
|
||||||
|
'airtight',
|
||||||
|
'dap',
|
||||||
|
'dvp',
|
||||||
|
'triple-penetration',
|
||||||
|
'tap',
|
||||||
|
'tvp',
|
||||||
|
],
|
||||||
fetish: [
|
fetish: [
|
||||||
'bdsm',
|
'bdsm',
|
||||||
'femdom',
|
'femdom',
|
||||||
@@ -134,15 +132,15 @@ const tagSlugsByCategory = {
|
|||||||
'latex',
|
'latex',
|
||||||
'blindfold',
|
'blindfold',
|
||||||
],
|
],
|
||||||
extreme: [
|
toys: [
|
||||||
'dp',
|
'toys',
|
||||||
'airtight',
|
'toy-anal',
|
||||||
'dap',
|
'toy-dp',
|
||||||
'dvp',
|
'double-dildo',
|
||||||
'da-tp',
|
'double-dildo-blowjob',
|
||||||
'dv-tp',
|
'double-dildo-kiss',
|
||||||
'tap',
|
'double-dildo-anal',
|
||||||
'tvp',
|
'double-dildo-dp',
|
||||||
],
|
],
|
||||||
misc: [
|
misc: [
|
||||||
'gaping',
|
'gaping',
|
||||||
|
|||||||
@@ -105,6 +105,7 @@ 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,6 +41,11 @@ 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: {
|
||||||
|
|||||||
@@ -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 integer AS $$
|
CREATE OR REPLACE FUNCTION entities_scene_total(entity entities) RETURNS bigint AS $$
|
||||||
SELECT COUNT(id)
|
SELECT COUNT(id)
|
||||||
FROM releases
|
FROM releases
|
||||||
WHERE releases.entity_id = entity.id;
|
WHERE releases.entity_id = entity.id;
|
||||||
|
|||||||
@@ -1,8 +0,0 @@
|
|||||||
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;
|
|
||||||
`);
|
|
||||||
23
migrations/20220227215315_entity_filters.js
Normal file
23
migrations/20220227215315_entity_filters.js
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
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_tags;
|
||||||
|
`);
|
||||||
98
migrations/20220304233846_series.js
Normal file
98
migrations/20220304233846_series.js
Normal file
@@ -0,0 +1,98 @@
|
|||||||
|
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');
|
||||||
|
}));
|
||||||
|
|
||||||
|
exports.down = async (knex) => Promise.resolve()
|
||||||
|
.then(() => knex.schema.dropTable('series_covers'))
|
||||||
|
.then(() => knex.schema.dropTable('series_trailers'))
|
||||||
|
.then(() => knex.schema.dropTable('series_posters'))
|
||||||
|
.then(() => knex.schema.dropTable('series'));
|
||||||
4
package-lock.json
generated
4
package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.209.4",
|
"version": "1.210.1",
|
||||||
"lockfileVersion": 2,
|
"lockfileVersion": 2,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.209.4",
|
"version": "1.210.1",
|
||||||
"license": "ISC",
|
"license": "ISC",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@casl/ability": "^5.2.2",
|
"@casl/ability": "^5.2.2",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "traxxx",
|
"name": "traxxx",
|
||||||
"version": "1.209.4",
|
"version": "1.210.1",
|
||||||
"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": {
|
||||||
|
|||||||
BIN
public/img/tags/triple-penetration/lazy/lucky_bee_analvids.jpeg
Normal file
BIN
public/img/tags/triple-penetration/lazy/lucky_bee_analvids.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 6.4 KiB |
BIN
public/img/tags/triple-penetration/lucky_bee_analvids.jpeg
Normal file
BIN
public/img/tags/triple-penetration/lucky_bee_analvids.jpeg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
After Width: | Height: | Size: 29 KiB |
@@ -2646,7 +2646,7 @@ const sites = [
|
|||||||
{
|
{
|
||||||
slug: 'digitalplayground',
|
slug: 'digitalplayground',
|
||||||
name: 'Digital Playground',
|
name: 'Digital Playground',
|
||||||
url: 'https://www.digitalplayground.com/scenes',
|
url: 'https://www.digitalplayground.com',
|
||||||
description: '',
|
description: '',
|
||||||
parameters: { extract: true },
|
parameters: { extract: true },
|
||||||
parent: 'digitalplayground',
|
parent: 'digitalplayground',
|
||||||
@@ -2680,6 +2680,13 @@ 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',
|
||||||
|
|||||||
@@ -727,8 +727,6 @@ 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'],
|
||||||
@@ -1049,6 +1047,7 @@ 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'],
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ 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');
|
||||||
@@ -1048,33 +1049,42 @@ async function flushProfiles(actorIdsOrNames) {
|
|||||||
logger.info(`Removed ${deleteCount} profiles`);
|
logger.info(`Removed ${deleteCount} profiles`);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function deleteActors(actorIdsOrNames) {
|
async function deleteActors(allActorIdsOrNames) {
|
||||||
const actors = await knex('actors')
|
const deleteCounts = await Promise.map(chunk(allActorIdsOrNames), async (actorIdsOrNames) => {
|
||||||
.whereIn('id', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'number'))
|
const actors = await knex('actors')
|
||||||
.orWhere((builder) => {
|
.whereIn('id', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'number'))
|
||||||
builder
|
.orWhere((builder) => {
|
||||||
.whereIn('name', actorIdsOrNames.filter((idOrName) => typeof idOrName === 'string'))
|
builder
|
||||||
.whereNull('entity_id');
|
.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')
|
const sceneIds = await knex('releases_actors')
|
||||||
.select('releases.id')
|
.select('releases.id')
|
||||||
.whereIn('actor_id', actorIds)
|
.whereIn('actor_id', actorIds)
|
||||||
.leftJoin('releases', 'releases.id', 'releases_actors.release_id')
|
.leftJoin('releases', 'releases.id', 'releases_actors.release_id')
|
||||||
.pluck('id');
|
.pluck('id');
|
||||||
|
|
||||||
const [deletedScenesCount, deletedActorsCount] = await Promise.all([
|
const [deletedScenesCount, deletedActorsCount] = await Promise.all([
|
||||||
deleteScenes(sceneIds),
|
deleteScenes(sceneIds),
|
||||||
knex('actors')
|
knex('actors')
|
||||||
.whereIn('id', actorIds)
|
.whereIn('id', actorIds)
|
||||||
.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() {
|
||||||
|
|||||||
@@ -961,9 +961,12 @@ async function flushOrphanedMedia() {
|
|||||||
await deleteS3Objects(orphanedMedia.filter((media) => media.is_s3));
|
await deleteS3Objects(orphanedMedia.filter((media) => media.is_s3));
|
||||||
}
|
}
|
||||||
|
|
||||||
await fsPromises.rm(path.join(config.media.path, 'temp'), { recursive: true });
|
try {
|
||||||
|
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 = {
|
||||||
|
|||||||
@@ -11,6 +11,12 @@ 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
|
||||||
@@ -18,7 +24,7 @@ function getThumbs(scene) {
|
|||||||
.map((image) => image.xl.url);
|
.map((image) => image.xl.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (scene.images.card_main_rect) {
|
if (Array.isArray(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', ''));
|
||||||
@@ -27,6 +33,20 @@ function getThumbs(scene) {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function getCovers(images) {
|
||||||
|
return [
|
||||||
|
[
|
||||||
|
images.cover[0].md?.url,
|
||||||
|
images.cover[0].sm?.url,
|
||||||
|
images.cover[0].xs?.url,
|
||||||
|
// bigger but usually upscaled
|
||||||
|
images.cover[0].xx?.url,
|
||||||
|
images.cover[0].xl?.url,
|
||||||
|
images.cover[0].lg?.url,
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -51,9 +71,7 @@ function scrapeLatestX(data, site, filterChannel) {
|
|||||||
description: data.description,
|
description: data.description,
|
||||||
};
|
};
|
||||||
|
|
||||||
const basepath = site.parameters?.scene
|
const basepath = getBasePath(site);
|
||||||
|| (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);
|
||||||
@@ -84,6 +102,9 @@ function scrapeLatestX(data, site, filterChannel) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const siteName = data.collections[0]?.name || data.brand;
|
||||||
|
release.channel = slugify(siteName, '');
|
||||||
|
|
||||||
return release;
|
return release;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -96,7 +117,7 @@ async function scrapeLatest(items, site, filterChannel) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
function scrapeScene(data, url, _site, networkName) {
|
function scrapeRelease(data, url, channel, networkName) {
|
||||||
const release = {};
|
const release = {};
|
||||||
|
|
||||||
const { id: entryId, title, description } = data;
|
const { id: entryId, title, description } = data;
|
||||||
@@ -129,6 +150,29 @@ function scrapeScene(data, url, _site, 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, '/movie')}/${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),
|
||||||
|
covers: getCovers(data.parent.images),
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,7 +274,7 @@ function scrapeProfile(data, html, releases = [], networkName) {
|
|||||||
profile.naturalBoobs = false;
|
profile.naturalBoobs = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
profile.releases = releases.map((release) => scrapeScene(release, null, null, networkName));
|
profile.releases = releases.map((release) => scrapeRelease(release, null, null, networkName));
|
||||||
|
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
@@ -292,8 +336,8 @@ async function fetchUpcoming(site, page, options) {
|
|||||||
return res.statusCode;
|
return res.statusCode;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchScene(url, site, baseScene, options) {
|
async function fetchRelease(url, site, baseScene, options) {
|
||||||
if (baseScene?.entryId) {
|
if (baseScene?.entryId && !baseScene.shallow) {
|
||||||
// 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;
|
||||||
}
|
}
|
||||||
@@ -312,7 +356,7 @@ async function fetchScene(url, site, baseScene, options) {
|
|||||||
|
|
||||||
if (res.status === 200 && res.body.result) {
|
if (res.status === 200 && res.body.result) {
|
||||||
return {
|
return {
|
||||||
scene: scrapeScene(res.body.result, url, site),
|
scene: scrapeRelease(res.body.result, url, site),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,6 +418,7 @@ module.exports = {
|
|||||||
scrapeLatestX,
|
scrapeLatestX,
|
||||||
fetchLatest,
|
fetchLatest,
|
||||||
fetchUpcoming,
|
fetchUpcoming,
|
||||||
fetchScene,
|
fetchScene: fetchRelease,
|
||||||
|
fetchMovie: fetchRelease,
|
||||||
fetchProfile,
|
fetchProfile,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -142,6 +142,7 @@ 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: {
|
||||||
@@ -169,6 +170,7 @@ 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, {
|
||||||
|
|||||||
@@ -392,7 +392,8 @@ async function associateMovieScenes(movies, movieScenes) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const sceneMovie = moviesByEntityIdAndEntryId[scene.entity.id]?.[scene.movie.entryId];
|
const sceneMovie = moviesByEntityIdAndEntryId[scene.entity.id]?.[scene.movie.entryId]
|
||||||
|
|| moviesByEntityIdAndEntryId[scene.entity.parent?.id]?.[scene.movie.entryId];
|
||||||
|
|
||||||
if (sceneMovie?.id) {
|
if (sceneMovie?.id) {
|
||||||
return {
|
return {
|
||||||
|
|||||||
Reference in New Issue
Block a user