Generating thumbnails. Added site overview page.

This commit is contained in:
ThePendulum 2019-11-11 03:20:00 +01:00
parent 948597d265
commit 50816d7b28
28 changed files with 780 additions and 182 deletions

View File

@ -10,7 +10,7 @@
"no-console": 0,
"indent": ["error", 4],
"max-len": [2, {
"code": 200,
"code": 300,
"tabWidth": 4,
"ignoreUrls": true
}],

View File

@ -77,6 +77,8 @@ import ReleaseTile from '../tile/release.vue';
async function mounted() {
this.releases = await this.$store.dispatch('fetchReleases');
this.networks = await this.$store.dispatch('fetchNetworks');
this.pageTitle = '';
}
@ -91,6 +93,7 @@ export default {
showGay: false,
showTrans: false,
releases: [],
networks: [],
pageTitle: null,
};
},

View File

@ -125,6 +125,6 @@ export default {
}
.sites {
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
</style>

View File

@ -8,7 +8,7 @@
<video
v-if="release.trailer"
:src="`/media/${release.trailer.path}`"
:poster="`/media/${(release.poster && release.poster.path) || (release.photos.length && release.photos[Math.floor(Math.random() * release.photos.length)].path)}`"
:poster="`/media/${(release.poster && release.poster.thumbnail) || (release.photos.length && release.photos[Math.floor(Math.random() * release.photos.length)].path)}`"
:alt="release.title"
class="banner-item"
controls
@ -23,7 +23,7 @@
rel="noopener noreferrer"
>
<img
:src="`/media/${photo.path}`"
:src="`/media/${photo.thumbnail}`"
:alt="`Photo ${photo.index + 1}`"
class="banner-item"
>
@ -77,15 +77,11 @@
<a
:href="`/network/${release.network.slug}`"
target="_blank"
rel="noopener noreferrer"
class="network-link"
>{{ release.network.name }}:</a>
<a
:href="`/site/${release.site.slug}`"
target="_blank"
rel="noopener noreferrer"
class="site-link"
>{{ release.site.name }}</a>
</span>

View File

@ -1,5 +1,157 @@
<template>
<div>
<h1>Site</h1>
<div
v-if="site"
class="content site"
>
<div class="header">
<span class="intro">
<h2 class="title">
{{ site.name }}
<a
v-if="site.url"
:href="site.url"
target="_blank"
rel="noopener noreferrer"
>
<Icon
icon="new-tab"
class="icon-href"
/>
</a>
</h2>
<span class="description">{{ site.description }}</span>
</span>
<span class="link">
<a
v-if="site.url"
:href="site.url"
target="_blank"
rel="noopener noreferrer"
class="logo-link"
>
<object
:data="`/img/logos/${site.network.slug}/${site.slug}.png`"
:title="site.name"
type="image/png"
class="logo"
>{{ site.name }}</object>
</a>
<span class="networklogo-container">
Part of
<a
:href="site.network.url"
target="_blank"
rel="noopener noreferrer"
class="networklogo-link"
>
<object
:data="`/img/logos/${site.network.slug}/network.png`"
:title="site.network.name"
type="image/png"
class="networklogo"
>{{ site.network.name }}</object>
</a>
</span>
</span>
</div>
<div class="content-inner">
<h3 class="heading">Latest releases</h3>
<ul class="nolist scenes">
<li
v-for="release in releases"
:key="`release-${release.id}`"
>
<ReleaseTile :release="release" />
</li>
</ul>
</div>
</div>
</template>
<script>
import ReleaseTile from '../tile/release.vue';
async function mounted() {
[this.site] = await this.$store.dispatch('fetchSites', this.$route.params.siteSlug);
this.releases = await this.$store.dispatch('fetchSiteReleases', this.$route.params.siteSlug);
this.pageTitle = this.site.name;
}
export default {
components: {
ReleaseTile,
},
data() {
return {
site: null,
releases: null,
pageTitle: null,
};
},
mounted,
};
</script>
<style lang="scss" scoped>
@import 'theme';
.header {
display: flex;
justify-content: space-between;
padding: 1rem;
}
.title {
display: inline-block;
margin: 0 .5rem 0 0;
}
.heading {
padding: 0;
margin: 0 0 1rem 0;
}
.link {
display: flex;
flex-shrink: 0;
flex-direction: column;
align-items: flex-end;
}
.logo {
height: 3rem;
}
.networklogo-container {
color: $shadow;
display: block;
margin: .5rem 0 0 0;
}
.networklogo {
color: $text;
height: 1rem;
font-weight: bold;
}
.sites,
.scenes {
display: grid;
grid-gap: 1rem;
margin: 0 0 1rem 0;
}
.scenes {
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}
.sites {
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
</style>

View File

@ -5,8 +5,6 @@
<a
:href="`/site/${release.site.slug}`"
:title="release.network.name"
target="_blank"
rel="noopener noreferrer"
class="site site-link"
>{{ release.site.name }}</a>
@ -34,14 +32,14 @@
>
<img
v-if="release.poster"
:src="`/media/${release.poster.path}`"
:src="`/media/${release.poster.thumbnail}`"
:alt="release.title"
class="thumbnail"
>
<img
v-else-if="release.photos.length > 0"
:src="`/media/${release.photos[0].path}`"
:src="`/media/${release.photos[0].thumbnail}`"
:alt="release.title"
class="thumbnail"
>
@ -92,8 +90,6 @@
>
<a
:href="`/tag/${tag.slug}`"
target="_blank"
rel="noopener noreferrer"
class="tag-link"
>{{ tag.name }}</a>
</li>
@ -135,11 +131,8 @@ export default {
.thumbnail {
width: 100%;
height: 12rem;
display: flex;
justify-content: center;
align-items: center;
object-fit: cover;
object-position: 50% 0;
background-position: center;
background-size: cover;
background-color: $shadow-hint;

View File

@ -47,7 +47,7 @@ export default {
display: flex;
align-items: center;
justify-content: center;
height: 4rem;
height: 3rem;
object-fit: contain;
font-size: 1rem;
font-weight: bold;

View File

@ -0,0 +1,22 @@
import { get } from '../api';
function initSitesActions(_store, _router) {
async function fetchSites({ _commit }, siteId) {
const sites = await get(`/sites/${siteId || ''}`);
return sites;
}
async function fetchSiteReleases({ _commit }, siteId) {
const releases = await get(`/sites/${siteId}/releases`);
return releases;
}
return {
fetchSites,
fetchSiteReleases,
};
}
export default initSitesActions;

View File

@ -0,0 +1 @@
export default {};

13
assets/js/sites/sites.js Normal file
View File

@ -0,0 +1,13 @@
import state from './state';
import mutations from './mutations';
import actions from './actions';
function initSitesStore(store, router) {
return {
state,
mutations,
actions: actions(store, router),
};
}
export default initSitesStore;

1
assets/js/sites/state.js Normal file
View File

@ -0,0 +1 @@
export default {};

View File

@ -3,6 +3,7 @@ import Vuex from 'vuex';
import initAuthStore from './auth/auth';
import initReleasesStore from './releases/releases';
import initSitesStore from './sites/sites';
import initNetworksStore from './networks/networks';
import initActorsStore from './actors/actors';
@ -14,6 +15,7 @@ function initStore(router) {
store.registerModule('auth', initAuthStore(store, router));
store.registerModule('releases', initReleasesStore(store, router));
store.registerModule('actors', initActorsStore(store, router));
store.registerModule('sites', initSitesStore(store, router));
store.registerModule('networks', initNetworksStore(store, router));
return store;

View File

@ -12,6 +12,8 @@ module.exports = {
'21sextury',
'blowpass',
'brazzers',
'dogfart',
'evilangel',
'julesjordan',
['kink', [
'boundgangbangs',
@ -27,6 +29,7 @@ module.exports = {
'waterbondage',
]],
'legalporno',
'mikeadriano',
'mofos',
'naughtyamerica',
'pervcity',
@ -79,7 +82,10 @@ module.exports = {
width: 30,
},
],
photoPath: './',
media: {
path: './',
thumbnailSize: 324, // width for 16:9 will be exactly 576px
},
filename: {
dateFormat: 'DD-MM-YYYY',
actorsJoin: ', ',

View File

@ -145,8 +145,10 @@ exports.up = knex => Promise.resolve()
table.increments('id', 16);
table.string('path');
table.string('thumbnail');
table.integer('index');
table.string('mime');
table.string('hash');
table.enum('domain', ['networks', 'sites', 'releases', 'actors', 'directors']);
table.integer('target_id', 16);

346
package-lock.json generated
View File

@ -1584,8 +1584,7 @@
"aproba": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
"dev": true
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
},
"arch": {
"version": "2.1.1",
@ -1596,7 +1595,6 @@
"version": "1.1.5",
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
"dev": true,
"requires": {
"delegates": "^1.0.0",
"readable-stream": "^2.0.6"
@ -2446,6 +2444,41 @@
"integrity": "sha512-EgmjVLMn22z7eGGv3kcnHwSnJXmFHjISTY9E/S5lIcTD3Oxw05QTcBLNkJFzcb3cNueUdF/IN4U+d78V0zO8Hw==",
"dev": true
},
"bl": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/bl/-/bl-3.0.0.tgz",
"integrity": "sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==",
"requires": {
"readable-stream": "^3.0.1"
},
"dependencies": {
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"blake2": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/blake2/-/blake2-4.0.0.tgz",
"integrity": "sha512-PIOc6RXAZYBYcdpyMzI6/SCU3BH8EbmA9vr0BAVyQv48CQTXDN6viHOTM+8KQue2IPsyHNpIR3UDisz8rZDPTA==",
"requires": {
"nan": "^2.14.0"
},
"dependencies": {
"nan": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
}
}
},
"block-stream": {
"version": "0.0.9",
"resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
@ -2859,8 +2892,7 @@
"chownr": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
"dev": true
"integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g=="
},
"chrome-trace-event": {
"version": "1.0.2",
@ -3003,6 +3035,15 @@
"object-visit": "^1.0.0"
}
},
"color": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/color/-/color-3.1.2.tgz",
"integrity": "sha512-vXTJhHebByxZn3lDvDJYw4lR5+uB3vuoHsuYA5AKuxRVn5wzzIfQKGLBmgdVRHKTJYeK5rvJcHnrd0Li49CFpg==",
"requires": {
"color-convert": "^1.9.1",
"color-string": "^1.5.2"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@ -3016,6 +3057,15 @@
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
},
"color-string": {
"version": "1.5.3",
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.3.tgz",
"integrity": "sha512-dC2C5qeWoYkxki5UAXapdjqO672AM4vZuPGRQfO8b5HKuKGBbKWpITyDYN7TOFKvRW7kOgAn3746clDBMDJyQw==",
"requires": {
"color-name": "^1.0.0",
"simple-swizzle": "^0.2.2"
}
},
"colors": {
"version": "1.3.3",
"resolved": "https://registry.npmjs.org/colors/-/colors-1.3.3.tgz",
@ -3121,8 +3171,7 @@
"console-control-strings": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
"dev": true
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
},
"consolidate": {
"version": "0.15.1",
@ -3480,6 +3529,19 @@
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
"integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU="
},
"decompress-response": {
"version": "4.2.1",
"resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz",
"integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==",
"requires": {
"mimic-response": "^2.0.0"
}
},
"deep-extend": {
"version": "0.6.0",
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
},
"deep-is": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
@ -3547,8 +3609,7 @@
"delegates": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
"dev": true
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
},
"depd": {
"version": "1.1.2",
@ -3584,6 +3645,11 @@
"repeating": "^2.0.0"
}
},
"detect-libc": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
},
"dev-null": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/dev-null/-/dev-null-0.1.1.tgz",
@ -4293,6 +4359,11 @@
}
}
},
"expand-template": {
"version": "2.0.3",
"resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz",
"integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg=="
},
"expand-tilde": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
@ -4809,6 +4880,11 @@
"readable-stream": "^2.0.0"
}
},
"fs-constants": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz",
"integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow=="
},
"fs-extra": {
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz",
@ -4819,6 +4895,14 @@
"universalify": "^0.1.0"
}
},
"fs-minipass": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.0.0.tgz",
"integrity": "sha512-40Qz+LFXmd9tzYVnnBmZvFfvAADfUA14TXPK1s7IfElJTIZ97rA8w4Kin7Wt5JBrC3ShnnFJO/5vPjPEeJIq9A==",
"requires": {
"minipass": "^3.0.0"
}
},
"fs-readdir-recursive": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/fs-readdir-recursive/-/fs-readdir-recursive-1.1.0.tgz",
@ -5418,7 +5502,6 @@
"version": "2.7.4",
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
"dev": true,
"requires": {
"aproba": "^1.0.3",
"console-control-strings": "^1.0.0",
@ -5433,14 +5516,12 @@
"ansi-regex": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
"dev": true
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
},
"is-fullwidth-code-point": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
"dev": true,
"requires": {
"number-is-nan": "^1.0.0"
}
@ -5449,7 +5530,6 @@
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
"dev": true,
"requires": {
"code-point-at": "^1.0.0",
"is-fullwidth-code-point": "^1.0.0",
@ -5460,7 +5540,6 @@
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
"dev": true,
"requires": {
"ansi-regex": "^2.0.0"
}
@ -5508,6 +5587,11 @@
"assert-plus": "^1.0.0"
}
},
"github-from-package": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz",
"integrity": "sha1-l/tdlr/eiXMxPyDoKI75oWf6ZM4="
},
"glob": {
"version": "7.1.3",
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
@ -5679,8 +5763,7 @@
"has-unicode": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
"dev": true
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
},
"has-value": {
"version": "1.0.0",
@ -7137,6 +7220,11 @@
"integrity": "sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==",
"dev": true
},
"mimic-response": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.0.0.tgz",
"integrity": "sha512-8ilDoEapqA4uQ3TwS0jakGONKXVJqpy+RpM+3b7pLdOjghCrEiGp9SRkFbUHAmZW9vdnrENWHjaweIoTIJExSQ=="
},
"mini-css-extract-plugin": {
"version": "0.7.0",
"resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-0.7.0.tgz",
@ -7174,6 +7262,37 @@
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
"integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
},
"minipass": {
"version": "3.1.1",
"resolved": "https://registry.npmjs.org/minipass/-/minipass-3.1.1.tgz",
"integrity": "sha512-UFqVihv6PQgwj8/yTGvl9kPz7xIAY+R5z6XYjRInD3Gk3qx6QGSD6zEcpeG4Dy/lQnv1J6zv8ejV90hyYIKf3w==",
"requires": {
"yallist": "^4.0.0"
},
"dependencies": {
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"minizlib": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.0.tgz",
"integrity": "sha512-EzTZN/fjSvifSX0SlqUERCN39o6T40AMarPbv0MrarSFtIITCBh7bi+dU8nxGFHuqs9jdIAeoYoKuQAAASsPPA==",
"requires": {
"minipass": "^3.0.0",
"yallist": "^4.0.0"
},
"dependencies": {
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"mississippi": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz",
@ -7310,6 +7429,11 @@
"to-regex": "^3.0.1"
}
},
"napi-build-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.1.tgz",
"integrity": "sha512-boQj1WFgQH3v4clhu3mTNfP+vOBxorDlE8EKiMjUlLG3C4qAESnn9AxIOkFgTR2c9LtzNjPrjS60cT27ZKBhaA=="
},
"natural-compare": {
"version": "1.4.0",
"resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
@ -7337,6 +7461,14 @@
"resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
"integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ=="
},
"node-abi": {
"version": "2.12.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-2.12.0.tgz",
"integrity": "sha512-VhPBXCIcvmo/5K8HPmnWJyyhvgKxnHTUMXR/XwGHV68+wrgkzST4UmQrY/XszSWA5dtnXpNp528zkcyJ/pzVcw==",
"requires": {
"semver": "^5.4.1"
}
},
"node-gyp": {
"version": "3.8.0",
"resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
@ -7520,6 +7652,11 @@
}
}
},
"noop-logger": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/noop-logger/-/noop-logger-0.1.1.tgz",
"integrity": "sha1-lKKxYzxPExdVMAfYlm/Q6EG2pMI="
},
"nopt": {
"version": "4.0.1",
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
@ -7577,7 +7714,6 @@
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
"dev": true,
"requires": {
"are-we-there-yet": "~1.1.2",
"console-control-strings": "~1.1.0",
@ -8379,6 +8515,35 @@
}
}
},
"prebuild-install": {
"version": "5.3.3",
"resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-5.3.3.tgz",
"integrity": "sha512-GV+nsUXuPW2p8Zy7SarF/2W/oiK8bFQgJcncoJ0d7kRpekEA0ftChjfEaF9/Y+QJEc/wFR7RAEa8lYByuUIe2g==",
"requires": {
"detect-libc": "^1.0.3",
"expand-template": "^2.0.3",
"github-from-package": "0.0.0",
"minimist": "^1.2.0",
"mkdirp": "^0.5.1",
"napi-build-utils": "^1.0.1",
"node-abi": "^2.7.0",
"noop-logger": "^0.1.1",
"npmlog": "^4.0.1",
"pump": "^3.0.0",
"rc": "^1.2.7",
"simple-get": "^3.0.3",
"tar-fs": "^2.0.0",
"tunnel-agent": "^0.6.0",
"which-pm-runs": "^1.0.0"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
},
"prelude-ls": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
@ -8655,6 +8820,24 @@
"schema-utils": "^1.0.0"
}
},
"rc": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
"requires": {
"deep-extend": "^0.6.0",
"ini": "~1.3.0",
"minimist": "^1.2.0",
"strip-json-comments": "~2.0.1"
},
"dependencies": {
"minimist": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
"integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
}
}
},
"react": {
"version": "16.8.6",
"resolved": "https://registry.npmjs.org/react/-/react-16.8.6.tgz",
@ -9506,6 +9689,34 @@
}
}
},
"sharp": {
"version": "0.23.2",
"resolved": "https://registry.npmjs.org/sharp/-/sharp-0.23.2.tgz",
"integrity": "sha512-BSo0tq6Jtzwa6GDKvVMNNPCP/HLczrFLGVcorYv7OtxlKx4UPHy7x9DdfT8F+PK7FCFDemVRwtsjWpvaJI9v6w==",
"requires": {
"color": "^3.1.2",
"detect-libc": "^1.0.3",
"nan": "^2.14.0",
"npmlog": "^4.1.2",
"prebuild-install": "^5.3.2",
"semver": "^6.3.0",
"simple-get": "^3.1.0",
"tar": "^5.0.5",
"tunnel-agent": "^0.6.0"
},
"dependencies": {
"nan": {
"version": "2.14.0",
"resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
"integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
},
"semver": {
"version": "6.3.0",
"resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
"integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
}
}
},
"shebang-command": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
@ -9529,6 +9740,36 @@
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
"integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
},
"simple-concat": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.0.tgz",
"integrity": "sha1-c0TLuLbib7J9ZrL8hvn21Zl1IcY="
},
"simple-get": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.0.tgz",
"integrity": "sha512-bCR6cP+aTdScaQCnQKbPKtJOKDp/hj9EDLJo3Nw4y1QksqaovlW/bnptB6/c1e+qmNIDHRK+oXFDdEqBT8WzUA==",
"requires": {
"decompress-response": "^4.2.0",
"once": "^1.3.1",
"simple-concat": "^1.0.0"
}
},
"simple-swizzle": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz",
"integrity": "sha1-pNprY1/8zMoz9w0Xy5JZLeleVXo=",
"requires": {
"is-arrayish": "^0.3.1"
},
"dependencies": {
"is-arrayish": {
"version": "0.3.2",
"resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz",
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="
}
}
},
"slash": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz",
@ -10027,8 +10268,7 @@
"strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
"dev": true
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
},
"style-loader": {
"version": "0.23.1",
@ -10099,6 +10339,66 @@
"integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==",
"dev": true
},
"tar": {
"version": "5.0.5",
"resolved": "https://registry.npmjs.org/tar/-/tar-5.0.5.tgz",
"integrity": "sha512-MNIgJddrV2TkuwChwcSNds/5E9VijOiw7kAc1y5hTNJoLDSuIyid2QtLYiCYNnICebpuvjhPQZsXwUL0O3l7OQ==",
"requires": {
"chownr": "^1.1.3",
"fs-minipass": "^2.0.0",
"minipass": "^3.0.0",
"minizlib": "^2.1.0",
"mkdirp": "^0.5.0",
"yallist": "^4.0.0"
},
"dependencies": {
"chownr": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz",
"integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw=="
},
"yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
}
}
},
"tar-fs": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz",
"integrity": "sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==",
"requires": {
"chownr": "^1.1.1",
"mkdirp": "^0.5.1",
"pump": "^3.0.0",
"tar-stream": "^2.0.0"
}
},
"tar-stream": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.0.tgz",
"integrity": "sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==",
"requires": {
"bl": "^3.0.0",
"end-of-stream": "^1.4.1",
"fs-constants": "^1.0.0",
"inherits": "^2.0.3",
"readable-stream": "^3.1.1"
},
"dependencies": {
"readable-stream": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
"integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
"requires": {
"inherits": "^2.0.3",
"string_decoder": "^1.1.1",
"util-deprecate": "^1.0.1"
}
}
}
},
"tarn": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/tarn/-/tarn-1.1.4.tgz",
@ -11103,11 +11403,15 @@
"resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz",
"integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho="
},
"which-pm-runs": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz",
"integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs="
},
"wide-align": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
"dev": true,
"requires": {
"string-width": "^1.0.2 || 2"
}

