diff --git a/assets/components/actors/actor.vue b/assets/components/actors/actor.vue index 537b91eb..8792cd80 100644 --- a/assets/components/actors/actor.vue +++ b/assets/components/actors/actor.vue @@ -274,7 +274,7 @@ function scrollDescription(event) { async function mounted() { [this.actor] = await Promise.all([ - this.$store.dispatch('fetchActors', this.$route.params.actorSlug), + this.$store.dispatch('fetchActors', { actorId: this.$route.params.actorSlug }), this.fetchReleases(), ]); diff --git a/assets/components/actors/actors.vue b/assets/components/actors/actors.vue index 31d19a81..308c55b7 100644 --- a/assets/components/actors/actors.vue +++ b/assets/components/actors/actors.vue @@ -12,7 +12,7 @@ import Actor from '../tile/actor.vue'; async function mounted() { - this.actors = await this.$store.dispatch('fetchActors'); + this.actors = await this.$store.dispatch('fetchActors', { limit: 1000 }); } export default { diff --git a/assets/components/header/header.vue b/assets/components/header/header.vue index fcaa3b4a..b20a126b 100644 --- a/assets/components/header/header.vue +++ b/assets/components/header/header.vue @@ -1,43 +1,58 @@ + + diff --git a/assets/components/networks/networks.vue b/assets/components/networks/networks.vue index 2dc7eaa4..c50f0e06 100644 --- a/assets/components/networks/networks.vue +++ b/assets/components/networks/networks.vue @@ -13,8 +13,6 @@ import Network from '../tile/network.vue'; async function mounted() { this.networks = await this.$store.dispatch('fetchNetworks'); - - console.log(this.networks); } export default { diff --git a/assets/components/tag/tag.vue b/assets/components/tags/tag.vue similarity index 82% rename from assets/components/tag/tag.vue rename to assets/components/tags/tag.vue index c1cbf09e..d10ea05a 100644 --- a/assets/components/tag/tag.vue +++ b/assets/components/tags/tag.vue @@ -6,6 +6,11 @@
+ +

@@ -34,8 +39,8 @@ async function fetchReleases() { } async function mounted() { - [[this.tag]] = await Promise.all([ - this.$store.dispatch('fetchTags', this.$route.params.tagSlug), + [this.tag] = await Promise.all([ + this.$store.dispatch('fetchTags', { tagId: this.$route.params.tagSlug }), this.fetchReleases(), ]); @@ -65,13 +70,17 @@ export default { @import 'theme'; .header { - display: flex; - justify-content: space-between; - padding: 1rem; +} + +.poster { + width: 30rem; + height: 18rem; + object-fit: cover; } .title { display: inline-block; + padding: 1rem; margin: 0 .5rem 0 0; text-transform: capitalize; diff --git a/assets/components/tags/tags.vue b/assets/components/tags/tags.vue new file mode 100644 index 00000000..6ef541d4 --- /dev/null +++ b/assets/components/tags/tags.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/assets/components/tile/release.vue b/assets/components/tile/release.vue index b939e9cb..6189d80f 100644 --- a/assets/components/tile/release.vue +++ b/assets/components/tile/release.vue @@ -2,19 +2,19 @@ - +
-

{{ release.title }}

-
+
    @@ -100,10 +100,10 @@ :key="`tag-${tag.slug}`" class="tag" > - {{ tag.name }} + >{{ tag.name }}
diff --git a/assets/components/tile/tag.vue b/assets/components/tile/tag.vue new file mode 100644 index 00000000..cefe46a5 --- /dev/null +++ b/assets/components/tile/tag.vue @@ -0,0 +1,72 @@ + + + + + diff --git a/assets/img/modelhub.svg b/assets/img/modelhub.svg new file mode 100644 index 00000000..6f2371c3 --- /dev/null +++ b/assets/img/modelhub.svg @@ -0,0 +1,91 @@ + + + + + + image/svg+xml + + cliphub + + + + + + cliphub + Created with Sketch. + + + + + + + + MH + + + + diff --git a/assets/img/onlyfans.svg b/assets/img/onlyfans.svg new file mode 100644 index 00000000..8e88f97f --- /dev/null +++ b/assets/img/onlyfans.svg @@ -0,0 +1,66 @@ + + diff --git a/assets/img/tumblr2.svg b/assets/img/tumblr2.svg deleted file mode 100644 index 7db0ee33..00000000 --- a/assets/img/tumblr2.svg +++ /dev/null @@ -1,5 +0,0 @@ - - -tumblr2 - - diff --git a/assets/js/actors/actions.js b/assets/js/actors/actions.js index a7fe35ff..ac949be8 100644 --- a/assets/js/actors/actions.js +++ b/assets/js/actors/actions.js @@ -1,10 +1,12 @@ import { get } from '../api'; function initActorActions(store, _router) { - async function fetchActors({ _commit }, actorId) { - const networks = await get(`/actors/${actorId || ''}`); + async function fetchActors({ _commit }, { actorId, limit = 100 }) { + if (actorId) { + return get(`/actors/${actorId}`, { limit }); + } - return networks; + return get('/actors', { limit }); } async function fetchActorReleases({ _commit }, actorId) { diff --git a/assets/js/api.js b/assets/js/api.js index ad0a5586..bb1904c2 100644 --- a/assets/js/api.js +++ b/assets/js/api.js @@ -1,9 +1,7 @@ import config from 'config'; -import queryString from 'query-string'; - async function get(endpoint, query = {}) { - const q = queryString.stringify(query); + const q = new URLSearchParams(query).toString(); const res = await fetch(`${config.api.url}${endpoint}?${q}`, { method: 'GET', diff --git a/assets/js/router.js b/assets/js/router.js index 65f9b038..66034465 100644 --- a/assets/js/router.js +++ b/assets/js/router.js @@ -8,7 +8,8 @@ import Network from '../components/networks/network.vue'; import Networks from '../components/networks/networks.vue'; import Actor from '../components/actors/actor.vue'; import Actors from '../components/actors/actors.vue'; -import Tag from '../components/tag/tag.vue'; +import Tag from '../components/tags/tag.vue'; +import Tags from '../components/tags/tags.vue'; import NotFound from '../components/errors/404.vue'; Vue.use(VueRouter); @@ -59,6 +60,11 @@ const routes = [ component: Networks, name: 'networks', }, + { + path: '/tags', + component: Tags, + name: 'tags', + }, { path: '*', component: NotFound, diff --git a/assets/js/tags/actions.js b/assets/js/tags/actions.js index 894e73a9..6a608ed2 100644 --- a/assets/js/tags/actions.js +++ b/assets/js/tags/actions.js @@ -1,10 +1,12 @@ import { get } from '../api'; function initTagsActions(store, _router) { - async function fetchTags({ _commit }, tagId) { - const tags = await get(`/tags/${tagId || ''}`); + async function fetchTags({ _commit }, { tagId, limit = 100, priority }) { + if (tagId) { + return get(`/tags/${tagId}`); + } - return tags; + return get('/tags', { limit, priority }); } async function fetchTagReleases({ _commit }, tagId) { diff --git a/package-lock.json b/package-lock.json index 2f5c6359..d536915b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8681,16 +8681,6 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" }, - "query-string": { - "version": "6.8.3", - "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.3.tgz", - "integrity": "sha512-llcxWccnyaWlODe7A9hRjkvdCKamEKTh+wH8ITdTc3OhchaqUZteiSCX/2ablWHVrkVIe04dntnaZJ7BdyW0lQ==", - "requires": { - "decode-uri-component": "^0.2.0", - "split-on-first": "^1.0.0", - "strict-uri-encode": "^2.0.0" - } - }, "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", @@ -10038,11 +10028,6 @@ "through": "2" } }, - "split-on-first": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/split-on-first/-/split-on-first-1.1.0.tgz", - "integrity": "sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==" - }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -10187,11 +10172,6 @@ "resolved": "https://registry.npmjs.org/stream-transform/-/stream-transform-1.0.8.tgz", "integrity": "sha512-1q+dL790Ps0NV33rISMq9OLtfDA9KMJZdo1PHZXE85orrWsM4FAh8CVyAOTHO0rhyeM138KNPngBPrx33bFsxw==" }, - "strict-uri-encode": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz", - "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY=" - }, "string": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/string/-/string-3.3.3.tgz", diff --git a/package.json b/package.json index e2d7b462..0edaca5d 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,6 @@ "opn": "^5.4.0", "pg": "^7.9.0", "prop-types": "^15.7.2", - "query-string": "^6.8.3", "react": "^16.8.6", "react-dom": "^16.8.6", "sharp": "^0.23.2", diff --git a/public/css/style.css b/public/css/style.css index 0671035f..d1b81c67 100644 --- a/public/css/style.css +++ b/public/css/style.css @@ -923,21 +923,64 @@ } /* $primary: #ff886c; */ -.header[data-v-80991bcc] { - display: flex; - justify-content: space-between; - padding: 1rem; +.poster[data-v-7f130e7f] { + width: 30rem; + height: 18rem; + -o-object-fit: cover; + object-fit: cover; } -.title[data-v-80991bcc] { +.title[data-v-7f130e7f] { display: inline-block; + padding: 1rem; margin: 0 .5rem 0 0; text-transform: capitalize; } -.title .icon[data-v-80991bcc] { +.title .icon[data-v-7f130e7f] { width: 1.25rem; height: 1.25rem; } +/* $primary: #ff886c; */ +.tile[data-v-602c6fd8] { + background: #fff; + display: flex; + flex-direction: column; + align-items: center; + box-sizing: border-box; + box-shadow: 0 0 3px rgba(0, 0, 0, 0.25); + text-align: center; + text-decoration: none; +} +.poster[data-v-602c6fd8] { + width: 100%; + height: 14rem; + -o-object-fit: cover; + object-fit: cover; +} +.title[data-v-602c6fd8] { + color: #222; + display: flex; + align-items: center; + justify-content: center; + font-size: 1rem; + font-weight: bold; + padding: .5rem 1rem; +} +.title[data-v-602c6fd8] { + color: #222; + height: 100%; + display: flex; + align-items: center; + margin: 0; +} + +.tags[data-v-66fa6284] { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr)); + grid-gap: .5rem; + padding: 1rem; +} + /* $primary: #ff886c; */ .errorpage[data-v-29109daf] { background: #fff; @@ -1103,15 +1146,31 @@ body { display: inline-block; } .nav-link[data-v-10b7ec04] { - display: inline-block; - color: rgba(0, 0, 0, 0.5); + display: inline-flex; + align-items: center; padding: 1rem; + border-bottom: solid 5px transparent; + color: rgba(0, 0, 0, 0.5); text-decoration: none; - font-size: 1rem; + font-size: .9rem; font-weight: bold; } -.nav-link[data-v-10b7ec04]:hover { +.nav-link .icon[data-v-10b7ec04] { + fill: rgba(0, 0, 0, 0.5); + margin: 0 .5rem 0 0; +} +.nav-link.active[data-v-10b7ec04] { color: #ff6c88; + border-bottom: solid 5px #ff6c88; +} +.nav-link.active .icon[data-v-10b7ec04] { + fill: #ff6c88; +} +.nav-link[data-v-10b7ec04]:hover:not(.active) { + color: #ff6c88; +} +.nav-link:hover:not(.active) .icon[data-v-10b7ec04] { + fill: #ff6c88; } /* $primary: #ff886c; */ diff --git a/public/img/tags/airtight.jpg b/public/img/tags/airtight.jpg new file mode 100644 index 00000000..0cd22fe3 Binary files /dev/null and b/public/img/tags/airtight.jpg differ diff --git a/public/img/tags/airtight_thumb.jpg b/public/img/tags/airtight_thumb.jpg new file mode 100644 index 00000000..815de4e6 Binary files /dev/null and b/public/img/tags/airtight_thumb.jpg differ diff --git a/public/img/tags/anal.jpg b/public/img/tags/anal.jpg new file mode 100644 index 00000000..c52ad57f Binary files /dev/null and b/public/img/tags/anal.jpg differ diff --git a/public/img/tags/anal_thumb.jpg b/public/img/tags/anal_thumb.jpg new file mode 100644 index 00000000..e5d10351 Binary files /dev/null and b/public/img/tags/anal_thumb.jpg differ diff --git a/public/img/tags/bdsm.jpg b/public/img/tags/bdsm.jpg new file mode 100644 index 00000000..21b40081 Binary files /dev/null and b/public/img/tags/bdsm.jpg differ diff --git a/public/img/tags/bdsm_thumb.jpg b/public/img/tags/bdsm_thumb.jpg new file mode 100644 index 00000000..4bbbb415 Binary files /dev/null and b/public/img/tags/bdsm_thumb.jpg differ diff --git a/public/img/tags/double-anal.jpg b/public/img/tags/double-anal.jpg new file mode 100644 index 00000000..37b415fc Binary files /dev/null and b/public/img/tags/double-anal.jpg differ diff --git a/public/img/tags/double-anal_thumb.jpg b/public/img/tags/double-anal_thumb.jpg new file mode 100644 index 00000000..1126f772 Binary files /dev/null and b/public/img/tags/double-anal_thumb.jpg differ diff --git a/public/img/tags/double-penetration.jpg b/public/img/tags/double-penetration.jpg new file mode 100644 index 00000000..3b21b8cc Binary files /dev/null and b/public/img/tags/double-penetration.jpg differ diff --git a/public/img/tags/double-penetration_thumb.jpg b/public/img/tags/double-penetration_thumb.jpg new file mode 100644 index 00000000..105bdaa7 Binary files /dev/null and b/public/img/tags/double-penetration_thumb.jpg differ diff --git a/public/img/tags/double-vaginal.jpg b/public/img/tags/double-vaginal.jpg new file mode 100644 index 00000000..f129c538 Binary files /dev/null and b/public/img/tags/double-vaginal.jpg differ diff --git a/public/img/tags/double-vaginal_thumb.jpg b/public/img/tags/double-vaginal_thumb.jpg new file mode 100644 index 00000000..bee76b43 Binary files /dev/null and b/public/img/tags/double-vaginal_thumb.jpg differ diff --git a/public/img/tags/gangbang.jpg b/public/img/tags/gangbang.jpg new file mode 100644 index 00000000..f3cb80d4 Binary files /dev/null and b/public/img/tags/gangbang.jpg differ diff --git a/public/img/tags/gangbang_thumb.jpg b/public/img/tags/gangbang_thumb.jpg new file mode 100644 index 00000000..87841fbf Binary files /dev/null and b/public/img/tags/gangbang_thumb.jpg differ diff --git a/public/img/tags/interracial.jpg b/public/img/tags/interracial.jpg new file mode 100644 index 00000000..95493de0 Binary files /dev/null and b/public/img/tags/interracial.jpg differ diff --git a/public/img/tags/interracial_thumb.jpg b/public/img/tags/interracial_thumb.jpg new file mode 100644 index 00000000..834cfdeb Binary files /dev/null and b/public/img/tags/interracial_thumb.jpg differ diff --git a/public/img/tags/triple-penetration.jpg b/public/img/tags/triple-penetration.jpg new file mode 100644 index 00000000..7b9daddb Binary files /dev/null and b/public/img/tags/triple-penetration.jpg differ diff --git a/public/img/tags/triple-penetration_thumb.jpg b/public/img/tags/triple-penetration_thumb.jpg new file mode 100644 index 00000000..7826f75e Binary files /dev/null and b/public/img/tags/triple-penetration_thumb.jpg differ diff --git a/src/actors.js b/src/actors.js index b4b3a7ff..ee140301 100644 --- a/src/actors.js +++ b/src/actors.js @@ -17,7 +17,8 @@ async function curateActor(actor) { .where({ domain: 'actors', target_id: actor.id }) .orderBy('index'), knex('social') - .where({ domain: 'actors', target_id: actor.id }), + .where({ domain: 'actors', target_id: actor.id }) + .orderBy('platform', 'desc'), ]); const curatedActor = { @@ -128,11 +129,17 @@ function curateActorEntry(actor, scraped, scrapeSuccess) { function curateSocialEntry(url, actorId) { const platforms = [ + // links supplied by PH often look like domain.com/domain.com/username { label: 'twitter', pattern: 'http(s)\\://(*)twitter.com/:username(/)(?*)', format: username => `https://www.twitter.com/${username}`, }, + { + label: 'youtube', + pattern: 'http(s)\\://(*)youtube.com/channel/:username(?*)', + format: username => `https://www.youtube.com/channel/${username}`, + }, { label: 'instagram', pattern: 'http(s)\\://(*)instagram.com/:username(/)(?*)', @@ -148,11 +155,21 @@ function curateSocialEntry(url, actorId) { pattern: 'http(s)\\://:username.tumblr.com(*)', format: username => `https://${username}.tumblr.com`, }, + { + label: 'onlyfans', + pattern: 'http(s)\\://(*)onlyfans.com/:username(/)(?*)', + format: username => `https://www.onlyfans.com/${username}`, + }, { label: 'fancentro', - pattern: 'http(s)\\://(www.)fancentro.com/:username(/)(?*)', + pattern: 'http(s)\\://(*)fancentro.com/:username(/)(?*)', format: username => `https://www.fancentro.com/${username}`, }, + { + label: 'modelhub', + pattern: 'http(s)\\://(*)modelhub.com/:username(/)(?*)', + format: username => `https://www.modelhub.com/${username}`, + }, ]; const match = platforms.reduce((acc, platform) => { @@ -202,7 +219,7 @@ async function curateSocialEntries(urls, actorId) { }, []); } -async function fetchActors(queryObject) { +async function fetchActors(queryObject, limit = 100) { const releases = await knex('actors') .select( 'actors.*', @@ -213,7 +230,7 @@ async function fetchActors(queryObject) { .leftJoin('countries as residence_countries', 'actors.residence_country_alpha2', 'residence_countries.alpha2') .orderBy(['actors.name', 'actors.gender']) .where(builder => whereOr(queryObject, 'actors', builder)) - .limit(100); + .limit(limit); return curateActors(releases); } diff --git a/src/tags.js b/src/tags.js index ce0d4cab..3f6ad1c4 100644 --- a/src/tags.js +++ b/src/tags.js @@ -9,6 +9,7 @@ async function curateTag(tag) { return { id: tag.id, name: tag.name, + slug: tag.slug, description: tag.description, group: { id: tag.group_id, @@ -36,7 +37,7 @@ async function associateTags(release, releaseId) { }))); } -async function fetchTags(queryObject) { +async function fetchTags(queryObject, limit = 100) { const tags = await knex('tags') .where(builder => whereOr(queryObject, 'tags', builder)) .andWhere({ 'tags.alias_for': null }) @@ -45,7 +46,8 @@ async function fetchTags(queryObject) { 'tags_groups.id as group_id', 'tags_groups.name as group_name', 'tags_groups.slug as group_slug', 'tags_groups.description as groups_description', ) .leftJoin('tags_groups', 'tags.group_id', 'tags_groups.id') - .limit(100); + .orderBy('name') + .limit(limit); return curateTags(tags); } diff --git a/src/utils/where-or.js b/src/utils/where-or.js index 800d2f65..bc9049a8 100644 --- a/src/utils/where-or.js +++ b/src/utils/where-or.js @@ -6,9 +6,17 @@ function whereOr(query, table, builder) { } Object.entries(query).forEach(([key, value]) => { - if (value !== undefined) { - builder.orWhere(`${table}.${key}`, value); + if (value === undefined) { + return builder; } + + if (Array.isArray(value)) { + builder.orWhereIn(`${table}.${key}`, value); + return builder; + } + + builder.orWhere(`${table}.${key}`, value); + return builder; }); return builder; diff --git a/src/web/actors.js b/src/web/actors.js index c87c89e6..c43cca32 100644 --- a/src/web/actors.js +++ b/src/web/actors.js @@ -21,7 +21,7 @@ async function fetchActorsApi(req, res) { return; } - const actors = await fetchActors(); + const actors = await fetchActors(null, req.query.limit); res.send(actors); } diff --git a/src/web/tags.js b/src/web/tags.js index 4a3966da..405ea7c0 100644 --- a/src/web/tags.js +++ b/src/web/tags.js @@ -6,10 +6,24 @@ async function fetchTagsApi(req, res) { const tagId = typeof req.params.tagId === 'number' ? req.params.tagId : undefined; // null will literally include NULL results const tagSlug = typeof req.params.tagId === 'string' ? req.params.tagId : undefined; + if (tagId || tagSlug) { + const tags = await fetchTags({ + id: tagId, + slug: tagSlug, + }, req.query.limit); + + if (tags.length > 0) { + res.send(tags[0]); + return; + } + + res.status(404).send(); + return; + } + const tags = await fetchTags({ - id: tagId, - slug: tagSlug, - }); + priority: req.query.priority.split(','), + }, req.query.limit); res.send(tags); }