Added tag filter to releases query, enabled on homepage.

This commit is contained in:
ThePendulum 2019-11-13 03:14:24 +01:00
parent d1212725bb
commit f9f9cc7977
26 changed files with 555 additions and 192 deletions

View File

@ -0,0 +1,172 @@
<template>
<div class="filters-bar noselect">
<Icon icon="filter" />
<ul class="filters">
<li
v-tooltip.bottom="'Not yet available'"
class="filter"
>
<label
class="toggle"
:class="{ active: !localFilter.includes('straight') }"
>
<input
v-model="localFilter"
value="straight"
type="checkbox"
class="check"
disabled
@change="$emit('set-filter', localFilter)"
>straight
</label>
</li>
<li class="filter">
<label
class="toggle"
:class="{ active: !localFilter.includes('lesbian') }"
>
<input
v-model="localFilter"
value="lesbian"
type="checkbox"
class="check"
@change="$emit('set-filter', localFilter)"
>lesbian
</label>
</li>
<li class="filter">
<label
class="toggle"
:class="{ active: !localFilter.includes('gay') }"
>
<input
v-model="localFilter"
value="gay"
type="checkbox"
class="check"
@change="$emit('set-filter', localFilter)"
>gay
</label>
</li>
<li class="filter">
<label
class="toggle"
:class="{ active: !localFilter.includes('transsexual') }"
>
<input
v-model="localFilter"
value="transsexual"
type="checkbox"
class="check"
@change="$emit('set-filter', localFilter)"
>trans
</label>
</li>
</ul>
<ul class="filters">
<li class="filter">
<label
class="toggle"
:class="{ active: !localFilter.includes('anal') }"
>
<input
v-model="localFilter"
value="anal"
type="checkbox"
class="check"
@change="$emit('set-filter', localFilter)"
>anal
</label>
</li>
</ul>
<ul class="filters">
<li class="filter">
<label
class="toggle"
:class="{ active: !localFilter.includes('femdom') }"
>
<input
v-model="localFilter"
value="femdom"
type="checkbox"
class="check"
@change="$emit('set-filter', localFilter)"
>femdom
</label>
</li>
</ul>
</div>
</template>
<script>
export default {
props: {
filter: {
type: Array,
default: () => [],
},
},
data() {
return {
localFilter: this.filter,
};
},
};
</script>
<style lang="scss" scoped>
@import 'theme';
.filters-bar {
display: block;
background: $shadow-hint;
padding: .5rem 1rem;
font-size: 0;
.icon {
fill: $shadow;
}
}
.filters {
display: inline-block;
list-style: none;
padding: .5rem;
margin: 0;
&:not(:last-child) {
border-right: solid 1px $shadow-weak;
}
}
.filter {
display: inline-block;
}
.toggle {
color: $shadow;
background: $shadow-hint;
box-sizing: border-box;
padding: .5rem;
margin: 0 .25rem;
border-radius: .5rem;
font-size: .9rem;
font-weight: bold;
cursor: pointer;
.check {
display: none;
}
&.active {
color: $text-contrast;
background: $primary;
}
}
</style>

View File

