diff --git a/assets/components/actors/actors.vue b/assets/components/actors/actors.vue index 1fc0c6d0..13c437cd 100644 --- a/assets/components/actors/actors.vue +++ b/assets/components/actors/actors.vue @@ -14,6 +14,7 @@ :to="{ name: 'actors', params: { gender: 'male', letter } }" :class="{ selected: gender === 'male' }" class="gender-link male" + replace >
  • @@ -21,6 +22,7 @@ :to="{ name: 'actors', params: { gender: 'trans', letter } }" :class="{ selected: gender === 'trans' }" class="gender-link transsexual" + replace >
  • @@ -28,6 +30,7 @@ :to="{ name: 'actors', params: { gender: 'other', letter } }" :class="{ selected: gender === 'other' }" class="gender-link other" + replace >
  • @@ -42,6 +45,7 @@ :to="{ name: 'actors', params: { gender, letter: letterX } }" :class="{ selected: letterX === letter }" class="letter-link" + replace >{{ letterX || 'All' }} diff --git a/assets/components/networks/network.vue b/assets/components/networks/network.vue index 521a3ac2..c03c0988 100644 --- a/assets/components/networks/network.vue +++ b/assets/components/networks/network.vue @@ -130,30 +130,22 @@ import FilterBar from '../header/filter-bar.vue'; import Releases from '../releases/releases.vue'; import Sites from '../sites/sites.vue'; import Network from '../tile/network.vue'; +import Entity from '../tile/entity.vue'; async function fetchNetwork() { - const { network, totalCount } = await this.$store.dispatch('fetchNetworkBySlug', { - networkSlug: this.$route.params.networkSlug, + const { entity, totalCount } = await this.$store.dispatch('fetchEntityBySlugAndType', { + entitySlug: this.$route.params.networkSlug, + entityType: 'network', limit: this.limit, range: this.$route.params.range, pageNumber: Number(this.$route.params.pageNumber), }); - this.network = network; - this.totalCount = totalCount; - - if (this.network.studios) { - this.studios = this.network.studios.map(studio => ({ - ...studio, - network: this.network, - })); - } - - this.networks = this.network.networks; - this.sites = this.network.sites - .filter(site => !site.independent); - + this.network = entity; + this.networks = this.network.children; this.releases = this.network.releases; + + this.totalCount = totalCount; } async function route() { @@ -171,6 +163,7 @@ export default { Releases, Sites, Network, + Entity, }, data() { return { diff --git a/assets/components/networks/networks.vue b/assets/components/networks/networks.vue index f7c4e3f1..73ede419 100644 --- a/assets/components/networks/networks.vue +++ b/assets/components/networks/networks.vue @@ -2,13 +2,13 @@
    @@ -135,7 +133,7 @@ export default { } } -.network-tiles { +.entity-tiles { display: grid; grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr)); grid-gap: 1rem; diff --git a/assets/components/releases/release.vue b/assets/components/releases/release.vue index 2ad155fb..b2fb2a3d 100644 --- a/assets/components/releases/release.vue +++ b/assets/components/releases/release.vue @@ -211,25 +211,15 @@ target="_blank" rel="noopener noreferrer" class="link added" - >{{ formatDate(release.dateAdded, 'MMMM D, YYYY') }} + >{{ formatDate(release.createdAt, 'MMMM D, YYYY HH:mm') }} - -
    - - - -
    diff --git a/assets/components/tile/entity.vue b/assets/components/tile/entity.vue new file mode 100644 index 00000000..f08c1d6e --- /dev/null +++ b/assets/components/tile/entity.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/assets/components/tile/network.vue b/assets/components/tile/network.vue index fbcae7d4..4b1c2f3f 100644 --- a/assets/components/tile/network.vue +++ b/assets/components/tile/network.vue @@ -1,33 +1,33 @@ @@ -39,7 +39,7 @@ export default { background: var(--profile); display: flex; flex-shrink: 0; - flex-direction: column; + justify-content: center; align-items: center; box-sizing: border-box; padding: .5rem 1rem; @@ -52,16 +52,9 @@ export default { } .logo { - width: 100%; - height: 100%; - color: $text; - display: flex; - align-items: center; - justify-content: center; - object-fit: contain; + max-width: 100%; + max-height: 100%; font-size: 1rem; - font-weight: bold; - /* filter: $logo-highlight; */ } .title { diff --git a/assets/js/curate.js b/assets/js/curate.js index bb6c5d05..f9f12aff 100644 --- a/assets/js/curate.js +++ b/assets/js/curate.js @@ -100,6 +100,7 @@ function curateSite(site, network) { function curateNetwork(network, releases) { const curatedNetwork = { + ...network, id: network.id, name: network.name, slug: network.slug, @@ -116,6 +117,19 @@ function curateNetwork(network, releases) { return curatedNetwork; } +function curateEntity(entity, parent, releases) { + const curatedEntity = { + ...entity, + children: [], + }; + + if (entity.parent || parent) curatedEntity.parent = curateEntity(entity.parent || parent); + if (entity.children) curatedEntity.children = entity.children.map(childEntity => curateEntity(childEntity, curatedEntity)); + if (releases) curatedEntity.releases = releases.map(release => curateRelease(release)); + + return curatedEntity; +} + function curateTag(tag) { const curatedTag = { ...tag, @@ -130,6 +144,7 @@ function curateTag(tag) { export { curateActor, + curateEntity, curateRelease, curateSite, curateNetwork, diff --git a/assets/js/entities/actions.js b/assets/js/entities/actions.js new file mode 100644 index 00000000..7ad6f13e --- /dev/null +++ b/assets/js/entities/actions.js @@ -0,0 +1,179 @@ +import { graphql } from '../api'; +// import { sitesFragment, releaseFields } from '../fragments'; +import { releaseFields } from '../fragments'; +import { curateEntity } from '../curate'; +import getDateRange from '../get-date-range'; + +function initEntitiesActions(store, _router) { + async function fetchEntityBySlugAndType({ _commit }, { + entitySlug, + entityType, + limit = 10, + pageNumber = 1, + range = 'latest', + }) { + const { before, after, orderBy } = getDateRange(range); + + const { entity, connection: { releases, totalCount } } = await graphql(` + query Entity( + $entitySlug: String! + $entityType: String! = "channel" + $limit: Int = 10, + $offset: Int = 0, + $after: Date = "1900-01-01", + $before: Date = "2100-01-01", + $afterTime: Datetime = "1900-01-01", + $beforeTime: Datetime = "2100-01-01", + $orderBy: [ReleasesOrderBy!] + $exclude: [String!] + ) { + entity: entityBySlugAndType(slug: $entitySlug, type: $entityType) { + id + name + slug + url + children: childEntities( + orderBy: [PRIORITY_DESC, NAME_ASC], + ) { + id + name + slug + url + type + priority + } + parent { + id + name + slug + type + url + } + } + connection: releasesConnection( + first: $limit + offset: $offset + orderBy: $orderBy + filter: { + entity: { + or: [ + { parent: { slug: { equalTo: $entitySlug } } }, + { parent: { parent: { slug: { equalTo: $entitySlug } } } } + ] + } + or: [ + { + date: { + lessThan: $before, + greaterThan: $after + } + }, + { + date: { + isNull: true + }, + createdAt: { + lessThan: $beforeTime, + greaterThan: $afterTime, + } + } + ] + releasesTagsConnection: { + none: { + tag: { + slug: { + in: $exclude + } + } + } + } + } + ) { + releases: nodes { + ${releaseFields} + } + totalCount + } + } + `, { + entitySlug, + entityType, + limit, + offset: Math.max(0, (pageNumber - 1)) * limit, + after, + before, + orderBy, + afterTime: store.getters.after, + beforeTime: store.getters.before, + exclude: store.state.ui.filter, + }); + + return { + entity: curateEntity(entity, null, releases), + totalCount, + }; + } + + async function fetchEntities({ _commit }, { type }) { + const { entities } = await graphql(` + query Entities( + $type: String! = "network" + ) { + entities( + orderBy: NAME_ASC + filter: { + type: { + equalTo: $type + } + } + ) { + id + name + slug + type + url + } + } + `, { type }); + + return entities.map(entity => curateEntity(entity)); + } + + async function searchEntities({ _commit }, { query, limit = 20 }) { + const { entities } = await graphql(` + query SearchEntities( + $query: String! + $limit:Int = 20, + ) { + entities: searchEntities( + search: $query, + first: $limit + ) { + name + slug + type + url + parent { + name + slug + type + url + } + } + } + `, { + query, + limit, + }); + + return entities.map(entity => curateEntity(entity)); + } + + return { + fetchEntityBySlugAndType, + fetchEntities, + searchEntities, + }; +} + +export default initEntitiesActions; diff --git a/assets/js/entities/entities.js b/assets/js/entities/entities.js new file mode 100644 index 00000000..bc8e4faa --- /dev/null +++ b/assets/js/entities/entities.js @@ -0,0 +1,13 @@ +import state from './state'; +import mutations from './mutations'; +import actions from './actions'; + +function initEntitiesStore(store, router) { + return { + state, + mutations, + actions: actions(store, router), + }; +} + +export default initEntitiesStore; diff --git a/assets/js/entities/mutations.js b/assets/js/entities/mutations.js new file mode 100644 index 00000000..ff8b4c56 --- /dev/null +++ b/assets/js/entities/mutations.js @@ -0,0 +1 @@ +export default {}; diff --git a/assets/js/entities/state.js b/assets/js/entities/state.js new file mode 100644 index 00000000..ff8b4c56 --- /dev/null +++ b/assets/js/entities/state.js @@ -0,0 +1 @@ +export default {}; diff --git a/assets/js/networks/actions.js b/assets/js/networks/actions.js index c2887059..d2e9fcf5 100644 --- a/assets/js/networks/actions.js +++ b/assets/js/networks/actions.js @@ -25,7 +25,7 @@ function initNetworksActions(store, _router) { $orderBy: [ReleasesOrderBy!] $exclude: [String!] ) { - network: entityBySlugAndType(slug: $networkSlug, type: 1) { + network: entityBySlugAndType(slug: $networkSlug, type: "network") { id name slug @@ -37,12 +37,14 @@ function initNetworksActions(store, _router) { name slug url + type priority } parent { id name slug + type url } } @@ -51,10 +53,10 @@ function initNetworksActions(store, _router) { offset: $offset orderBy: $orderBy filter: { - site: { + entity: { or: [ - { network: { slug: { equalTo: $networkSlug } } }, - { network: { parent: { slug: { equalTo: $networkSlug } } } } + { parent: { slug: { equalTo: $networkSlug } } }, + { parent: { parent: { slug: { equalTo: $networkSlug } } } } ] } or: [ @@ -116,13 +118,14 @@ function initNetworksActions(store, _router) { orderBy: NAME_ASC filter: { type: { - equalTo: 1 + equalTo: "network" } } ) { id name slug + type url } } diff --git a/assets/js/sites/actions.js b/assets/js/sites/actions.js index 5cfc6a59..3b616ad3 100644 --- a/assets/js/sites/actions.js +++ b/assets/js/sites/actions.js @@ -22,18 +22,18 @@ function initSitesActions(store, _router) { $orderBy:[ReleasesOrderBy!] $exclude: [String!] ) { - site: siteBySlug(slug: $siteSlug) { + site: entityBySlugAndType(slug: $siteSlug, type: 2) { name slug url - tags: sitesTags { + tags: entitiesTags { tag { id slug name } } - network { + network: parent { id name slug @@ -70,7 +70,7 @@ function initSitesActions(store, _router) { offset: $offset orderBy: $orderBy filter: { - site: { + entity: { slug: { equalTo: $siteSlug } @@ -122,7 +122,7 @@ function initSitesActions(store, _router) { $after:Date = "1900-01-01", $before:Date = "2100-01-01", ) { - site { + site: entity { name slug url @@ -137,38 +137,9 @@ function initSitesActions(store, _router) { return sites; } - async function searchSites({ _commit }, { query, limit = 20 }) { - const { sites } = await graphql(` - query SearchSites( - $query: String! - $limit:Int = 20, - ) { - sites: searchSites( - search: $query, - first: $limit - ) { - name - slug - url - network { - name - slug - url - } - } - } - `, { - query, - limit, - }); - - return sites; - } - return { fetchSiteBySlug, fetchSites, - searchSites, }; } diff --git a/assets/js/store.js b/assets/js/store.js index 663fae27..8bd6b49d 100644 --- a/assets/js/store.js +++ b/assets/js/store.js @@ -4,6 +4,7 @@ import Vuex from 'vuex'; import initUiStore from './ui/ui'; import initAuthStore from './auth/auth'; import initReleasesStore from './releases/releases'; +import initEntitiesStore from './entities/entities'; import initSitesStore from './sites/sites'; import initNetworksStore from './networks/networks'; import initActorsStore from './actors/actors'; @@ -18,6 +19,7 @@ function initStore(router) { store.registerModule('auth', initAuthStore(store, router)); store.registerModule('releases', initReleasesStore(store, router)); store.registerModule('actors', initActorsStore(store, router)); + store.registerModule('entities', initEntitiesStore(store, router)); store.registerModule('sites', initSitesStore(store, router)); store.registerModule('networks', initNetworksStore(store, router)); store.registerModule('tags', initTagsStore(store, router)); diff --git a/migrations/20190325001339_releases.js b/migrations/20190325001339_releases.js index b7cfa5ae..c6bdaeb4 100644 --- a/migrations/20190325001339_releases.js +++ b/migrations/20190325001339_releases.js @@ -141,8 +141,8 @@ exports.up = knex => Promise.resolve() table.unique(['tag_id', 'media_id']); })) .then(() => knex.schema.createTable('entities_types', (table) => { - table.increments('id', 4); - table.text('type'); + table.text('type') + .primary(); })) .then(() => knex('entities_types').insert([ { type: 'network' }, @@ -160,10 +160,11 @@ exports.up = knex => Promise.resolve() table.text('name'); table.text('slug', 32); - table.integer('type', 4) - .references('id') + table.text('type') + .notNullable() + .references('type') .inTable('entities_types') - .defaultTo(2); + .defaultTo('channel'); table.unique(['slug', 'type']); @@ -196,114 +197,18 @@ exports.up = knex => Promise.resolve() table.unique(['tag_id', 'entity_id']); })) - .then(() => knex.schema.createTable('networks', (table) => { - table.increments('id', 12); - - table.text('name'); - table.text('alias'); - table.text('url'); - table.text('description'); - table.json('parameters'); - - table.integer('parent_id', 12) - .references('id') - .inTable('networks'); - - table.text('slug', 32) - .unique(); - - table.datetime('created_at') - .defaultTo(knex.fn.now()); - })) - .then(() => knex.schema.createTable('networks_social', (table) => { + .then(() => knex.schema.createTable('entities_social', (table) => { table.increments('id', 16); table.text('url'); table.text('platform'); - table.integer('network_id', 12) + table.integer('entity_id', 12) .notNullable() .references('id') - .inTable('networks'); + .inTable('entities'); - table.unique(['url', 'network_id']); - - table.datetime('created_at') - .defaultTo(knex.fn.now()); - })) - .then(() => knex.schema.createTable('sites', (table) => { - table.increments('id', 12); - - table.integer('network_id', 12) - .notNullable() - .references('id') - .inTable('networks'); - - table.text('name'); - table.text('slug', 32) - .unique(); - - table.text('alias'); - - table.text('url'); - table.text('description'); - table.json('parameters'); - - table.integer('priority', 3) - .defaultTo(0); - - table.boolean('show') - .defaultTo(true); - - table.datetime('created_at') - .defaultTo(knex.fn.now()); - })) - .then(() => knex.schema.createTable('sites_tags', (table) => { - table.integer('tag_id', 12) - .notNullable() - .references('id') - .inTable('tags'); - - table.integer('site_id', 12) - .notNullable() - .references('id') - .inTable('sites'); - - table.boolean('inherit') - .defaultTo(false); - - table.unique(['tag_id', 'site_id']); - })) - .then(() => knex.schema.createTable('sites_social', (table) => { - table.increments('id', 16); - - table.text('url'); - table.text('platform'); - - table.integer('site_id', 12) - .notNullable() - .references('id') - .inTable('sites'); - - table.unique(['url', 'site_id']); - - table.datetime('created_at') - .defaultTo(knex.fn.now()); - })) - .then(() => knex.schema.createTable('studios', (table) => { - table.increments('id', 12); - - table.integer('network_id', 12) - .notNullable() - .references('id') - .inTable('networks'); - - table.text('name'); - table.text('url'); - table.text('description'); - - table.text('slug', 32) - .unique(); + table.unique(['url', 'entity_id']); table.datetime('created_at') .defaultTo(knex.fn.now()); @@ -683,7 +588,7 @@ exports.up = knex => Promise.resolve() table.integer('studio_id', 12) .references('id') - .inTable('studios'); + .inTable('entities'); table.text('type', 10) .defaultTo('scene'); @@ -878,8 +783,8 @@ exports.up = knex => Promise.resolve() ); $$ LANGUAGE SQL STABLE; - CREATE FUNCTION search_sites(search text) RETURNS SETOF sites AS $$ - SELECT * FROM sites + CREATE FUNCTION search_entities(search text) RETURNS SETOF entities AS $$ + SELECT * FROM entities WHERE name ILIKE ('%' || search || '%') OR slug ILIKE ('%' || search || '%') OR @@ -944,6 +849,7 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style DROP TABLE IF EXISTS body CASCADE; DROP TABLE IF EXISTS entities_tags CASCADE; + DROP TABLE IF EXISTS entities_social CASCADE; DROP TABLE IF EXISTS sites_tags CASCADE; DROP TABLE IF EXISTS sites_social CASCADE; DROP TABLE IF EXISTS networks_social CASCADE; @@ -966,6 +872,7 @@ exports.down = (knex) => { // eslint-disable-line arrow-body-style DROP TABLE IF EXISTS entities CASCADE; DROP FUNCTION IF EXISTS search_sites; + DROP FUNCTION IF EXISTS search_entities; DROP FUNCTION IF EXISTS search_actors; DROP FUNCTION IF EXISTS get_random_sfw_media_id; diff --git a/public/img/logos/kink/kinkybites.png b/public/img/logos/kink/kinkybites.png new file mode 100644 index 00000000..da521f0d Binary files /dev/null and b/public/img/logos/kink/kinkybites.png differ diff --git a/public/img/logos/kink/lazy/boundgangbangs.png b/public/img/logos/kink/lazy/boundgangbangs.png index cc703604..1bbcbb05 100644 Binary files a/public/img/logos/kink/lazy/boundgangbangs.png and b/public/img/logos/kink/lazy/boundgangbangs.png differ diff --git a/public/img/logos/kink/lazy/boundgods.png b/public/img/logos/kink/lazy/boundgods.png index c5736e59..764fe63a 100644 Binary files a/public/img/logos/kink/lazy/boundgods.png and b/public/img/logos/kink/lazy/boundgods.png differ diff --git a/public/img/logos/kink/lazy/boundinpublic.png b/public/img/logos/kink/lazy/boundinpublic.png index dc439393..1592beba 100644 Binary files a/public/img/logos/kink/lazy/boundinpublic.png and b/public/img/logos/kink/lazy/boundinpublic.png differ diff --git a/public/img/logos/kink/lazy/brutalsessions.png b/public/img/logos/kink/lazy/brutalsessions.png index b497ee2d..cc49655e 100644 Binary files a/public/img/logos/kink/lazy/brutalsessions.png and b/public/img/logos/kink/lazy/brutalsessions.png differ diff --git a/public/img/logos/kink/lazy/buttmachineboys.png b/public/img/logos/kink/lazy/buttmachineboys.png index 738f9211..a0a80d9d 100644 Binary files a/public/img/logos/kink/lazy/buttmachineboys.png and b/public/img/logos/kink/lazy/buttmachineboys.png differ diff --git a/public/img/logos/kink/lazy/devicebondage.png b/public/img/logos/kink/lazy/devicebondage.png index 403fa6c8..26bdfd34 100644 Binary files a/public/img/logos/kink/lazy/devicebondage.png and b/public/img/logos/kink/lazy/devicebondage.png differ diff --git a/public/img/logos/kink/lazy/divinebitches.png b/public/img/logos/kink/lazy/divinebitches.png index 4e85d4d5..c7704821 100644 Binary files a/public/img/logos/kink/lazy/divinebitches.png and b/public/img/logos/kink/lazy/divinebitches.png differ diff --git a/public/img/logos/kink/lazy/electrosluts.png b/public/img/logos/kink/lazy/electrosluts.png index d619c2d2..514a2867 100644 Binary files a/public/img/logos/kink/lazy/electrosluts.png and b/public/img/logos/kink/lazy/electrosluts.png differ diff --git a/public/img/logos/kink/lazy/everythingbutt.png b/public/img/logos/kink/lazy/everythingbutt.png index 34a8cc4a..699a151d 100644 Binary files a/public/img/logos/kink/lazy/everythingbutt.png and b/public/img/logos/kink/lazy/everythingbutt.png differ diff --git a/public/img/logos/kink/lazy/familiestied.png b/public/img/logos/kink/lazy/familiestied.png index d5f82caf..66c18b53 100644 Binary files a/public/img/logos/kink/lazy/familiestied.png and b/public/img/logos/kink/lazy/familiestied.png differ diff --git a/public/img/logos/kink/lazy/favicon.png b/public/img/logos/kink/lazy/favicon.png index 3e15b4e4..ee0720b1 100644 Binary files a/public/img/logos/kink/lazy/favicon.png and b/public/img/logos/kink/lazy/favicon.png differ diff --git a/public/img/logos/kink/lazy/filthyfemdom.png b/public/img/logos/kink/lazy/filthyfemdom.png index a1a9911f..33a121f5 100644 Binary files a/public/img/logos/kink/lazy/filthyfemdom.png and b/public/img/logos/kink/lazy/filthyfemdom.png differ diff --git a/public/img/logos/kink/lazy/footworship.png b/public/img/logos/kink/lazy/footworship.png index fa1c6b60..da1958e6 100644 Binary files a/public/img/logos/kink/lazy/footworship.png and b/public/img/logos/kink/lazy/footworship.png differ diff --git a/public/img/logos/kink/lazy/fuckedandbound.png b/public/img/logos/kink/lazy/fuckedandbound.png index b338f041..3c7cdd7a 100644 Binary files a/public/img/logos/kink/lazy/fuckedandbound.png and b/public/img/logos/kink/lazy/fuckedandbound.png differ diff --git a/public/img/logos/kink/lazy/fuckingmachines.png b/public/img/logos/kink/lazy/fuckingmachines.png index ab9c963e..842958de 100644 Binary files a/public/img/logos/kink/lazy/fuckingmachines.png and b/public/img/logos/kink/lazy/fuckingmachines.png differ diff --git a/public/img/logos/kink/lazy/hardcoregangbang.png b/public/img/logos/kink/lazy/hardcoregangbang.png index 8913ca75..a5813b4f 100644 Binary files a/public/img/logos/kink/lazy/hardcoregangbang.png and b/public/img/logos/kink/lazy/hardcoregangbang.png differ diff --git a/public/img/logos/kink/lazy/hogtied.png b/public/img/logos/kink/lazy/hogtied.png index de1f4a39..111c5d9b 100644 Binary files a/public/img/logos/kink/lazy/hogtied.png and b/public/img/logos/kink/lazy/hogtied.png differ diff --git a/public/img/logos/kink/lazy/kink-dvd.png b/public/img/logos/kink/lazy/kink-dvd.png index 6a4c458c..649d69cb 100644 Binary files a/public/img/logos/kink/lazy/kink-dvd.png and b/public/img/logos/kink/lazy/kink-dvd.png differ diff --git a/public/img/logos/kink/lazy/kinkfeatures.png b/public/img/logos/kink/lazy/kinkfeatures.png index b72c052f..ba29b586 100644 Binary files a/public/img/logos/kink/lazy/kinkfeatures.png and b/public/img/logos/kink/lazy/kinkfeatures.png differ diff --git a/public/img/logos/kink/lazy/kinkuniversity.png b/public/img/logos/kink/lazy/kinkuniversity.png index 3bafd0c2..cee0c96e 100644 Binary files a/public/img/logos/kink/lazy/kinkuniversity.png and b/public/img/logos/kink/lazy/kinkuniversity.png differ diff --git a/public/img/logos/kink/lazy/kinkybites.png b/public/img/logos/kink/lazy/kinkybites.png new file mode 100644 index 00000000..d467e44c Binary files /dev/null and b/public/img/logos/kink/lazy/kinkybites.png differ diff --git a/public/img/logos/kink/lazy/meninpain.png b/public/img/logos/kink/lazy/meninpain.png index e1b14738..4e6bdd34 100644 Binary files a/public/img/logos/kink/lazy/meninpain.png and b/public/img/logos/kink/lazy/meninpain.png differ diff --git a/public/img/logos/kink/lazy/menonedge.png b/public/img/logos/kink/lazy/menonedge.png index 2f0a5c60..7a583346 100644 Binary files a/public/img/logos/kink/lazy/menonedge.png and b/public/img/logos/kink/lazy/menonedge.png differ diff --git a/public/img/logos/kink/lazy/nakedkombat.png b/public/img/logos/kink/lazy/nakedkombat.png index 455931b5..58921dba 100644 Binary files a/public/img/logos/kink/lazy/nakedkombat.png and b/public/img/logos/kink/lazy/nakedkombat.png differ diff --git a/public/img/logos/kink/lazy/network.png b/public/img/logos/kink/lazy/network.png index 37d377f6..5a59322b 100644 Binary files a/public/img/logos/kink/lazy/network.png and b/public/img/logos/kink/lazy/network.png differ diff --git a/public/img/logos/kink/lazy/publicdisgrace.png b/public/img/logos/kink/lazy/publicdisgrace.png index 7e501a50..7a6bc365 100644 Binary files a/public/img/logos/kink/lazy/publicdisgrace.png and b/public/img/logos/kink/lazy/publicdisgrace.png differ diff --git a/public/img/logos/kink/lazy/sadisticrope.png b/public/img/logos/kink/lazy/sadisticrope.png index 06240c4f..cc289dda 100644 Binary files a/public/img/logos/kink/lazy/sadisticrope.png and b/public/img/logos/kink/lazy/sadisticrope.png differ diff --git a/public/img/logos/kink/lazy/sexandsubmission.png b/public/img/logos/kink/lazy/sexandsubmission.png index 43cc4817..682a3b08 100644 Binary files a/public/img/logos/kink/lazy/sexandsubmission.png and b/public/img/logos/kink/lazy/sexandsubmission.png differ diff --git a/public/img/logos/kink/lazy/strugglingbabes.png b/public/img/logos/kink/lazy/strugglingbabes.png index 544be857..c308fc19 100644 Binary files a/public/img/logos/kink/lazy/strugglingbabes.png and b/public/img/logos/kink/lazy/strugglingbabes.png differ diff --git a/public/img/logos/kink/lazy/thetrainingofo.png b/public/img/logos/kink/lazy/thetrainingofo.png index 6dfa0894..1e8513f2 100644 Binary files a/public/img/logos/kink/lazy/thetrainingofo.png and b/public/img/logos/kink/lazy/thetrainingofo.png differ diff --git a/public/img/logos/kink/lazy/theupperfloor.png b/public/img/logos/kink/lazy/theupperfloor.png index 3362ecd3..645f70b5 100644 Binary files a/public/img/logos/kink/lazy/theupperfloor.png and b/public/img/logos/kink/lazy/theupperfloor.png differ diff --git a/public/img/logos/kink/lazy/thirtyminutesoftorment.png b/public/img/logos/kink/lazy/thirtyminutesoftorment.png index 5550b06a..af5ded00 100644 Binary files a/public/img/logos/kink/lazy/thirtyminutesoftorment.png and b/public/img/logos/kink/lazy/thirtyminutesoftorment.png differ diff --git a/public/img/logos/kink/lazy/tspussyhunters.png b/public/img/logos/kink/lazy/tspussyhunters.png index 4cbaa7ab..eebada52 100644 Binary files a/public/img/logos/kink/lazy/tspussyhunters.png and b/public/img/logos/kink/lazy/tspussyhunters.png differ diff --git a/public/img/logos/kink/lazy/tsseduction.png b/public/img/logos/kink/lazy/tsseduction.png index d65401d9..542250e1 100644 Binary files a/public/img/logos/kink/lazy/tsseduction.png and b/public/img/logos/kink/lazy/tsseduction.png differ diff --git a/public/img/logos/kink/lazy/ultimatesurrender.png b/public/img/logos/kink/lazy/ultimatesurrender.png index 6340be90..6eb621e0 100644 Binary files a/public/img/logos/kink/lazy/ultimatesurrender.png and b/public/img/logos/kink/lazy/ultimatesurrender.png differ diff --git a/public/img/logos/kink/lazy/waterbondage.png b/public/img/logos/kink/lazy/waterbondage.png index e31f301b..69e511d1 100644 Binary files a/public/img/logos/kink/lazy/waterbondage.png and b/public/img/logos/kink/lazy/waterbondage.png differ diff --git a/public/img/logos/kink/lazy/whippedass.png b/public/img/logos/kink/lazy/whippedass.png index 0947df11..cef334fc 100644 Binary files a/public/img/logos/kink/lazy/whippedass.png and b/public/img/logos/kink/lazy/whippedass.png differ diff --git a/public/img/logos/kink/lazy/wiredpussy.png b/public/img/logos/kink/lazy/wiredpussy.png index 30612b66..781e6e87 100644 Binary files a/public/img/logos/kink/lazy/wiredpussy.png and b/public/img/logos/kink/lazy/wiredpussy.png differ diff --git a/public/img/logos/kink/thumbs/boundgangbangs.png b/public/img/logos/kink/thumbs/boundgangbangs.png index 31bc5f6e..05cc3999 100644 Binary files a/public/img/logos/kink/thumbs/boundgangbangs.png and b/public/img/logos/kink/thumbs/boundgangbangs.png differ diff --git a/public/img/logos/kink/thumbs/boundgods.png b/public/img/logos/kink/thumbs/boundgods.png index ab692507..bd42fd4c 100644 Binary files a/public/img/logos/kink/thumbs/boundgods.png and b/public/img/logos/kink/thumbs/boundgods.png differ diff --git a/public/img/logos/kink/thumbs/boundinpublic.png b/public/img/logos/kink/thumbs/boundinpublic.png index 6879726a..125915a5 100644 Binary files a/public/img/logos/kink/thumbs/boundinpublic.png and b/public/img/logos/kink/thumbs/boundinpublic.png differ diff --git a/public/img/logos/kink/thumbs/brutalsessions.png b/public/img/logos/kink/thumbs/brutalsessions.png index 110d01ec..e73b6dd4 100644 Binary files a/public/img/logos/kink/thumbs/brutalsessions.png and b/public/img/logos/kink/thumbs/brutalsessions.png differ diff --git a/public/img/logos/kink/thumbs/buttmachineboys.png b/public/img/logos/kink/thumbs/buttmachineboys.png index a4c61861..de6f2eec 100644 Binary files a/public/img/logos/kink/thumbs/buttmachineboys.png and b/public/img/logos/kink/thumbs/buttmachineboys.png differ diff --git a/public/img/logos/kink/thumbs/devicebondage.png b/public/img/logos/kink/thumbs/devicebondage.png index 050ab89b..db572a2a 100644 Binary files a/public/img/logos/kink/thumbs/devicebondage.png and b/public/img/logos/kink/thumbs/devicebondage.png differ diff --git a/public/img/logos/kink/thumbs/divinebitches.png b/public/img/logos/kink/thumbs/divinebitches.png index 9a4cbfae..0c8427a5 100644 Binary files a/public/img/logos/kink/thumbs/divinebitches.png and b/public/img/logos/kink/thumbs/divinebitches.png differ diff --git a/public/img/logos/kink/thumbs/electrosluts.png b/public/img/logos/kink/thumbs/electrosluts.png index 0ac2d54c..0f483a35 100644 Binary files a/public/img/logos/kink/thumbs/electrosluts.png and b/public/img/logos/kink/thumbs/electrosluts.png differ diff --git a/public/img/logos/kink/thumbs/everythingbutt.png b/public/img/logos/kink/thumbs/everythingbutt.png index 0d6aed99..6734970b 100644 Binary files a/public/img/logos/kink/thumbs/everythingbutt.png and b/public/img/logos/kink/thumbs/everythingbutt.png differ diff --git a/public/img/logos/kink/thumbs/familiestied.png b/public/img/logos/kink/thumbs/familiestied.png index 3e53a7da..709a1873 100644 Binary files a/public/img/logos/kink/thumbs/familiestied.png and b/public/img/logos/kink/thumbs/familiestied.png differ diff --git a/public/img/logos/kink/thumbs/favicon.png b/public/img/logos/kink/thumbs/favicon.png index 28fca58a..b06d0113 100644 Binary files a/public/img/logos/kink/thumbs/favicon.png and b/public/img/logos/kink/thumbs/favicon.png differ diff --git a/public/img/logos/kink/thumbs/filthyfemdom.png b/public/img/logos/kink/thumbs/filthyfemdom.png index 4b796fe4..9bfbde45 100644 Binary files a/public/img/logos/kink/thumbs/filthyfemdom.png and b/public/img/logos/kink/thumbs/filthyfemdom.png differ diff --git a/public/img/logos/kink/thumbs/footworship.png b/public/img/logos/kink/thumbs/footworship.png index 26ebda62..cea93074 100644 Binary files a/public/img/logos/kink/thumbs/footworship.png and b/public/img/logos/kink/thumbs/footworship.png differ diff --git a/public/img/logos/kink/thumbs/fuckedandbound.png b/public/img/logos/kink/thumbs/fuckedandbound.png index b338f041..3c7cdd7a 100644 Binary files a/public/img/logos/kink/thumbs/fuckedandbound.png and b/public/img/logos/kink/thumbs/fuckedandbound.png differ diff --git a/public/img/logos/kink/thumbs/fuckingmachines.png b/public/img/logos/kink/thumbs/fuckingmachines.png index 7f173547..e5c1cd2a 100644 Binary files a/public/img/logos/kink/thumbs/fuckingmachines.png and b/public/img/logos/kink/thumbs/fuckingmachines.png differ diff --git a/public/img/logos/kink/thumbs/hardcoregangbang.png b/public/img/logos/kink/thumbs/hardcoregangbang.png index 3577ad13..163aa0c2 100644 Binary files a/public/img/logos/kink/thumbs/hardcoregangbang.png and b/public/img/logos/kink/thumbs/hardcoregangbang.png differ diff --git a/public/img/logos/kink/thumbs/hogtied.png b/public/img/logos/kink/thumbs/hogtied.png index 25bcc58c..abc26023 100644 Binary files a/public/img/logos/kink/thumbs/hogtied.png and b/public/img/logos/kink/thumbs/hogtied.png differ diff --git a/public/img/logos/kink/thumbs/kink-dvd.png b/public/img/logos/kink/thumbs/kink-dvd.png index c3ffd644..95db997f 100644 Binary files a/public/img/logos/kink/thumbs/kink-dvd.png and b/public/img/logos/kink/thumbs/kink-dvd.png differ diff --git a/public/img/logos/kink/thumbs/kinkfeatures.png b/public/img/logos/kink/thumbs/kinkfeatures.png index 4a6b62ca..2015ad21 100644 Binary files a/public/img/logos/kink/thumbs/kinkfeatures.png and b/public/img/logos/kink/thumbs/kinkfeatures.png differ diff --git a/public/img/logos/kink/thumbs/kinkuniversity.png b/public/img/logos/kink/thumbs/kinkuniversity.png index 41e4be99..e3589b9e 100644 Binary files a/public/img/logos/kink/thumbs/kinkuniversity.png and b/public/img/logos/kink/thumbs/kinkuniversity.png differ diff --git a/public/img/logos/kink/thumbs/kinkybites.png b/public/img/logos/kink/thumbs/kinkybites.png new file mode 100644 index 00000000..e65ad9a6 Binary files /dev/null and b/public/img/logos/kink/thumbs/kinkybites.png differ diff --git a/public/img/logos/kink/thumbs/meninpain.png b/public/img/logos/kink/thumbs/meninpain.png index 77374421..7dee04d9 100644 Binary files a/public/img/logos/kink/thumbs/meninpain.png and b/public/img/logos/kink/thumbs/meninpain.png differ diff --git a/public/img/logos/kink/thumbs/menonedge.png b/public/img/logos/kink/thumbs/menonedge.png index 7ec3fc28..27daf019 100644 Binary files a/public/img/logos/kink/thumbs/menonedge.png and b/public/img/logos/kink/thumbs/menonedge.png differ diff --git a/public/img/logos/kink/thumbs/nakedkombat.png b/public/img/logos/kink/thumbs/nakedkombat.png index 20098fb3..e31201a1 100644 Binary files a/public/img/logos/kink/thumbs/nakedkombat.png and b/public/img/logos/kink/thumbs/nakedkombat.png differ diff --git a/public/img/logos/kink/thumbs/network.png b/public/img/logos/kink/thumbs/network.png index d8a83448..45b489b8 100644 Binary files a/public/img/logos/kink/thumbs/network.png and b/public/img/logos/kink/thumbs/network.png differ diff --git a/public/img/logos/kink/thumbs/publicdisgrace.png b/public/img/logos/kink/thumbs/publicdisgrace.png index 3a0a2e02..4ef0172b 100644 Binary files a/public/img/logos/kink/thumbs/publicdisgrace.png and b/public/img/logos/kink/thumbs/publicdisgrace.png differ diff --git a/public/img/logos/kink/thumbs/sadisticrope.png b/public/img/logos/kink/thumbs/sadisticrope.png index 52a491b6..92cf72e5 100644 Binary files a/public/img/logos/kink/thumbs/sadisticrope.png and b/public/img/logos/kink/thumbs/sadisticrope.png differ diff --git a/public/img/logos/kink/thumbs/sexandsubmission.png b/public/img/logos/kink/thumbs/sexandsubmission.png index 139aab93..4c3cdc71 100644 Binary files a/public/img/logos/kink/thumbs/sexandsubmission.png and b/public/img/logos/kink/thumbs/sexandsubmission.png differ diff --git a/public/img/logos/kink/thumbs/strugglingbabes.png b/public/img/logos/kink/thumbs/strugglingbabes.png index a80423f3..cc224f7e 100644 Binary files a/public/img/logos/kink/thumbs/strugglingbabes.png and b/public/img/logos/kink/thumbs/strugglingbabes.png differ diff --git a/public/img/logos/kink/thumbs/thetrainingofo.png b/public/img/logos/kink/thumbs/thetrainingofo.png index b702e3d1..4a022d15 100644 Binary files a/public/img/logos/kink/thumbs/thetrainingofo.png and b/public/img/logos/kink/thumbs/thetrainingofo.png differ diff --git a/public/img/logos/kink/thumbs/theupperfloor.png b/public/img/logos/kink/thumbs/theupperfloor.png index 0e636826..c3c119d1 100644 Binary files a/public/img/logos/kink/thumbs/theupperfloor.png and b/public/img/logos/kink/thumbs/theupperfloor.png differ diff --git a/public/img/logos/kink/thumbs/thirtyminutesoftorment.png b/public/img/logos/kink/thumbs/thirtyminutesoftorment.png index ee38d8d0..a061c9ec 100644 Binary files a/public/img/logos/kink/thumbs/thirtyminutesoftorment.png and b/public/img/logos/kink/thumbs/thirtyminutesoftorment.png differ diff --git a/public/img/logos/kink/thumbs/tspussyhunters.png b/public/img/logos/kink/thumbs/tspussyhunters.png index ea0e5c22..9bad63fa 100644 Binary files a/public/img/logos/kink/thumbs/tspussyhunters.png and b/public/img/logos/kink/thumbs/tspussyhunters.png differ diff --git a/public/img/logos/kink/thumbs/tsseduction.png b/public/img/logos/kink/thumbs/tsseduction.png index 1955a6dc..bad5bcff 100644 Binary files a/public/img/logos/kink/thumbs/tsseduction.png and b/public/img/logos/kink/thumbs/tsseduction.png differ diff --git a/public/img/logos/kink/thumbs/ultimatesurrender.png b/public/img/logos/kink/thumbs/ultimatesurrender.png index 2e39e114..7371d604 100644 Binary files a/public/img/logos/kink/thumbs/ultimatesurrender.png and b/public/img/logos/kink/thumbs/ultimatesurrender.png differ diff --git a/public/img/logos/kink/thumbs/waterbondage.png b/public/img/logos/kink/thumbs/waterbondage.png index 353b7060..a83ade92 100644 Binary files a/public/img/logos/kink/thumbs/waterbondage.png and b/public/img/logos/kink/thumbs/waterbondage.png differ diff --git a/public/img/logos/kink/thumbs/whippedass.png b/public/img/logos/kink/thumbs/whippedass.png index 22d8d985..386489f3 100644 Binary files a/public/img/logos/kink/thumbs/whippedass.png and b/public/img/logos/kink/thumbs/whippedass.png differ diff --git a/public/img/logos/kink/thumbs/wiredpussy.png b/public/img/logos/kink/thumbs/wiredpussy.png index 46a0131e..b217c0eb 100644 Binary files a/public/img/logos/kink/thumbs/wiredpussy.png and b/public/img/logos/kink/thumbs/wiredpussy.png differ diff --git a/public/img/logos/wgcz/favicon.png b/public/img/logos/wgcz/favicon.png new file mode 100644 index 00000000..ef5ea108 Binary files /dev/null and b/public/img/logos/wgcz/favicon.png differ diff --git a/public/img/logos/wgcz/lazy/favicon.png b/public/img/logos/wgcz/lazy/favicon.png new file mode 100644 index 00000000..3d453e5c Binary files /dev/null and b/public/img/logos/wgcz/lazy/favicon.png differ diff --git a/public/img/logos/wgcz/lazy/network.png b/public/img/logos/wgcz/lazy/network.png new file mode 100644 index 00000000..be20716b Binary files /dev/null and b/public/img/logos/wgcz/lazy/network.png differ diff --git a/public/img/logos/wgcz/misc/xvideos_bg.png b/public/img/logos/wgcz/misc/xvideos_bg.png new file mode 100644 index 00000000..2b1cd842 Binary files /dev/null and b/public/img/logos/wgcz/misc/xvideos_bg.png differ diff --git a/public/img/logos/wgcz/network.png b/public/img/logos/wgcz/network.png new file mode 100644 index 00000000..00784fd2 Binary files /dev/null and b/public/img/logos/wgcz/network.png differ diff --git a/public/img/logos/wgcz/thumbs/favicon.png b/public/img/logos/wgcz/thumbs/favicon.png new file mode 100644 index 00000000..fddd0810 Binary files /dev/null and b/public/img/logos/wgcz/thumbs/favicon.png differ diff --git a/public/img/logos/wgcz/thumbs/network.png b/public/img/logos/wgcz/thumbs/network.png new file mode 100644 index 00000000..2b81bc9f Binary files /dev/null and b/public/img/logos/wgcz/thumbs/network.png differ diff --git a/seeds/01_networks.js b/seeds/01_networks.js index 8ceda11a..9b85e167 100644 --- a/seeds/01_networks.js +++ b/seeds/01_networks.js @@ -21,6 +21,10 @@ const parentNetworks = [ slug: 'whalemember', name: 'Whale Member', }, + { + slug: 'wgcz', + name: 'WGCZ Holding', + }, ]; const networks = [ @@ -98,6 +102,7 @@ const networks = [ name: 'Bang Bros', url: 'https://bangbros.com', description: 'Here at Bang Bros, we only film the best highest quality porn with the sexiest Amateur girls and the top pornstars. Updated daily on Bangbros.com.', + parent: 'wgcz', }, { slug: 'blowpass', @@ -120,7 +125,7 @@ const networks = [ slug: 'boobpedia', name: 'Boobpedia', url: 'https://www.boobpedia.com', - type: 4, + type: 'info', }, { slug: 'burningangel', @@ -142,13 +147,14 @@ const networks = [ slug: 'freeones', name: 'FreeOnes', url: 'https://www.freeones.com', - type: 4, + type: 'info', }, { slug: 'ddfnetwork', name: 'DDF Network', url: 'https://ddfnetwork.com', description: 'European porn videos hub with exclusive VR, 4K and full HD XXX videos and hot sex photos of Europes finest porn star babes.', + parent: 'wgcz', }, { slug: 'digitalplayground', @@ -272,6 +278,7 @@ const networks = [ name: 'LegalPorno', url: 'https://www.legalporno.com', description: 'The Best HD Porn For You!', + parent: 'wgcz', }, { slug: 'men', @@ -355,6 +362,7 @@ const networks = [ name: 'Private', url: 'https://www.private.com', description: 'Private is the best source for adult movies and videos. Featuring the most popular hardcore adult stars in hundreds of porn movies, Private.com delivers...', + parent: 'wgcz', }, { slug: 'puretaboo', @@ -437,13 +445,13 @@ const networks = [ exports.seed = knex => Promise.resolve() .then(async () => { - const { inserted, updated } = await upsert('entities', parentNetworks.map(network => ({ ...network, type: 1 })), ['slug', 'type'], knex); + const { inserted, updated } = await upsert('entities', parentNetworks.map(network => ({ ...network, type: 'network' })), ['slug', 'type'], knex); const parentNetworksBySlug = [].concat(inserted, updated).reduce((acc, network) => ({ ...acc, [network.slug]: network.id }), {}); const networksWithParent = networks.map(network => ({ slug: network.slug, name: network.name, - type: network.type || 1, + type: network.type || 'network', alias: network.alias ? network.alias.join(',') : null, url: network.url, description: network.description, diff --git a/seeds/02_sites.js b/seeds/02_sites.js index 7ddd9bd2..16c37c81 100644 --- a/seeds/02_sites.js +++ b/seeds/02_sites.js @@ -2830,6 +2830,13 @@ const sites = [ description: 'Learn BDSM Technical Skills & Theories From Respected Teachers In The Kink Community. Learn BDSM skills and improve your sex techniques. Video tutorials feature top sex ed experts and hardcore demos on topics from bondage to relationships.', network: 'kink', }, + { + slug: 'kinkybites', + name: 'Kinky Bites', + url: 'https://www.kink.com/channel/kinkybites', + description: 'Come see what the hottest kink models have for you at home. Sink your teeth into this kinky private collection made just for you.', + network: 'kink', + }, { slug: 'meninpain', name: 'Men In Pain', @@ -6369,7 +6376,7 @@ exports.seed = knex => Promise.resolve() const sitesWithNetworks = sites.map(site => ({ slug: site.slug, name: site.name, - type: site.type || 2, + type: site.type || 'channel', alias: (site.alias || []).join(','), description: site.description, url: site.url, diff --git a/seeds/03_studios.js b/seeds/03_studios.js index 0b54d534..6994aa35 100644 --- a/seeds/03_studios.js +++ b/seeds/03_studios.js @@ -153,17 +153,13 @@ function getStudios(networksMap) { /* eslint-disable max-len */ exports.seed = knex => Promise.resolve() .then(async () => { - const [networks, types] = await Promise.all([ - knex('entities').select('*'), - knex('entities_types').select('*'), - ]); + const networks = await knex('entities').select('*').where('type', 'network'); const networksMap = networks.reduce((acc, { id, slug }) => ({ ...acc, [slug]: id }), {}); - const typesMap = types.reduce((acc, type) => ({ [type.type]: type.id }), {}); const studios = getStudios(networksMap).map(studio => ({ ...studio, - type: typesMap.studio, + type: 'studio', })); return upsert('entities', studios, 'slug', knex); diff --git a/src/app.js b/src/app.js index 6bed361c..a9474948 100644 --- a/src/app.js +++ b/src/app.js @@ -24,7 +24,7 @@ async function init() { const actors = argv.actors && await scrapeActors(argv.actors); const actorBaseScenes = argv.actors && argv.actorScenes && actors.map(actor => actor.releases).flat().filter(Boolean); - const updateBaseScenes = (argv.scrape || argv.sites || argv.networks) && await fetchUpdates(); + const updateBaseScenes = (argv.scrape || argv.channels || argv.networks) && await fetchUpdates(); const deepScenes = argv.deep ? await fetchScenes([...(argv.scenes || []), ...(updateBaseScenes || []), ...(actorBaseScenes || [])]) diff --git a/src/argv.js b/src/argv.js index a1851dfb..632ce9eb 100644 --- a/src/argv.js +++ b/src/argv.js @@ -11,23 +11,18 @@ const { argv } = yargs alias: 'web', }) .option('scrape', { - describe: 'Scrape sites and networks defined in configuration', + describe: 'Scrape channels and networks defined in configuration', type: 'boolean', }) .option('networks', { - describe: 'Networks to scrape (overrides configuration)', + describe: 'Network to scrape all channels from (overrides configuration)', type: 'array', alias: 'network', }) - .option('sites', { - describe: 'Sites to scrape (overrides configuration)', + .option('channels', { + describe: 'Channel to scrape (overrides configuration)', type: 'array', - alias: 'site', - }) - .option('entities', { - describe: 'Networks or sites to scrape (overrides configuration)', - type: 'array', - alias: 'entity', + alias: 'channel', }) .option('actors', { describe: 'Scrape actors by name or slug', diff --git a/src/entities.js b/src/entities.js index 1984319c..4e93c86b 100644 --- a/src/entities.js +++ b/src/entities.js @@ -20,7 +20,7 @@ function curateEntity(entity, includeParameters = false) { children: (entity.children || []).map(child => curateEntity({ ...child, parent: entity, - })), + }, includeParameters)), }; return curatedEntity; @@ -30,39 +30,40 @@ async function curateEntities(entities, includeParameters) { return Promise.all(entities.map(async entity => curateEntity(entity, includeParameters))); } -async function fetchSitesFromArgv() { +async function fetchChannelsFromArgv() { const rawNetworks = await knex.raw(` - /* networks from argument with sites as children */ - WITH RECURSIVE temp AS ( + /* networks from argument with channels as children */ + WITH RECURSIVE children AS ( SELECT id, parent_id, name, slug, type, url, description, parameters FROM entities WHERE - slug = ANY(?) AND entities.type = 1 + slug = ANY(?) AND entities.type = 'network' UNION ALL SELECT entities.id, entities.parent_id, entities.name, entities.slug, entities.type, entities.url, entities.description, entities.parameters FROM entities INNER JOIN - temp ON temp.id = entities.parent_id + children ON children.id = entities.parent_id ) SELECT - entities.*, row_to_json(parents) as parent, json_agg(temp) as children + entities.*, row_to_json(parents) as parent, json_agg(children) as children FROM - temp + children LEFT JOIN - entities ON entities.id = temp.parent_id + entities ON entities.id = children.parent_id LEFT JOIN entities AS parents ON parents.id = entities.parent_id WHERE - temp.type = 2 + children.type = 'channel' GROUP BY - temp.parent_id, entities.id, entities.name, parents.id + children.parent_id, entities.id, entities.name, parents.id + UNION ALL - /* sites from argument as the child of network with parent */ + /* channels from argument as the child of network with parent */ SELECT entities.*, row_to_json(parents) as parent, json_agg(row_to_json(children)) FROM @@ -72,10 +73,10 @@ async function fetchSitesFromArgv() { LEFT JOIN entities AS parents ON parents.id = entities.parent_id WHERE - children.slug = ANY(?) AND children.type = 2 + children.slug = ANY(?) AND children.type = 'channel' GROUP BY entities.id, parents.id; - `, [argv.networks || [], argv.sites || []]); + `, [argv.networks || [], argv.channels || []]); const curatedNetworks = await curateEntities(rawNetworks.rows, true); logger.info(`Found ${curatedNetworks.length} networks in database`); @@ -83,10 +84,10 @@ async function fetchSitesFromArgv() { return curatedNetworks; } -async function fetchSitesFromConfig() { +async function fetchChannelsFromConfig() { const rawSites = await knex('entities') - .select('entities.*') - .leftJoin('entities as entities_parents', 'entities_parents.id', 'entities.id') + .select(knex.raw('entities.*, row_to_json(parents) as parent')) + .leftJoin('entities as parents', 'parents.id', 'entities.parent_id') .where((builder) => { if (config.include) { builder.whereIn('entities.slug', config.include); @@ -103,14 +104,14 @@ async function fetchSitesFromConfig() { } async function fetchIncludedEntities() { - if (argv.networks || argv.sites) { - return fetchSitesFromArgv(); + if (argv.networks || argv.channels) { + return fetchChannelsFromArgv(); } - return fetchSitesFromConfig(); + return fetchChannelsFromConfig(); } -async function fetchSites(queryObject) { +async function fetchChannels(queryObject) { const sites = await knex('sites') .where(builder => whereOr(queryObject, 'sites', builder)) .select( @@ -123,7 +124,7 @@ async function fetchSites(queryObject) { return curateEntities(sites); } -async function fetchSitesFromReleases() { +async function fetchChannelsFromReleases() { const sites = await knex('releases') .select('site_id', '') .leftJoin('sites', 'sites.id', 'releases.site_id') @@ -137,8 +138,8 @@ module.exports = { curateEntity, curateEntities, fetchIncludedEntities, - fetchSites, - fetchSitesFromConfig, - fetchSitesFromArgv, - fetchSitesFromReleases, + fetchChannels, + fetchChannelsFromConfig, + fetchChannelsFromArgv, + fetchChannelsFromReleases, }; diff --git a/src/scrapers/kink.js b/src/scrapers/kink.js index 35ed5f5b..a63ad7e2 100644 --- a/src/scrapers/kink.js +++ b/src/scrapers/kink.js @@ -1,117 +1,97 @@ 'use strict'; -const bhttp = require('bhttp'); -const cheerio = require('cheerio'); -const moment = require('moment'); +const { get, getAll } = require('../utils/qu'); -function scrapeLatest(html, site) { - const $ = cheerio.load(html, { normalizeWhitespace: true }); - const sceneElements = $('.shoot-list .shoot').toArray(); +function scrapeLatest(scenes) { + return scenes.map(({ qu }) => { + const release = {}; - return sceneElements.map((element) => { - const sceneLinkElement = $(element).find('.shoot-thumb-title a'); - const href = sceneLinkElement.attr('href'); - const url = `https://kink.com${href}`; - const shootId = href.split('/')[2]; - const title = sceneLinkElement.text().trim(); + const href = qu.url('.shoot-thumb-title a'); + release.url = `https://kink.com${href}`; - const poster = $(element).find('.adimage').attr('src'); - const photos = $(element).find('.rollover .roll-image').map((photoIndex, photoElement) => $(photoElement).attr('data-imagesrc')).toArray(); + release.shootId = href.split('/').slice(-1)[0]; + release.entryId = release.shootId; - const date = moment.utc($(element).find('.date').text(), 'MMM DD, YYYY').toDate(); - const actors = $(element).find('.shoot-thumb-models a').map((actorIndex, actorElement) => $(actorElement).text()).toArray(); - const stars = $(element).find('.average-rating').attr('data-rating') / 10; + release.title = qu.q('.shoot-thumb-title a', true); + release.date = qu.date('.date', 'MMM DD, YYYY'); - const timestamp = $(element).find('.video span').text(); - const timestampComponents = timestamp.split(':'); // fix mixed hh:mm:ss and mm:ss format - const duration = moment.duration(timestampComponents.length > 2 ? timestamp : `0:${timestamp}`).asSeconds(); + release.actors = qu.all('.shoot-thumb-models a', true); + release.stars = qu.q('.average-rating', 'data-rating') / 10; - return { - url, - shootId, - entryId: shootId, - title, - actors, - date, - photos, - poster, - rating: { - stars, - }, - duration, - site, - }; + release.poster = qu.img('.adimage'); + release.photos = qu.imgs('.rollover .roll-image', 'data-imagesrc').map(photo => [ + photo.replace('410/', '830/'), + photo, + ]); + + release.duration = qu.dur('.video span'); + + return release; }); } -async function scrapeScene(html, url, shootId, ratingRes, site) { - const $ = cheerio.load(html, { normalizeWhitespace: true }); +async function scrapeScene({ qu }, url) { + const release = { url }; - // const title = $('h1.shoot-title').text().replace(/\ue800/, ''); // fallback, special character is 'like'-heart - const title = $('h1.shoot-title span.favorite-button').attr('data-title'); - const actorsRaw = $('.shoot-info p.starring'); + release.shootId = new URL(url).pathname.split('/')[2]; + release.entryId = release.shootId; - const photos = $('.gallery .thumb img').map((photoIndex, photoElement) => $(photoElement).attr('data-image-file')).toArray(); - const trailerVideo = $('.player span[data-type="trailer-src"]').attr('data-url'); - const trailerPoster = $('.player video#kink-player').attr('poster'); + release.title = qu.q('.shoot-title span.favorite-button', 'data-title'); + release.description = qu.q('.description-text', true); - const date = moment.utc($(actorsRaw) - .prev() - .text() - .trim() - .replace('Date: ', ''), - 'MMMM DD, YYYY') - .toDate(); + release.date = qu.date('.shoot-date', 'MMMM DD, YYYY'); + release.actors = qu.all('.names a', true).map(actor => actor.replace(/,\s*/, '')); + release.director = qu.q('.director-name', true); - const actors = $(actorsRaw).find('span.names a').map((actorIndex, actorElement) => $(actorElement).text()).toArray(); - const description = $('.shoot-info .description').text().trim(); + release.photos = qu.imgs('.gallery .thumb img', 'data-image-file'); + release.poster = qu.poster(); - const { average: stars } = ratingRes.body; + release.tags = qu.all('.tag-list a[href*="/tag"]', true).map(tag => tag.replace(/,\s*/, '')); - const siteName = $('.shoot-logo a').attr('href').split('/')[2]; - const siteSlug = siteName.replace(/\s+/g, '').toLowerCase(); + const trailer = qu.q('.player span[data-type="trailer-src"]', 'data-url'); - const tags = $('.tag-list > a[href*="/tag"]').map((tagIndex, tagElement) => $(tagElement).text()).toArray(); - const channel = siteSlug; - - return { - url, - shootId, - entryId: shootId, - title, - date, - actors, - description, - photos, - poster: trailerPoster, - trailer: { - src: trailerVideo, + release.trailer = [ + { + src: trailer.replace('480p', '1080p'), + quality: 1080, + }, + { + src: trailer.replace('480p', '720p'), + quality: 720, + }, + { + src: trailer, quality: 480, }, - rating: { - stars, + { + src: trailer.replace('480p', '360p'), + quality: 360, }, - tags, - site, - channel, - }; + ]; + + release.channel = qu.url('.shoot-logo a').split('/').slice(-1)[0]; + + return release; } async function fetchLatest(site, page = 1) { - const res = await bhttp.get(`${site.url}/latest/page/${page}`); + const res = await getAll(`${site.url}/latest/page/${page}`, '.shoot-list .shoot'); - return scrapeLatest(res.body.toString(), site); + if (res.ok) { + return scrapeLatest(res.items, site); + } + + return res.status; } async function fetchScene(url, site) { - const shootId = new URL(url).pathname.split('/')[2]; + const res = await get(url); - const [res, ratingRes] = await Promise.all([ - bhttp.get(url), - bhttp.get(`https://kink.com/api/ratings/${shootId}`), - ]); + if (res.ok) { + return scrapeScene(res.item, url, site); + } - return scrapeScene(res.body.toString(), url, shootId, ratingRes, site); + return res.status; } module.exports = { diff --git a/src/updates.js b/src/updates.js index d2eaa5b1..8019f632 100644 --- a/src/updates.js +++ b/src/updates.js @@ -8,7 +8,7 @@ const logger = require('./logger')(__filename); const knex = require('./knex'); const include = require('./utils/argv-include')(argv); const scrapers = require('./scrapers/scrapers'); -const { fetchSitesFromArgv, fetchSitesFromConfig } = require('./entities'); +const { fetchChannelsFromArgv, fetchChannelsFromConfig } = require('./entities'); const afterDate = (() => { if (/\d{2,4}-\d{2}-\d{2,4}/.test(argv.after)) { @@ -27,7 +27,7 @@ const afterDate = (() => { async function filterUniqueReleases(latestReleases, accReleases) { const latestReleaseIdentifiers = latestReleases - .map(release => [release.site.id, release.entryId]); + .map(release => [release.entity.id, release.entryId]); const duplicateReleases = await knex('releases') .whereIn(['entity_id', 'entry_id'], latestReleaseIdentifiers); @@ -37,17 +37,17 @@ async function filterUniqueReleases(latestReleases, accReleases) { const duplicateReleasesSiteIdAndEntryIds = duplicateReleases .concat(accReleases) .reduce((acc, release) => { - const siteId = release.entity_id || release.site.id; + const entityId = release.entity_id || release.entity.id; const entryId = release.entry_id || release.entryId; - if (!acc[siteId]) acc[siteId] = {}; - acc[siteId][entryId] = true; + if (!acc[entityId]) acc[entityId] = {}; + acc[entityId][entryId] = true; return acc; }, {}); const uniqueReleases = latestReleases - .filter(release => !duplicateReleasesSiteIdAndEntryIds[release.site.id]?.[release.entryId]); + .filter(release => !duplicateReleasesSiteIdAndEntryIds[release.entity.id]?.[release.entryId]); return uniqueReleases; } @@ -77,15 +77,15 @@ function needNextPage(uniqueReleases, pageAccReleases) { return pageAccReleases.length <= argv.nullDateLimit; } -async function scrapeReleases(scraper, site, preData, upcoming = false) { +async function scrapeReleases(scraper, entity, preData, upcoming = false) { const scrapePage = async (page = 1, accReleases = []) => { const latestReleases = upcoming - ? await scraper.fetchUpcoming(site, page, preData, include) - : await scraper.fetchLatest(site, page, preData, include); + ? await scraper.fetchUpcoming(entity, page, preData, include) + : await scraper.fetchLatest(entity, page, preData, include); if (!Array.isArray(latestReleases)) { // scraper is unable to fetch the releases and returned a HTTP code or null - logger.warn(`Scraper returned ${latestReleases} when fetching latest from '${site.name}' (${site.parent?.name})`); + logger.warn(`Scraper returned ${latestReleases} when fetching latest from '${entity.name}' (${entity.parent?.name})`); return accReleases; } @@ -94,15 +94,15 @@ async function scrapeReleases(scraper, site, preData, upcoming = false) { return accReleases; } - const latestReleasesWithSite = latestReleases.map(release => ({ ...release, site: release.site || site })); // attach site release is assigned to when stored + const latestReleasesWithEntity = latestReleases.map(release => ({ ...release, entity })); // attach entity the release is assigned to when stored const uniqueReleases = argv.redownload - ? latestReleasesWithSite - : await filterUniqueReleases(latestReleasesWithSite, accReleases); + ? latestReleasesWithEntity + : await filterUniqueReleases(latestReleasesWithEntity, accReleases); const pageAccReleases = accReleases.concat(uniqueReleases); - logger.verbose(`Scraped '${site.name}' (${site.parent?.name}) ${upcoming ? 'upcoming' : 'latest'} page ${page}, found ${uniqueReleases.length} unique updates`); + logger.verbose(`Scraped '${entity.name}' (${entity.parent?.name}) ${upcoming ? 'upcoming' : 'latest'} page ${page}, found ${uniqueReleases.length} unique updates`); if (needNextPage(uniqueReleases, pageAccReleases)) { return scrapePage(page + 1, pageAccReleases); @@ -127,70 +127,70 @@ async function scrapeReleases(scraper, site, preData, upcoming = false) { return releases.slice(0, argv.nullDateLimit); } -async function scrapeLatestReleases(scraper, site, preData) { +async function scrapeLatestReleases(scraper, entity, preData) { if (!scraper.fetchLatest) { return []; } try { - return await scrapeReleases(scraper, site, preData, false); + return await scrapeReleases(scraper, entity, preData, false); } catch (error) { - logger.warn(`Failed to scrape latest updates for '${site.slug}' (${site.parent?.slug}): ${error.message}`); + logger.warn(`Failed to scrape latest updates for '${entity.slug}' (${entity.parent?.slug}): ${error.message}`); } return []; } -async function scrapeUpcomingReleases(scraper, site, preData) { +async function scrapeUpcomingReleases(scraper, entity, preData) { if (!scraper.fetchUpcoming) { return []; } try { - return await scrapeReleases(scraper, site, preData, true); + return await scrapeReleases(scraper, entity, preData, true); } catch (error) { - logger.warn(`Failed to scrape upcoming updates for '${site.slug}' (${site.parent?.slug}): ${error.message}`); + logger.warn(`Failed to scrape upcoming updates for '${entity.slug}' (${entity.parent?.slug}): ${error.message}`); } return []; } -async function scrapeSiteReleases(scraper, site, preData) { +async function scrapeChannelReleases(scraper, channelEntity, preData) { const [latestReleases, upcomingReleases] = await Promise.all([ argv.latest - ? scrapeLatestReleases(scraper, site, preData) + ? scrapeLatestReleases(scraper, channelEntity, preData) : [], argv.upcoming - ? scrapeUpcomingReleases(scraper, site, preData) + ? scrapeUpcomingReleases(scraper, channelEntity, preData) : [], ]); - logger.info(`Fetching ${latestReleases.length} latest and ${upcomingReleases.length} upcoming updates for '${site.name}' (${site.parent.name})`); + logger.info(`Fetching ${latestReleases.length} latest and ${upcomingReleases.length} upcoming updates for '${channelEntity.name}' (${channelEntity.parent.name})`); return [...latestReleases, ...upcomingReleases]; } -async function scrapeSite(site, accSiteReleases) { - const scraper = scrapers.releases[site.slug] - || scrapers.releases[site.parent?.slug] - || scrapers.releases[site.parent?.parent?.slug]; +async function scrapeChannel(channelEntity, accNetworkReleases) { + const scraper = scrapers.releases[channelEntity.slug] + || scrapers.releases[channelEntity.parent?.slug] + || scrapers.releases[channelEntity.parent?.parent?.slug]; if (!scraper) { - logger.warn(`No scraper found for '${site.name}' (${site.parent.name})`); + logger.warn(`No scraper found for '${channelEntity.name}' (${channelEntity.parent.name})`); return []; } try { - const beforeFetchLatest = await scraper.beforeFetchLatest?.(site); + const beforeFetchLatest = await scraper.beforeFetchLatest?.(channelEntity); - const siteReleases = await scrapeSiteReleases(scraper, site, { - accSiteReleases, + const channelEntityReleases = await scrapeChannelReleases(scraper, channelEntity, { + accNetworkReleases, beforeFetchLatest, }); - return siteReleases.map(release => ({ ...release, site })); + return channelEntityReleases.map(release => ({ ...release, channelEntity })); } catch (error) { - logger.error(`Failed to scrape releases from ${site.name} using ${scraper.slug}: ${error.message}`); + logger.error(`Failed to scrape releases from ${channelEntity.name} using ${scraper.slug}: ${error.message}`); return []; } @@ -199,11 +199,11 @@ async function scrapeSite(site, accSiteReleases) { async function scrapeNetworkSequential(networkEntity) { return Promise.reduce( networkEntity.children, - async (chain, siteEntity) => { - const accSiteReleases = await chain; - const siteReleases = await scrapeSite(siteEntity, networkEntity, accSiteReleases); + async (chain, channelEntity) => { + const accNetworkReleases = await chain; + const channelReleases = await scrapeChannel(channelEntity, networkEntity, accNetworkReleases); - return accSiteReleases.concat(siteReleases); + return accNetworkReleases.concat(channelReleases); }, Promise.resolve([]), ); @@ -212,21 +212,21 @@ async function scrapeNetworkSequential(networkEntity) { async function scrapeNetworkParallel(networkEntity) { return Promise.map( networkEntity.children, - async siteEntity => scrapeSite(siteEntity, networkEntity), + async channelEntity => scrapeChannel(channelEntity, networkEntity), { concurrency: 3 }, ); } async function fetchUpdates() { - const includedNetworks = argv.sites || argv.networks || argv.from - ? await fetchSitesFromArgv() - : await fetchSitesFromConfig(); + const includedNetworks = argv.channels || argv.networks + ? await fetchChannelsFromArgv() + : await fetchChannelsFromConfig(); const scrapedNetworks = await Promise.map( includedNetworks, - async network => (network.parameters?.sequential - ? scrapeNetworkSequential(network) - : scrapeNetworkParallel(network)), + async networkEntity => (networkEntity.parameters?.sequential + ? scrapeNetworkSequential(networkEntity) + : scrapeNetworkParallel(networkEntity)), { concurrency: 5 }, );