View File

@ -64,6 +64,7 @@
},
"dependencies": {
"bhttp": "^1.2.4",
"blake2": "^4.0.0",
"bluebird": "^3.5.4",
"body-parser": "^1.19.0",
"cheerio": "^1.0.0-rc.2",
@ -86,6 +87,7 @@
"prop-types": "^15.7.2",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"sharp": "^0.23.2",
"tough-cookie": "^3.0.1",
"tty-table": "^2.7.0",
"vue": "^2.6.10",

View File

@ -15,12 +15,10 @@
}
.thumbnail[data-v-3abcf101] {
width: 100%;
height: 12rem;
display: flex;
justify-content: center;
align-items: center;
-o-object-fit: cover;
object-fit: cover;
-o-object-position: 50% 0;
object-position: 50% 0;
background-position: center;
background-size: cover;
background-color: rgba(0, 0, 0, 0.1);
@ -226,6 +224,52 @@
color: #ff6c88;
}
/* $primary: #ff886c; */
.header[data-v-3e57cf44] {
display: flex;
justify-content: space-between;
padding: 1rem;
}
.title[data-v-3e57cf44] {
display: inline-block;
margin: 0 .5rem 0 0;
}
.heading[data-v-3e57cf44] {
padding: 0;
margin: 0 0 1rem 0;
}
.link[data-v-3e57cf44] {
display: flex;
flex-shrink: 0;
flex-direction: column;
align-items: flex-end;
}
.logo[data-v-3e57cf44] {
height: 3rem;
}
.networklogo-container[data-v-3e57cf44] {
color: rgba(0, 0, 0, 0.5);
display: block;
margin: .5rem 0 0 0;
}
.networklogo[data-v-3e57cf44] {
color: #222;
height: 1rem;
font-weight: bold;
}
.sites[data-v-3e57cf44],
.scenes[data-v-3e57cf44] {
display: grid;
grid-gap: 1rem;
margin: 0 0 1rem 0;
}
.scenes[data-v-3e57cf44] {
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}
.sites[data-v-3e57cf44] {
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
/* $primary: #ff886c; */
.tile[data-v-f4958086] {
display: flex;
@ -247,7 +291,7 @@
display: flex;
align-items: center;
justify-content: center;
height: 4rem;
height: 3rem;
-o-object-fit: contain;
object-fit: contain;
font-size: 1rem;
@ -288,7 +332,7 @@
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
}
.sites[data-v-757c14c2] {
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
grid-template-columns: repeat(auto-fit, minmax(15rem, 1fr));
}
/* $primary: #ff886c; */

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

View File

@ -8,6 +8,6 @@
"no-unused-vars": ["error", {"argsIgnorePattern": "^_"}],
"no-console": 0,
"indent": ["error", 4],
"max-len": [2, {"code": 200, "tabWidth": 4, "ignoreUrls": true}]
"max-len": [2, {"code": 300, "tabWidth": 4, "ignoreUrls": true}]
}
}