@ -1,62 +1,9 @@
<template> <template>
<div class="content"> <div class="content">
<div class="filters-bar noselect"> <FilterBar
<Icon icon="filter" /> :filter="filter"
@set-filter="setFilter"
<ul class="filters"> />
<li class="filter">
<label
class="toggle"
:class="{ active: showStraight }"
>
<input
v-model="showStraight"
type="checkbox"
class="check"
>straight
</label>
</li>
<li class="filter">
<label
class="toggle"
:class="{ active: showLesbian }"
>
<input
v-model="showLesbian"
type="checkbox"
class="check"
>lesbian
</label>
</li>
<li class="filter">
<label
class="toggle"
:class="{ active: showGay }"
>
<input
v-model="showGay"
type="checkbox"
class="check"
>gay
</label>
</li>
<li class="filter">
<label
class="toggle"
:class="{ active: showTrans }"
>
<input
v-model="showTrans"
type="checkbox"
class="check"
>trans
</label>
</li>
</ul>
</div>
<div class="content-inner"> <div class="content-inner">
<ul class="scenes nolist"> <ul class="scenes nolist">
@ -73,75 +20,47 @@
</template> </template>
<script> <script>
import FilterBar from './filter.vue';
import ReleaseTile from '../tile/release.vue'; import ReleaseTile from '../tile/release.vue';
async function mounted() { async function fetchReleases() {
this.releases = await this.$store.dispatch('fetchReleases'); this.releases = await this.$store.dispatch('fetchReleases', {
this.networks = await this.$store.dispatch('fetchNetworks'); filter: this.filter,
});
}
async function setFilter(filter) {
this.filter = filter;
localStorage.setItem('filter', this.filter);
await this.fetchReleases();
}
async function mounted() {
this.pageTitle = ''; this.pageTitle = '';
await this.fetchReleases();
} }
export default { export default {
components: { components: {
FilterBar,
ReleaseTile, ReleaseTile,
}, },
data() { data() {
const storedFilter = localStorage.getItem('filter');
return { return {
showStraight: true, filter: storedFilter ? storedFilter.split(',') : ['gay', 'transsexual'],
showLesbian: true,
showGay: false,
showTrans: false,
releases: [], releases: [],
networks: [], networks: [],
pageTitle: null, pageTitle: null,
}; };
}, },
mounted, mounted,
methods: {
fetchReleases,
setFilter,
},
}; };
</script> </script>
<style lang="scss" scoped>
@import 'theme';
.filters-bar {
display: block;
background: $shadow-hint;
padding: .5rem 1rem;
.icon {
fill: $shadow;
}
}
.filters {
display: inline-block;
list-style: none;
padding: .5rem;
margin: 0;
.toggle {
color: $shadow;
background: $shadow-hint;
box-sizing: border-box;
padding: .5rem;
border-radius: .5rem;
font-size: .9rem;
font-weight: bold;
cursor: pointer;
.check {
display: none;
}
&.active {
color: $text-contrast;
background: $primary;
}
}
}
.filter {
display: inline-block;
}
</style>

View File

@ -168,7 +168,7 @@ function photos() {
} }
async function mounted() { async function mounted() {
[this.release] = await this.$store.dispatch('fetchReleases', this.$route.params.releaseId); [this.release] = await this.$store.dispatch('fetchReleases', { id: this.$route.params.releaseId });
} }
export default { export default {

View File

@ -116,7 +116,7 @@ export default {
} }
.logo { .logo {
width: 15rem; width: 20rem;
max-height: 8rem; max-height: 8rem;
object-fit: contain; object-fit: contain;
margin: 0 .5rem 1rem 0; margin: 0 .5rem 1rem 0;

109
assets/css/_tooltip.scss Normal file
View File

@ -0,0 +1,109 @@
.tooltip {
display: block !important;
z-index: 10000;
.tooltip-inner {
background: #222;
color: white;
border-radius: 16px;
padding: 5px 10px 4px;
}
.tooltip-arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 5px;
border-color: #222;
z-index: 1;
}
&[x-placement^="top"] {
margin-bottom: 5px;
.tooltip-arrow {
border-width: 5px 5px 0 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
bottom: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
}
&[x-placement^="bottom"] {
margin-top: 5px;
.tooltip-arrow {
border-width: 0 5px 5px 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-top-color: transparent !important;
top: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0;
}
}
&[x-placement^="right"] {
margin-left: 5px;
.tooltip-arrow {
border-width: 5px 5px 5px 0;
border-left-color: transparent !important;
border-top-color: transparent !important;
border-bottom-color: transparent !important;
left: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
}
&[x-placement^="left"] {
margin-right: 5px;
.tooltip-arrow {
border-width: 5px 0 5px 5px;
border-top-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
right: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0;
}
}
&.popover {
$color: #f9f9f9;
.popover-inner {
background: $color;
color: black;
padding: 24px;
border-radius: 5px;
box-shadow: 0 5px 30px rgba(black, .1);
}
.popover-arrow {
border-color: $color;
}
}
&[aria-hidden='true'] {
visibility: hidden;
opacity: 0;
/* transition: opacity .15s, visibility .15s; */
}
&[aria-hidden='false'] {
visibility: visible;
opacity: 1;
/* transition: opacity .15s; */
}
}

View File

@ -1,5 +1,6 @@
@import 'theme'; @import 'theme';
@import 'states'; @import 'states';
@import 'tooltip';
html, html,
body { body {

View File

@ -1,9 +1,11 @@
import config from 'config'; import config from 'config';
async function get(endpoint, query = {}) { import queryString from 'query-string';
const queryString = Object.entries(query).reduce((acc, [key, value], index) => `${acc}${index > 0 ? '&' : ''}${key}=${value}`, '?');
const res = await fetch(`${config.api.url}${endpoint}${queryString}`, { async function get(endpoint, query = {}) {
const q = queryString.stringify(query);
const res = await fetch(`${config.api.url}${endpoint}?${q}`, {
method: 'GET', method: 'GET',
mode: 'cors', mode: 'cors',
credentials: 'same-origin', credentials: 'same-origin',

View File

@ -1,5 +1,6 @@
import Vue from 'vue'; import Vue from 'vue';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import VTooltip from 'v-tooltip';
import router from './router'; import router from './router';
import initStore from './store'; import initStore from './store';
@ -31,6 +32,8 @@ function init() {
}, },
}); });
Vue.use(VTooltip);
new Vue({ // eslint-disable-line no-new new Vue({ // eslint-disable-line no-new
el: '#container', el: '#container',
store, store,

View File

@ -1,8 +1,8 @@
import { get } from '../api'; import { get } from '../api';
function initReleasesActions(_store, _router) { function initReleasesActions(_store, _router) {
async function fetchReleases({ _commit }, releaseId) { async function fetchReleases({ _commit }, { id, filter }) {
const releases = await get(`/releases/${releaseId || ''}`); const releases = await get(`/releases/${id || ''}`, { filter });
return releases; return releases;
} }

62
package-lock.json generated
View File

@ -7700,6 +7700,24 @@
"prepend-http": "^1.0.0", "prepend-http": "^1.0.0",
"query-string": "^4.1.0", "query-string": "^4.1.0",
"sort-keys": "^1.0.0" "sort-keys": "^1.0.0"
},
"dependencies": {
"query-string": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
"dev": true,
"requires": {
"object-assign": "^4.1.0",
"strict-uri-encode": "^1.0.0"
}
},
"strict-uri-encode": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
"dev": true
}
} }
}, },
"npm-run-path": { "npm-run-path": {
@ -8335,6 +8353,11 @@
"resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
"integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==" "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
}, },
"popper.js": {
"version": "1.16.0",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.0.tgz",
"integrity": "sha512-+G+EkOPoE5S/zChTpmBSSDYmhXJ5PsW8eMhH8cP/CQHMFPBG/kC9Y5IIw6qNYgdJ+/COf0ddY2li28iHaZRSjw=="
},
"posix-character-classes": { "posix-character-classes": {
"version": "0.1.1", "version": "0.1.1",
"resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
@ -8709,13 +8732,13 @@
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==" "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
}, },
"query-string": { "query-string": {
"version": "4.3.4", "version": "6.8.3",
"resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz", "resolved": "https://registry.npmjs.org/query-string/-/query-string-6.8.3.tgz",
"integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=", "integrity": "sha512-llcxWccnyaWlODe7A9hRjkvdCKamEKTh+wH8ITdTc3OhchaqUZteiSCX/2ablWHVrkVIe04dntnaZJ7BdyW0lQ==",
"dev": true,
"requires": { "requires": {
"object-assign": "^4.1.0", "decode-uri-component": "^0.2.0",
"strict-uri-encode": "^1.0.0" "split-on-first": "^1.0.0",
"strict-uri-encode": "^2.0.0"
} }
}, },
"querystring": { "querystring": {
@ -10065,6 +10088,11 @@
"through": "2" "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": { "split-string": {
"version": "3.1.0", "version": "3.1.0",
"resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
@ -10210,10 +10238,9 @@
"integrity": "sha512-1q+dL790Ps0NV33rISMq9OLtfDA9KMJZdo1PHZXE85orrWsM4FAh8CVyAOTHO0rhyeM138KNPngBPrx33bFsxw==" "integrity": "sha512-1q+dL790Ps0NV33rISMq9OLtfDA9KMJZdo1PHZXE85orrWsM4FAh8CVyAOTHO0rhyeM138KNPngBPrx33bFsxw=="
}, },
"strict-uri-encode": { "strict-uri-encode": {
"version": "1.1.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz", "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-2.0.0.tgz",
"integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=", "integrity": "sha1-ucczDHBChi9rFC3CdLvMWGbONUY="
"dev": true
}, },
"string": { "string": {
"version": "3.3.3", "version": "3.3.3",
@ -10997,6 +11024,16 @@
"resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
"integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho=" "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
}, },
"v-tooltip": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/v-tooltip/-/v-tooltip-2.0.2.tgz",
"integrity": "sha512-xQ+qzOFfywkLdjHknRPgMMupQNS8yJtf9Utd5Dxiu/0n4HtrxqsgDtN2MLZ0LKbburtSAQgyypuE/snM8bBZhw==",
"requires": {
"lodash": "^4.17.11",
"popper.js": "^1.15.0",
"vue-resize": "^0.4.5"
}
},
"v8-compile-cache": { "v8-compile-cache": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz", "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz",
@ -11121,6 +11158,11 @@
"vue-style-loader": "^4.1.0" "vue-style-loader": "^4.1.0"
} }
}, },
"vue-resize": {
"version": "0.4.5",
"resolved": "https://registry.npmjs.org/vue-resize/-/vue-resize-0.4.5.tgz",
"integrity": "sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg=="
},
"vue-router": { "vue-router": {
"version": "3.0.6", "version": "3.0.6",
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.6.tgz", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.0.6.tgz",

View File

@ -85,11 +85,13 @@
"opn": "^5.4.0", "opn": "^5.4.0",
"pg": "^7.9.0", "pg": "^7.9.0",
"prop-types": "^15.7.2", "prop-types": "^15.7.2",
"query-string": "^6.8.3",
"react": "^16.8.6", "react": "^16.8.6",
"react-dom": "^16.8.6", "react-dom": "^16.8.6",
"sharp": "^0.23.2", "sharp": "^0.23.2",
"tough-cookie": "^3.0.1", "tough-cookie": "^3.0.1",
"tty-table": "^2.7.0", "tty-table": "^2.7.0",
"v-tooltip": "^2.0.2",
"vue": "^2.6.10", "vue": "^2.6.10",
"vue-router": "^3.0.6", "vue-router": "^3.0.6",
"vuex": "^3.1.1", "vuex": "^3.1.1",

View File

@ -1,3 +1,44 @@
/* $primary: #ff886c; */
.filters-bar[data-v-7de6ddc6] {
display: block;
background: rgba(0, 0, 0, 0.1);
padding: .5rem 1rem;
font-size: 0;
}
.filters-bar .icon[data-v-7de6ddc6] {
fill: rgba(0, 0, 0, 0.5);
}
.filters[data-v-7de6ddc6] {
display: inline-block;
list-style: none;
padding: .5rem;
margin: 0;
}
.filters[data-v-7de6ddc6]:not(:last-child) {
border-right: solid 1px rgba(0, 0, 0, 0.2);
}
.filter[data-v-7de6ddc6] {
display: inline-block;
}
.toggle[data-v-7de6ddc6] {
color: rgba(0, 0, 0, 0.5);
background: rgba(0, 0, 0, 0.1);
box-sizing: border-box;
padding: .5rem;
margin: 0 .25rem;
border-radius: .5rem;
font-size: .9rem;
font-weight: bold;
cursor: pointer;
}
.toggle .check[data-v-7de6ddc6] {
display: none;
}
.toggle.active[data-v-7de6ddc6] {
color: #fff;
background: #ff6c88;
}
/* $primary: #ff886c; */ /* $primary: #ff886c; */
.tile[data-v-3abcf101] { .tile[data-v-3abcf101] {
display: flex; display: flex;
@ -118,42 +159,6 @@
color: rgba(0, 0, 0, 0.7); color: rgba(0, 0, 0, 0.7);
} }
/* $primary: #ff886c; */
.filters-bar[data-v-5533e378] {
display: block;
background: rgba(0, 0, 0, 0.1);
padding: .5rem 1rem;
}
.filters-bar .icon[data-v-5533e378] {
fill: rgba(0, 0, 0, 0.5);
}
.filters[data-v-5533e378] {
display: inline-block;
list-style: none;
padding: .5rem;
margin: 0;
}
.filters .toggle[data-v-5533e378] {
color: rgba(0, 0, 0, 0.5);
background: rgba(0, 0, 0, 0.1);
box-sizing: border-box;
padding: .5rem;
border-radius: .5rem;
font-size: .9rem;
font-weight: bold;
cursor: pointer;
}
.filters .toggle .check[data-v-5533e378] {
display: none;
}
.filters .toggle.active[data-v-5533e378] {
color: #fff;
background: #ff6c88;
}
.filter[data-v-5533e378] {
display: inline-block;
}
/* $primary: #ff886c; */ /* $primary: #ff886c; */
.banner[data-v-2bc41e74] { .banner[data-v-2bc41e74] {
background: #222; background: #222;
@ -246,7 +251,7 @@
align-items: flex-end; align-items: flex-end;
} }
.logo[data-v-3e57cf44] { .logo[data-v-3e57cf44] {
width: 15rem; width: 20rem;
max-height: 8rem; max-height: 8rem;
-o-object-fit: contain; -o-object-fit: contain;
object-fit: contain; object-fit: contain;
@ -423,6 +428,83 @@
-ms-user-select: none; -ms-user-select: none;
-webkit-tap-highlight-color: transparent; } -webkit-tap-highlight-color: transparent; }
.tooltip {
display: block !important;
z-index: 10000; }
.tooltip .tooltip-inner {
background: #222;
color: white;
border-radius: 16px;
padding: 5px 10px 4px; }
.tooltip .tooltip-arrow {
width: 0;
height: 0;
border-style: solid;
position: absolute;
margin: 5px;
border-color: #222;
z-index: 1; }
.tooltip[x-placement^="top"] {
margin-bottom: 5px; }
.tooltip[x-placement^="top"] .tooltip-arrow {
border-width: 5px 5px 0 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
bottom: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0; }
.tooltip[x-placement^="bottom"] {
margin-top: 5px; }
.tooltip[x-placement^="bottom"] .tooltip-arrow {
border-width: 0 5px 5px 5px;
border-left-color: transparent !important;
border-right-color: transparent !important;
border-top-color: transparent !important;
top: -5px;
left: calc(50% - 5px);
margin-top: 0;
margin-bottom: 0; }
.tooltip[x-placement^="right"] {
margin-left: 5px; }
.tooltip[x-placement^="right"] .tooltip-arrow {
border-width: 5px 5px 5px 0;
border-left-color: transparent !important;
border-top-color: transparent !important;
border-bottom-color: transparent !important;
left: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0; }
.tooltip[x-placement^="left"] {
margin-right: 5px; }
.tooltip[x-placement^="left"] .tooltip-arrow {
border-width: 5px 0 5px 5px;
border-top-color: transparent !important;
border-right-color: transparent !important;
border-bottom-color: transparent !important;
right: -5px;
top: calc(50% - 5px);
margin-left: 0;
margin-right: 0; }
.tooltip.popover .popover-inner {
background: #f9f9f9;
color: black;
padding: 24px;
border-radius: 5px;
box-shadow: 0 5px 30px rgba(0, 0, 0, 0.1); }
.tooltip.popover .popover-arrow {
border-color: #f9f9f9; }
.tooltip[aria-hidden='true'] {
visibility: hidden;
opacity: 0;
/* transition: opacity .15s, visibility .15s; */ }
.tooltip[aria-hidden='false'] {
visibility: visible;
opacity: 1;
/* transition: opacity .15s; */ }
html, html,
body { body {
height: 100%; } height: 100%; }

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

View File

@ -1399,6 +1399,10 @@ function getTagAliases(tagsMap) {
name: 'tittyfuck', name: 'tittyfuck',
alias_for: tagsMap['titty-fuck'], alias_for: tagsMap['titty-fuck'],
}, },
{
name: 'tp',
alias_for: tagsMap['triple-penetration'],
},
{ {
name: 'trans', name: 'trans',
alias_for: tagsMap['transsexual'], alias_for: tagsMap['transsexual'],
@ -1408,8 +1412,8 @@ function getTagAliases(tagsMap) {
alias_for: tagsMap['trimmed'], alias_for: tagsMap['trimmed'],
}, },
{ {
name: 'tp', name: 'ts',
alias_for: tagsMap['triple-penetration'], alias_for: tagsMap['transsexual'],
}, },
{ {
name: 'whipping', name: 'whipping',

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
const knex = require('./knex'); const knex = require('./knex');
const whereOr = require('./utils/where-or');
async function curateActor(actor) { async function curateActor(actor) {
const aliases = await knex('actors') const aliases = await knex('actors')
@ -26,10 +27,9 @@ function curateActors(releases) {
return Promise.all(releases.map(async release => curateActor(release))); return Promise.all(releases.map(async release => curateActor(release)));
} }
async function fetchActors(actorId, actorSlug) { async function fetchActors(queryObject) {
const releases = await knex('actors') const releases = await knex('actors')
.where({ id: actorId }) .where(builder => whereOr(queryObject, 'actors', builder))
.orWhere({ slug: actorSlug })
.limit(100); .limit(100);
return curateActors(releases); return curateActors(releases);

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
const knex = require('./knex'); const knex = require('./knex');
const whereOr = require('./utils/where-or');
async function curateNetwork(network) { async function curateNetwork(network) {
const [sites, studios] = await Promise.all([ const [sites, studios] = await Promise.all([
@ -44,10 +45,9 @@ function curateNetworks(releases) {
return Promise.all(releases.map(async release => curateNetwork(release))); return Promise.all(releases.map(async release => curateNetwork(release)));
} }
async function fetchNetworks(networkId, networkSlug) { async function fetchNetworks(queryObject) {
const releases = await knex('networks') const releases = await knex('networks')
.where({ id: networkId }) .where(builder => whereOr(queryObject, 'networks', builder))
.orWhere({ slug: networkSlug })
.limit(100); .limit(100);
return curateNetworks(releases); return curateNetworks(releases);

View File

@ -66,18 +66,29 @@ function curateReleases(releases) {
return Promise.all(releases.map(async release => curateRelease(release))); return Promise.all(releases.map(async release => curateRelease(release)));
} }
async function fetchReleases(releaseId) { async function fetchReleases(releaseId, filter = []) {
// const straightFilter = filter.includes('straight') ? ['gay', 'lesbian'] : [];
const releases = await knex('releases') const releases = await knex('releases')
.where(releaseId ? { 'releases.id': releaseId } : {}) .leftJoin('sites', 'releases.site_id', 'sites.id')
.leftJoin('studios', 'releases.studio_id', 'studios.id')
.leftJoin('networks', 'sites.network_id', 'networks.id')
.select( .select(
'releases.*', 'releases.*',
'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id', 'sites.name as site_name', 'sites.slug as site_slug', 'sites.url as site_url', 'sites.network_id',
'studios.name as studio_name', 'sites.slug as site_slug', 'studios.url as studio_url', 'studios.name as studio_name', 'sites.slug as site_slug', 'studios.url as studio_url',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url', 'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url',
) )
.leftJoin('sites', 'releases.site_id', 'sites.id') .whereNotExists((builder) => {
.leftJoin('studios', 'releases.studio_id', 'studios.id') // apply filters
.leftJoin('networks', 'sites.network_id', 'networks.id') builder
.select('*')
.from('tags_associated')
.leftJoin('tags', 'tags_associated.tag_id', 'tags.id')
.whereIn('tags.slug', filter)
.andWhereRaw('tags_associated.release_id = releases.id');
})
.andWhere(releaseId ? { 'releases.id': releaseId } : {})
.orderBy([{ column: 'date', order: 'desc' }, { column: 'created_at', order: 'desc' }]) .orderBy([{ column: 'date', order: 'desc' }, { column: 'created_at', order: 'desc' }])
.limit(100); .limit(100);

View File

@ -8,6 +8,13 @@ const moment = require('moment');
const { matchTags } = require('../tags'); const { matchTags } = require('../tags');
const defaultTags = {
hardx: [],
darkx: ['interracial'],
eroticax: [],
lesbianx: ['lesbian'],
};
async function fetchPhotos(url) { async function fetchPhotos(url) {
const res = await bhttp.get(url); const res = await bhttp.get(url);
@ -144,7 +151,7 @@ async function scrapeScene(html, url, site) {
.orWhere({ slug: siteId }) .orWhere({ slug: siteId })
.first() .first()
: site, : site,
matchTags(rawTags), matchTags([...defaultTags[siteId], ...rawTags]),
]); ]);
return { return {

View File

@ -23,9 +23,9 @@ function curateSites(sites) {
return Promise.all(sites.map(async site => curateSite(site))); return Promise.all(sites.map(async site => curateSite(site)));
} }
async function fetchSites(query) { async function fetchSites(queryObject) {
const sites = await knex('sites') const sites = await knex('sites')
.where(builder => whereOr(query, builder)) .where(builder => whereOr(queryObject, 'sites', builder))
.select( .select(
'sites.*', 'sites.*',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url', 'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url',

View File

@ -1,6 +1,7 @@
'use strict'; 'use strict';
const knex = require('./knex'); const knex = require('./knex');
const whereOr = require('./utils/where-or');
async function curateTag(tag) { async function curateTag(tag) {
const aliases = await knex('tags').where({ alias_for: tag.id }); const aliases = await knex('tags').where({ alias_for: tag.id });
@ -30,10 +31,9 @@ async function storeTags(release, releaseEntry) {
}))); })));
} }
async function fetchTags(tagId, tagSlug) { async function fetchTags(queryObject) {
const tags = await knex('tags') const tags = await knex('tags')
.where({ 'tags.id': tagId }) .where(builder => whereOr(queryObject, 'tags', builder))
.orWhere({ 'tags.slug': tagSlug })
.andWhere({ 'tags.alias_for': null }) .andWhere({ 'tags.alias_for': null })
.select( .select(
'tags.*', 'tags.*',

View File

@ -1,9 +1,9 @@
'use strict'; 'use strict';
function whereOr(query, builder) { function whereOr(query, table, builder) {
Object.entries(query).forEach(([key, value]) => { Object.entries(query).forEach(([key, value]) => {
if (value !== undefined) { if (value !== undefined) {
builder.orWhere(`sites.${key}`, value); builder.orWhere(`${table}.${key}`, value);
} }
}); });
} }

View File

@ -6,7 +6,10 @@ async function fetchActorsApi(req, res) {
const actorId = typeof req.params.actorId === 'number' ? req.params.actorId : null; const actorId = typeof req.params.actorId === 'number' ? req.params.actorId : null;
const actorSlug = typeof req.params.actorId === 'string' ? req.params.actorId : null; const actorSlug = typeof req.params.actorId === 'string' ? req.params.actorId : null;
const actors = await fetchActors(actorId, actorSlug); const actors = await fetchActors({
id: actorId,
slug: actorSlug,
});
res.send(actors); res.send(actors);
} }

View File

@ -3,10 +3,13 @@
const { fetchNetworks, fetchNetworksFromReleases } = require('../networks'); const { fetchNetworks, fetchNetworksFromReleases } = require('../networks');
async function fetchNetworksApi(req, res) { async function fetchNetworksApi(req, res) {
const networkId = typeof req.params.networkId === 'number' ? req.params.networkId : null; const networkId = typeof req.params.networkId === 'number' ? req.params.networkId : undefined; // null will literally include NULL results
const networkSlug = typeof req.params.networkId === 'string' ? req.params.networkId : null; const networkSlug = typeof req.params.networkId === 'string' ? req.params.networkId : undefined;
const networks = await fetchNetworks(networkId, networkSlug); const networks = await fetchNetworks({
id: networkId,
slug: networkSlug,
});
res.send(networks); res.send(networks);
} }

View File

@ -9,7 +9,7 @@ const {
} = require('../releases'); } = require('../releases');
async function fetchReleasesApi(req, res) { async function fetchReleasesApi(req, res) {
const releases = await fetchReleases(req.params.releaseId); const releases = await fetchReleases(req.params.releaseId, req.query.filter ? [].concat(req.query.filter) : []);
res.send(releases); res.send(releases);
} }

View File

@ -3,10 +3,13 @@
const { fetchTags } = require('../tags'); const { fetchTags } = require('../tags');
async function fetchTagsApi(req, res) { async function fetchTagsApi(req, res) {
const tagId = typeof req.params.tagId === 'number' ? req.params.tagId : null; 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 : null; const tagSlug = typeof req.params.tagId === 'string' ? req.params.tagId : undefined;
const tags = await fetchTags(tagId, tagSlug); const tags = await fetchTags({
id: tagId,
slug: tagSlug,
});
res.send(tags); res.send(tags);
} }