View File

@ -35,6 +35,24 @@ async function fetchActors(actorId, actorSlug) {
return curateActors(releases);
}
async function storeActors(release, releaseEntry) {
const actors = await knex('actors').whereIn('name', release.actors);
const newActors = release.actors.filter(actorName => !actors.some(actor => actor.name === actorName));
const { rows: insertedActors } = newActors.length
? await knex.raw(`${knex('actors').insert(newActors.map(actorName => ({
name: actorName,
slug: actorName.toLowerCase().replace(/\s+/g, '-'),
})))} ON CONFLICT DO NOTHING RETURNING *`)
: { rows: [] };
return knex('actors_associated').insert(actors.concat(insertedActors).map(actor => ({
release_id: releaseEntry.id,
actor_id: actor.id,
})), '*');
}
module.exports = {
fetchActors,
storeActors,
};

View File

@ -5,13 +5,14 @@ const fs = require('fs-extra');
const path = require('path');
const Promise = require('bluebird');
const moment = require('moment');
const mime = require('mime');
const bhttp = require('bhttp');
const argv = require('./argv');
const knex = require('./knex');
const scrapers = require('./scrapers');
const fetchScene = require('./fetch-scene');
const { storeTags } = require('./tags');
const { storeActors } = require('./actors');
const { storePoster, storePhotos, storeTrailer } = require('./media');
function destructConfigNetworks(networks) {
return networks.reduce((acc, network) => {
@ -87,112 +88,6 @@ async function findDuplicateReleases(latestReleases, _siteId) {
.orWhereIn('entry_id', latestReleasesEntryIds);
}
async function storeActors(release, releaseEntry) {
const actors = await knex('actors').whereIn('name', release.actors);
const newActors = release.actors.filter(actorName => !actors.some(actor => actor.name === actorName));
const { rows: insertedActors } = newActors.length
? await knex.raw(`${knex('actors').insert(newActors.map(actorName => ({
name: actorName,
slug: actorName.toLowerCase().replace(/\s+/g, '-'),
})))} ON CONFLICT DO NOTHING RETURNING *`)
: { rows: [] };
return knex('actors_associated').insert(actors.concat(insertedActors).map(actor => ({
release_id: releaseEntry.id,
actor_id: actor.id,
})), '*');
}
async function storeTags(release, releaseEntry) {
return knex('tags_associated').insert(release.tags.map(tagId => ({
tag_id: tagId,
release_id: releaseEntry.id,
})));
}
async function storePhotos(release, releaseEntry) {
console.log(`Storing ${release.photos.length} photos for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
const files = await Promise.map(release.photos, async (photoUrl, index) => {
const { pathname } = new URL(photoUrl);
const mimetype = mime.getType(pathname);
const res = await bhttp.get(photoUrl);
if (res.statusCode === 200) {
const filepath = path.join(release.site.slug, releaseEntry.id.toString(), `${index + 1}.${mime.getExtension(mimetype)}`);
await fs.writeFile(path.join(config.photoPath, filepath), res.body);
return {
filepath,
mimetype,
};
}
console.warn(`Failed to store photo ${index + 1} for (${release.site.name}, ${releaseEntry.id}) "${release.title}": ${res.statusCode}`);
return null;
}, {
concurrency: 2,
});
await knex('media').insert(files.filter(file => file).map(({ filepath, mimetype }, index) => ({
path: filepath,
mime: mimetype,
index,
domain: 'releases',
target_id: releaseEntry.id,
role: 'photo',
})));
}
async function storePoster(release, releaseEntry) {
console.log(`Storing poster for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
const res = await bhttp.get(release.poster);
if (res.statusCode === 200) {
const { pathname } = new URL(release.poster);
const mimetype = res.headers['content-type'] || mime.getType(pathname) || 'image/jpeg';
const filepath = path.join(release.site.slug, releaseEntry.id.toString(), `poster.${mime.getExtension(mimetype)}`);
await fs.writeFile(path.join(config.photoPath, filepath), res.body);
await knex('media').insert({
path: filepath,
mime: mimetype,
domain: 'releases',
target_id: releaseEntry.id,
role: 'poster',
});
return;
}
console.warn(`Failed to store poster for (${release.site.name}, ${releaseEntry.id}) "${release.title}": ${res.statusCode}`);
}
async function storeTrailer(release, releaseEntry) {
console.log(`Storing trailer for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
const { pathname } = new URL(release.trailer.src);
const mimetype = release.trailer.type || mime.getType(pathname);
const res = await bhttp.get(release.trailer.src);
const filepath = path.join(release.site.slug, releaseEntry.id.toString(), `trailer${release.trailer.quality ? `_${release.trailer.quality}` : ''}.${mime.getExtension(mimetype)}`);
await fs.writeFile(path.join(config.photoPath, filepath), res.body);
await knex('media').insert({
path: filepath,
mime: mimetype,
domain: 'releases',
target_id: releaseEntry.id,
role: 'trailer',
quality: release.trailer.quality || null,
});
}
async function storeReleases(releases = []) {
return Promise.map(releases, async (release) => {
const curatedRelease = {
@ -212,11 +107,6 @@ async function storeReleases(releases = []) {
deep: argv.deep,
};
/*
const releaseQuery = `${knex('releases').insert(curatedRelease).toString()} ON CONFLICT DO NOTHING RETURNING *`;
const releaseEntry = await knex.raw(releaseQuery);
*/
const releaseEntries = await knex('releases')
.insert(curatedRelease)
.returning('*');
@ -227,7 +117,7 @@ async function storeReleases(releases = []) {
console.log(`Stored (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
if (release.poster || (release.photos && release.photos.length)) {
await fs.mkdir(path.join(config.photoPath, release.site.slug, releaseEntry.id.toString()), { recursive: true });
await fs.mkdir(path.join(config.media.path, release.site.network.slug, release.site.slug, releaseEntry.id.toString()), { recursive: true });
}
await Promise.all([

137
src/media.js Normal file
View File

@ -0,0 +1,137 @@
'use strict';
const config = require('config');
const Promise = require('bluebird');
const path = require('path');
const fs = require('fs-extra');
const bhttp = require('bhttp');
const mime = require('mime');
const sharp = require('sharp');
const blake2 = require('blake2');
const knex = require('./knex');
function getHash(buffer) {
const hash = blake2.createHash('blake2b', { digestLength: 24 });
hash.update(buffer);
return hash.digest('hex');
}
async function storePoster(release, releaseEntry) {
console.log(`Storing poster for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
const res = await bhttp.get(release.poster);
const thumbnail = await sharp(res.body)
.resize({ width: Math.floor((config.media.thumbnailSize / 9) * 16), height: config.media.thumbnailSize }) // ensure thumbnail is 16:9
.toBuffer();
if (res.statusCode === 200) {
const { pathname } = new URL(release.poster);
const mimetype = res.headers['content-type'] || mime.getType(pathname) || 'image/jpeg';
const extension = mime.getExtension(mimetype);
const filepath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `poster.${extension}`);
const thumbpath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `poster_thumb.${extension}`);
const hash = getHash(res.body);
await Promise.all([
fs.writeFile(path.join(config.media.path, filepath), res.body),
fs.writeFile(path.join(config.media.path, thumbpath), thumbnail),
]);
await knex('media').insert({
path: filepath,
thumbnail: thumbpath,
mime: mimetype,
hash,
domain: 'releases',
target_id: releaseEntry.id,
role: 'poster',
});
return;
}
console.warn(`Failed to store poster for (${release.site.name}, ${releaseEntry.id}) "${release.title}": ${res.statusCode}`);
}
async function storePhotos(release, releaseEntry) {
console.log(`Storing ${release.photos.length} photos for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
const files = await Promise.map(release.photos, async (photoUrl, index) => {
const { pathname } = new URL(photoUrl);
const mimetype = mime.getType(pathname);
const res = await bhttp.get(photoUrl);
const thumbnail = await sharp(res.body).resize({ height: config.media.thumbnailSize }).toBuffer();
if (res.statusCode === 200) {
const extension = mime.getExtension(mimetype);
const filepath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `${index + 1}.${extension}`);
const thumbpath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `${index + 1}_thumb.${extension}`);
const hash = getHash(res.body);
await Promise.all([
fs.writeFile(path.join(config.media.path, filepath), res.body),
fs.writeFile(path.join(config.media.path, thumbpath), thumbnail),
]);
return {
filepath,
thumbpath,
mimetype,
hash,
};
}
console.warn(`Failed to store photo ${index + 1} for (${release.site.name}, ${releaseEntry.id}) "${release.title}": ${res.statusCode}`);
return null;
}, {
concurrency: 2,
});
await knex('media')
.insert(files.filter(file => file)
.map((file, index) => ({
path: file.filepath,
thumbnail: file.thumbpath,
mime: file.mimetype,
hash: file.hash,
index,
domain: 'releases',
target_id: releaseEntry.id,
role: 'photo',
})));
}
async function storeTrailer(release, releaseEntry) {
console.log(`Storing trailer for (${release.site.name}, ${releaseEntry.id}) "${release.title}"`);
const { pathname } = new URL(release.trailer.src);
const mimetype = release.trailer.type || mime.getType(pathname);
const res = await bhttp.get(release.trailer.src);
const filepath = path.join(release.site.network.slug, release.site.slug, releaseEntry.id.toString(), `trailer${release.trailer.quality ? `_${release.trailer.quality}` : ''}.${mime.getExtension(mimetype)}`);
await Promise.all([
fs.writeFile(path.join(config.media.path, filepath), res.body),
knex('media').insert({
path: filepath,
mime: mimetype,
domain: 'releases',
target_id: releaseEntry.id,
role: 'trailer',
quality: release.trailer.quality || null,
}),
]);
}
module.exports = {
storePoster,
storePhotos,
storeTrailer,
};

View File

@ -3,8 +3,6 @@
const knex = require('./knex');
async function curateSite(site) {
const network = await knex('network').where({ id: site.network_id });
return {
id: site.id,
name: site.name,
@ -12,36 +10,40 @@ async function curateSite(site) {
description: site.description,
slug: site.slug,
network: {
id: network.id,
name: network.name,
url: network.url,
description: network.description,
slug: network.slug,
id: site.network_id,
name: site.network_name,
slug: site.network_slug,
url: site.network_url,
},
};
}
function curateSites(releases) {
return Promise.all(releases.map(async site => curateSite(site)));
function curateSites(sites) {
return Promise.all(sites.map(async site => curateSite(site)));
}
async function fetchSites(siteId, siteSlug) {
const releases = await knex('sites')
.where({ id: siteId })
.orWhere({ slug: siteSlug })
const sites = await knex('sites')
.where({ 'sites.id': siteId })
.orWhere({ 'sites.slug': siteSlug })
.select(
'sites.*',
'networks.name as network_name', 'networks.slug as network_slug', 'networks.url as network_url',
)
.leftJoin('networks', 'sites.network_id', 'networks.id')
.limit(100);
return curateSites(releases);
return curateSites(sites);
}
async function fetchSitesFromReleases() {
const releases = await knex('releases')
const sites = await knex('releases')
.select('site_id', '')
.leftJoin('sites', 'sites.id', 'releases.site_id')
.groupBy('sites.id')
.limit(100);
return curateSites(releases);
return curateSites(sites);
}
module.exports = {

View File

@ -25,4 +25,14 @@ async function matchTags(rawTags) {
return tagEntries;
}
module.exports = { matchTags };
async function storeTags(release, releaseEntry) {
return knex('tags_associated').insert(release.tags.map(tagId => ({
tag_id: tagId,
release_id: releaseEntry.id,
})));
}
module.exports = {
matchTags,
storeTags,
};

View File

@ -25,7 +25,7 @@ function initServer() {
const app = express();
const router = Router();
router.use('/media', express.static(config.photoPath));
router.use('/media', express.static(config.media.path));
router.use(express.static('public'));
router.use('/img', (req, res) => {

View File

@ -1,6 +1,6 @@
'use strict';
const { fetchSites, fetchSitesFromReleases } = require('../networks');
const { fetchSites, fetchSitesFromReleases } = require('../sites');
async function fetchSitesApi(req, res) {
const siteId = typeof req.params.siteId === 'number' ? req.params.siteId : null;