Using grid layout with thumbnails.
This commit is contained in:
parent
8eb2dcfd89
commit
e3558fc0c5
10
.eslintrc
10
.eslintrc
|
@ -1,15 +1,21 @@
|
||||||
{
|
{
|
||||||
"root": true,
|
"root": true,
|
||||||
"parser": "babel-eslint",
|
"parser": "babel-eslint",
|
||||||
"extends": "airbnb-base",
|
"extends": ["airbnb", "plugin:react/recommended"],
|
||||||
|
"plugins": ["react"],
|
||||||
"parserOptions": {
|
"parserOptions": {
|
||||||
"sourceType": "script",
|
"sourceType": "script",
|
||||||
|
"ecmaFeatures": {
|
||||||
|
"jsx": true
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"rules": {
|
"rules": {
|
||||||
"strict": 0,
|
"strict": 0,
|
||||||
"no-unused-vars": ["error", {"argsIgnorePattern": "^_"}],
|
"no-unused-vars": ["error", {"argsIgnorePattern": "^_"}],
|
||||||
"no-console": 0,
|
"no-console": 0,
|
||||||
"indent": ["error", 4],
|
"indent": ["error", 4],
|
||||||
"max-len": [2, {"code": 200, "tabWidth": 4, "ignoreUrls": true}]
|
"max-len": [2, {"code": 200, "tabWidth": 4, "ignoreUrls": true}],
|
||||||
|
"react/jsx-uses-vars": 2,
|
||||||
|
"react/jsx-indent": ["error", 4],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,32 +3,88 @@
|
||||||
const React = require('react');
|
const React = require('react');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
|
||||||
|
const Layout = require('./layout.jsx');
|
||||||
|
|
||||||
class Home extends React.Component {
|
class Home extends React.Component {
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<table>
|
<Layout>
|
||||||
<tr>
|
<ul className="scenes">
|
||||||
<th>Date</th>
|
{this.props.releases.map(release => (
|
||||||
<th>ID</th>
|
<li key={release.id} className="scene">
|
||||||
<th>Shoot ID / Entry ID</th>
|
<a
|
||||||
<th>Site</th>
|
href={`/item/${release.id}`}
|
||||||
<th>Title</th>
|
target="_blank"
|
||||||
<th>Actors</th>
|
>
|
||||||
<th>Tags</th>
|
<img
|
||||||
</tr>
|
src={`/${release.site.id}/${release.id}/0.jpg`}
|
||||||
|
className="scene-thumbnail"
|
||||||
|
/>
|
||||||
|
</a>
|
||||||
|
|
||||||
{this.props.releases.map(release => (
|
<div className="scene-info">
|
||||||
<tr key={release.id}>
|
<a
|
||||||
<td>{ moment(release.date).format('YYYY-MM-DD') }</td>
|
href={`/item/${release.id}`}
|
||||||
<td>{ release.id }</td>
|
target="_blank"
|
||||||
<td>{ release.shootId || release.entryId }</td>
|
rel="noopener noreferrer"
|
||||||
<td>{ release.site.name }</td>
|
className="scene-row scene-link"
|
||||||
<td>{ release.title }</td>
|
><h2 className="scene-title">{release.title}</h2></a>
|
||||||
<td>{ release.actors.map(actor => actor.name).join(', ') }</td>
|
|
||||||
<td>{ release.tags.map(tag => tag.tag).join(', ') }</td>
|
<span className="scene-row">
|
||||||
</tr>
|
<a
|
||||||
))}
|
href={`/site/${release.site.id}`}
|
||||||
</table>
|
className="scene-site site-link"
|
||||||
|
>{release.site.name}</a>
|
||||||
|
|
||||||
|
<span>
|
||||||
|
<a
|
||||||
|
className="scene-network"
|
||||||
|
href={`/network/${release.network.id}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
>{release.network.name}</a>
|
||||||
|
|
||||||
|
<a
|
||||||
|
href={release.url}
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="scene-date"
|
||||||
|
>{moment(release.date).format('YYYY-MM-DD')}</a>
|
||||||
|
</span>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span className="scene-row">
|
||||||
|
<ul className="scene-actors nolist">{release.actors.map(actor =>
|
||||||
|
<li
|
||||||
|
key={actor.id}
|
||||||
|
className="scene-actor"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={`/actor/${actor.id}`}
|
||||||
|
className="actor-link"
|
||||||
|
>{actor.name}</a>
|
||||||
|
</li>
|
||||||
|
)}</ul>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<span className="scene-row">
|
||||||
|
<ul className="scene-tags nolist">{release.tags.map(tag =>
|
||||||
|
<li
|
||||||
|
key={tag.tag}
|
||||||
|
className="scene-tag"
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href={`/tag/${tag.tag}`}
|
||||||
|
className="tag-link"
|
||||||
|
>{tag.tag}</a>
|
||||||
|
</li>
|
||||||
|
)}</ul>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</Layout>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
const React = require('react');
|
||||||
|
|
||||||
|
class Layout extends React.Component {
|
||||||
|
render() {
|
||||||
|
return (
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Traxxx</title>
|
||||||
|
|
||||||
|
<link href="/css/style.css" rel="stylesheet" />
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
{this.props.children}
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = Layout;
|
|
@ -81,6 +81,7 @@ module.exports = {
|
||||||
width: 30,
|
width: 30,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
thumbnailPath: '/home/niels/Pictures/traxxx',
|
||||||
filename: {
|
filename: {
|
||||||
dateFormat: 'DD-MM-YYYY',
|
dateFormat: 'DD-MM-YYYY',
|
||||||
actorsJoin: ', ',
|
actorsJoin: ', ',
|
||||||
|
|
|
@ -969,6 +969,16 @@
|
||||||
"sprintf-js": "~1.0.2"
|
"sprintf-js": "~1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"aria-query": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-ZbP8wcoRVajJrmTW7uKX8V1RM8w=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ast-types-flow": "0.0.7",
|
||||||
|
"commander": "^2.11.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"arr-diff": {
|
"arr-diff": {
|
||||||
"version": "4.0.0",
|
"version": "4.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
|
||||||
|
@ -994,6 +1004,16 @@
|
||||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||||
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
"integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI="
|
||||||
},
|
},
|
||||||
|
"array-includes": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.0.3.tgz",
|
||||||
|
"integrity": "sha1-GEtI9i2S10UrsxsyMWXH+L0CJm0=",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"define-properties": "^1.1.2",
|
||||||
|
"es-abstract": "^1.7.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"array-slice": {
|
"array-slice": {
|
||||||
"version": "1.1.0",
|
"version": "1.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
|
||||||
|
@ -1022,6 +1042,12 @@
|
||||||
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
|
||||||
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
|
"integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c="
|
||||||
},
|
},
|
||||||
|
"ast-types-flow": {
|
||||||
|
"version": "0.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.7.tgz",
|
||||||
|
"integrity": "sha1-9wtzXGvKGlycItmCw+Oef+ujva0=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"astral-regex": {
|
"astral-regex": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz",
|
||||||
|
@ -1054,6 +1080,15 @@
|
||||||
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
|
||||||
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
"integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
|
||||||
},
|
},
|
||||||
|
"axobject-query": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-MCeek8ZH7hKyO1rWUbKNQBbl4l2eY0ntk7OGi+q0RlafrCnfPxC06WZA+uebCfmYp4mNU9jRBP1AhGyf8+W3ww==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"ast-types-flow": "0.0.7"
|
||||||
|
}
|
||||||
|
},
|
||||||
"babel-eslint": {
|
"babel-eslint": {
|
||||||
"version": "10.0.1",
|
"version": "10.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.0.1.tgz",
|
||||||
|
@ -1740,6 +1775,12 @@
|
||||||
"lodash.get": "~4.4.2"
|
"lodash.get": "~4.4.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"damerau-levenshtein": {
|
||||||
|
"version": "1.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.4.tgz",
|
||||||
|
"integrity": "sha1-AxkcQyy27qFou3fzpV/9zLiXhRQ=",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"dashdash": {
|
"dashdash": {
|
||||||
"version": "1.14.1",
|
"version": "1.14.1",
|
||||||
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
"resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
|
||||||
|
@ -2079,6 +2120,17 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"eslint-config-airbnb": {
|
||||||
|
"version": "17.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-config-airbnb/-/eslint-config-airbnb-17.1.0.tgz",
|
||||||
|
"integrity": "sha512-R9jw28hFfEQnpPau01NO5K/JWMGLi6aymiF6RsnMURjTk+MqZKllCqGK/0tOvHkPi/NWSSOU2Ced/GX++YxLnw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"eslint-config-airbnb-base": "^13.1.0",
|
||||||
|
"object.assign": "^4.1.0",
|
||||||
|
"object.entries": "^1.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"eslint-config-airbnb-base": {
|
"eslint-config-airbnb-base": {
|
||||||
"version": "13.1.0",
|
"version": "13.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-config-airbnb-base/-/eslint-config-airbnb-base-13.1.0.tgz",
|
||||||
|
@ -2140,6 +2192,57 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"eslint-plugin-jsx-a11y": {
|
||||||
|
"version": "6.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.2.1.tgz",
|
||||||
|
"integrity": "sha512-cjN2ObWrRz0TTw7vEcGQrx+YltMvZoOEx4hWU8eEERDnBIU00OTq7Vr+jA7DFKxiwLNv4tTh5Pq2GUNEa8b6+w==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"aria-query": "^3.0.0",
|
||||||
|
"array-includes": "^3.0.3",
|
||||||
|
"ast-types-flow": "^0.0.7",
|
||||||
|
"axobject-query": "^2.0.2",
|
||||||
|
"damerau-levenshtein": "^1.0.4",
|
||||||
|
"emoji-regex": "^7.0.2",
|
||||||
|
"has": "^1.0.3",
|
||||||
|
"jsx-ast-utils": "^2.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"eslint-plugin-react": {
|
||||||
|
"version": "7.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.13.0.tgz",
|
||||||
|
"integrity": "sha512-uA5LrHylu8lW/eAH3bEQe9YdzpPaFd9yAJTwTi/i/BKTD7j6aQMKVAdGM/ML72zD6womuSK7EiGtMKuK06lWjQ==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"array-includes": "^3.0.3",
|
||||||
|
"doctrine": "^2.1.0",
|
||||||
|
"has": "^1.0.3",
|
||||||
|
"jsx-ast-utils": "^2.1.0",
|
||||||
|
"object.fromentries": "^2.0.0",
|
||||||
|
"prop-types": "^15.7.2",
|
||||||
|
"resolve": "^1.10.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"doctrine": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"esutils": "^2.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"resolve": {
|
||||||
|
"version": "1.10.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz",
|
||||||
|
"integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"path-parse": "^1.0.6"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"eslint-restricted-globals": {
|
"eslint-restricted-globals": {
|
||||||
"version": "0.1.1",
|
"version": "0.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-restricted-globals/-/eslint-restricted-globals-0.1.1.tgz",
|
||||||
|
@ -4031,6 +4134,15 @@
|
||||||
"verror": "1.10.0"
|
"verror": "1.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"jsx-ast-utils": {
|
||||||
|
"version": "2.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-2.1.0.tgz",
|
||||||
|
"integrity": "sha512-yDGDG2DS4JcqhA6blsuYbtsT09xL8AoLuUR2Gb5exrw7UEM19sBcOTq+YBBhrNbl0PUC4R4LnFu+dHg2HKeVvA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"array-includes": "^3.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"keypress": {
|
"keypress": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/keypress/-/keypress-0.2.1.tgz",
|
||||||
|
@ -4668,6 +4780,18 @@
|
||||||
"has": "^1.0.3"
|
"has": "^1.0.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"object.fromentries": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.0.tgz",
|
||||||
|
"integrity": "sha512-9iLiI6H083uiqUuvzyY6qrlmc/Gz8hLQFOcb/Ri/0xXFkSNS3ctV+CbE6yM2+AnkYfOB3dGjdzC0wrMLIhQICA==",
|
||||||
|
"dev": true,
|
||||||
|
"requires": {
|
||||||
|
"define-properties": "^1.1.2",
|
||||||
|
"es-abstract": "^1.11.0",
|
||||||
|
"function-bind": "^1.1.1",
|
||||||
|
"has": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"object.map": {
|
"object.map": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz",
|
||||||
|
|
|
@ -34,8 +34,10 @@
|
||||||
"babel-eslint": "^10.0.1",
|
"babel-eslint": "^10.0.1",
|
||||||
"babel-preset-airbnb": "^3.2.0",
|
"babel-preset-airbnb": "^3.2.0",
|
||||||
"eslint": "^5.15.0",
|
"eslint": "^5.15.0",
|
||||||
"eslint-config-airbnb-base": "^13.1.0",
|
"eslint-config-airbnb": "^17.1.0",
|
||||||
"eslint-plugin-import": "^2.16.0",
|
"eslint-plugin-import": "^2.16.0",
|
||||||
|
"eslint-plugin-jsx-a11y": "^6.2.1",
|
||||||
|
"eslint-plugin-react": "^7.13.0",
|
||||||
"eslint-watch": "^4.0.2"
|
"eslint-watch": "^4.0.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -0,0 +1,102 @@
|
||||||
|
body {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nolist {
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nolist li {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scenes {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(auto-fit, minmax(20rem, 1fr));
|
||||||
|
list-style: none;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
box-sizing: border-box;
|
||||||
|
margin: .5rem;
|
||||||
|
height: 22rem;
|
||||||
|
box-shadow: 0 0 3px rgba(0, 0, 0, .5);
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-thumbnail {
|
||||||
|
width: 100%;
|
||||||
|
height: 200px;
|
||||||
|
object-fit: cover;
|
||||||
|
background-position: center;
|
||||||
|
background-size: cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-row {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: .25rem .5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-info {
|
||||||
|
flex-grow: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-link {
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-title {
|
||||||
|
color: #000;
|
||||||
|
margin: 0;
|
||||||
|
font-size: 1rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-site {
|
||||||
|
font-weight: bold;
|
||||||
|
font-size: .8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-date {
|
||||||
|
color: #555;
|
||||||
|
font-size: .8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-network {
|
||||||
|
color: #555;
|
||||||
|
margin: 0 .25rem 0 0;
|
||||||
|
font-size: .8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-tags {
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-actor,
|
||||||
|
.scene-tag {
|
||||||
|
margin: 0 .25rem 0 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-tag {
|
||||||
|
font-size: .75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.scene-actor:not(:last-of-type)::after,
|
||||||
|
.scene-tag:not(:last-of-type):after {
|
||||||
|
content: ",";
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-link {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.actor-link,
|
||||||
|
.tag-link {
|
||||||
|
color: #000;
|
||||||
|
}
|
|
@ -882,8 +882,8 @@ exports.seed = knex => Promise.resolve()
|
||||||
network_id: 'kink',
|
network_id: 'kink',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'devinebitches',
|
id: 'divinebitches',
|
||||||
name: 'Devine Bitches',
|
name: 'Divine Bitches',
|
||||||
url: 'https://www.kink.com/channel/divinebitches',
|
url: 'https://www.kink.com/channel/divinebitches',
|
||||||
description: 'Beautiful Women Dominate Submissive Men With Pain, Humiliation And Strap-On Fucking. The best in femdom and bondage. Men on Divine Bitches respond with obedience, ass worship, cunt worship, oral servitude, pantyhose worship, and foot worship.',
|
description: 'Beautiful Women Dominate Submissive Men With Pain, Humiliation And Strap-On Fucking. The best in femdom and bondage. Men on Divine Bitches respond with obedience, ass worship, cunt worship, oral servitude, pantyhose worship, and foot worship.',
|
||||||
network_id: 'kink',
|
network_id: 'kink',
|
||||||
|
@ -1008,7 +1008,7 @@ exports.seed = knex => Promise.resolve()
|
||||||
network_id: 'kink',
|
network_id: 'kink',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
id: 'tspussyhunts',
|
id: 'tspussyhunters',
|
||||||
name: 'TS Pussy Hunters',
|
name: 'TS Pussy Hunters',
|
||||||
url: 'https://www.kink.com/channel/tspussyhunters',
|
url: 'https://www.kink.com/channel/tspussyhunters',
|
||||||
description: 'Hot TS cocks prey on the wet pussies of submissive ladies who are fucked hard till they cum. Dominant TS femme fatales with the hardest dicks, the softest tits, and the worst intentions dominate, bind, and punish bitches on the ultimate transfucking porn site.',
|
description: 'Hot TS cocks prey on the wet pussies of submissive ladies who are fucked hard till they cum. Dominant TS femme fatales with the hardest dicks, the softest tits, and the worst intentions dominate, bind, and punish bitches on the ultimate transfucking porn site.',
|
||||||
|
|
|
@ -1,8 +1,11 @@
|
||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const config = require('config');
|
const config = require('config');
|
||||||
|
const fs = require('fs-extra');
|
||||||
|
const path = require('path');
|
||||||
const Promise = require('bluebird');
|
const Promise = require('bluebird');
|
||||||
const moment = require('moment');
|
const moment = require('moment');
|
||||||
|
const bhttp = require('bhttp');
|
||||||
|
|
||||||
const argv = require('./argv');
|
const argv = require('./argv');
|
||||||
const knex = require('./knex');
|
const knex = require('./knex');
|
||||||
|
@ -75,9 +78,7 @@ async function findDuplicateReleases(latestReleases, _siteId) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function storeReleases(releases = []) {
|
async function storeReleases(releases = []) {
|
||||||
return Promise.reduce(releases, async (acc, release) => {
|
return Promise.map(releases, async (release) => {
|
||||||
await acc;
|
|
||||||
|
|
||||||
const curatedRelease = {
|
const curatedRelease = {
|
||||||
site_id: release.site.id,
|
site_id: release.site.id,
|
||||||
shoot_id: release.shootId || null,
|
shoot_id: release.shootId || null,
|
||||||
|
@ -115,7 +116,23 @@ async function storeReleases(releases = []) {
|
||||||
release_id: releaseEntry.rows[0].id,
|
release_id: releaseEntry.rows[0].id,
|
||||||
})));
|
})));
|
||||||
}
|
}
|
||||||
}, []);
|
|
||||||
|
if (release.thumbnails && release.thumbnails.length > 0) {
|
||||||
|
const thumbnailPath = path.join(config.thumbnailPath, release.site.id, releaseEntry.rows[0].id.toString());
|
||||||
|
|
||||||
|
await fs.mkdir(thumbnailPath, { recursive: true });
|
||||||
|
|
||||||
|
await Promise.map(release.thumbnails, async (thumbnailUrl, index) => {
|
||||||
|
const res = await bhttp.get(thumbnailUrl);
|
||||||
|
|
||||||
|
await fs.writeFile(path.join(thumbnailPath, `${index}.jpg`), res.body);
|
||||||
|
}, {
|
||||||
|
concurrency: 2,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
concurrency: 2,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fetchNewReleases(scraper, site, afterDate, accReleases = [], page = 1) {
|
async function fetchNewReleases(scraper, site, afterDate, accReleases = [], page = 1) {
|
||||||
|
@ -151,7 +168,7 @@ async function fetchNewReleases(scraper, site, afterDate, accReleases = [], page
|
||||||
async function fetchReleases() {
|
async function fetchReleases() {
|
||||||
const sites = await accumulateIncludedSites();
|
const sites = await accumulateIncludedSites();
|
||||||
|
|
||||||
const scenesPerSite = await Promise.all(sites.map(async (site) => {
|
const scenesPerSite = await Promise.map(sites, async (site) => {
|
||||||
const scraper = scrapers[site.id] || scrapers[site.network.id];
|
const scraper = scrapers[site.id] || scrapers[site.network.id];
|
||||||
|
|
||||||
if (scraper) {
|
if (scraper) {
|
||||||
|
@ -167,13 +184,18 @@ async function fetchReleases() {
|
||||||
|
|
||||||
if (argv.save) {
|
if (argv.save) {
|
||||||
const finalReleases = argv.deep
|
const finalReleases = argv.deep
|
||||||
? await Promise.all(newReleases.map(async (release) => {
|
? await Promise.map(newReleases, async (release) => {
|
||||||
if (release.url) {
|
if (release.url) {
|
||||||
return fetchScene(release.url);
|
const scene = await fetchScene(release.url, release);
|
||||||
|
|
||||||
|
return {
|
||||||
|
...release,
|
||||||
|
...scene,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return release;
|
return release;
|
||||||
}), {
|
}, {
|
||||||
concurrency: 2,
|
concurrency: 2,
|
||||||
})
|
})
|
||||||
: newReleases;
|
: newReleases;
|
||||||
|
@ -204,7 +226,9 @@ async function fetchReleases() {
|
||||||
}
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
}));
|
}, {
|
||||||
|
concurrency: 2,
|
||||||
|
});
|
||||||
|
|
||||||
const accumulatedScenes = scenesPerSite.reduce((acc, siteScenes) => ([...acc, ...siteScenes]), []);
|
const accumulatedScenes = scenesPerSite.reduce((acc, siteScenes) => ([...acc, ...siteScenes]), []);
|
||||||
const sortedScenes = accumulatedScenes.sort(({ date: dateA }, { date: dateB }) => moment(dateB).diff(dateA));
|
const sortedScenes = accumulatedScenes.sort(({ date: dateA }, { date: dateB }) => moment(dateB).diff(dateA));
|
||||||
|
|
|
@ -32,7 +32,11 @@ async function curateRelease(release) {
|
||||||
site: {
|
site: {
|
||||||
id: release.site_id,
|
id: release.site_id,
|
||||||
name: release.site_name,
|
name: release.site_name,
|
||||||
network: release.network_id,
|
},
|
||||||
|
network: {
|
||||||
|
id: release.network_id,
|
||||||
|
name: release.network_name,
|
||||||
|
url: release.network_url,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -43,8 +47,9 @@ function curateReleases(releases) {
|
||||||
|
|
||||||
async function fetchReleases() {
|
async function fetchReleases() {
|
||||||
const releases = await knex('releases')
|
const releases = await knex('releases')
|
||||||
.select('releases.*', 'sites.name as site_name')
|
.select('releases.*', 'sites.name as site_name', 'sites.network_id', 'networks.name as network_name', 'networks.url as network_url')
|
||||||
.leftJoin('sites', 'releases.site_id', 'sites.id')
|
.leftJoin('sites', 'releases.site_id', 'sites.id')
|
||||||
|
.leftJoin('networks', 'sites.network_id', 'networks.id')
|
||||||
.orderBy('date', 'desc')
|
.orderBy('date', 'desc')
|
||||||
.limit(100);
|
.limit(100);
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,10 @@ function scrapeLatest(html, site) {
|
||||||
const scenesElements = $('.update_details').toArray();
|
const scenesElements = $('.update_details').toArray();
|
||||||
|
|
||||||
return scenesElements.map((element) => {
|
return scenesElements.map((element) => {
|
||||||
|
const thumbnailElement = $(element).find('a img.thumbs');
|
||||||
|
const thumbnailCount = Number(thumbnailElement.attr('cnt'));
|
||||||
|
const thumbnails = Array.from({ length: thumbnailCount }, (value, index) => thumbnailElement.attr(`src${index}_1x`)).filter(thumbnailUrl => thumbnailUrl !== undefined);
|
||||||
|
|
||||||
const sceneLinkElement = $(element).children('a').eq(1);
|
const sceneLinkElement = $(element).children('a').eq(1);
|
||||||
const url = sceneLinkElement.attr('href');
|
const url = sceneLinkElement.attr('href');
|
||||||
const title = sceneLinkElement.text();
|
const title = sceneLinkElement.text();
|
||||||
|
@ -32,6 +36,7 @@ function scrapeLatest(html, site) {
|
||||||
actors,
|
actors,
|
||||||
date,
|
date,
|
||||||
site,
|
site,
|
||||||
|
thumbnails,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -41,6 +46,10 @@ function scrapeUpcoming(html, site) {
|
||||||
const scenesElements = $('#coming_soon_carousel').find('.table').toArray();
|
const scenesElements = $('#coming_soon_carousel').find('.table').toArray();
|
||||||
|
|
||||||
return scenesElements.map((element) => {
|
return scenesElements.map((element) => {
|
||||||
|
const thumbnailElement = $(element).find('a img.thumbs');
|
||||||
|
const thumbnailCount = Number(thumbnailElement.attr('cnt'));
|
||||||
|
const thumbnails = Array.from({ length: thumbnailCount }, (value, index) => thumbnailElement.attr(`src${index}_1x`)).filter(thumbnailUrl => thumbnailUrl !== undefined);
|
||||||
|
|
||||||
const shootId = $(element).find('.upcoming_updates_thumb').attr('id').match(/\d+/)[0];
|
const shootId = $(element).find('.upcoming_updates_thumb').attr('id').match(/\d+/)[0];
|
||||||
|
|
||||||
const details = $(element).find('.update_details_comingsoon')
|
const details = $(element).find('.update_details_comingsoon')
|
||||||
|
@ -66,8 +75,9 @@ function scrapeUpcoming(html, site) {
|
||||||
url: null,
|
url: null,
|
||||||
shootId,
|
shootId,
|
||||||
title,
|
title,
|
||||||
actors,
|
|
||||||
date,
|
date,
|
||||||
|
actors,
|
||||||
|
thumbnails,
|
||||||
rating: null,
|
rating: null,
|
||||||
site,
|
site,
|
||||||
};
|
};
|
||||||
|
|
|
@ -18,6 +18,8 @@ function scrapeLatest(html, site) {
|
||||||
const shootId = href.split('/')[2];
|
const shootId = href.split('/')[2];
|
||||||
const title = sceneLinkElement.text().trim();
|
const title = sceneLinkElement.text().trim();
|
||||||
|
|
||||||
|
const thumbnails = $(element).find('.rollover .roll-image').map((thumbnailIndex, thumbnailElement) => $(thumbnailElement).attr('data-imagesrc')).toArray();
|
||||||
|
|
||||||
const date = moment.utc($(element).find('.date').text(), 'MMM DD, YYYY').toDate();
|
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 actors = $(element).find('.shoot-thumb-models a').map((actorIndex, actorElement) => $(actorElement).text()).toArray();
|
||||||
const stars = $(element).find('.average-rating').attr('data-rating') / 10;
|
const stars = $(element).find('.average-rating').attr('data-rating') / 10;
|
||||||
|
@ -33,6 +35,7 @@ function scrapeLatest(html, site) {
|
||||||
title,
|
title,
|
||||||
actors,
|
actors,
|
||||||
date,
|
date,
|
||||||
|
thumbnails,
|
||||||
rating: {
|
rating: {
|
||||||
stars,
|
stars,
|
||||||
},
|
},
|
||||||
|
@ -49,6 +52,10 @@ async function scrapeScene(html, url, shootId, ratingRes, site) {
|
||||||
const title = $('h1.shoot-title span.favorite-button').attr('data-title');
|
const title = $('h1.shoot-title span.favorite-button').attr('data-title');
|
||||||
const actorsRaw = $('.shoot-info p.starring');
|
const actorsRaw = $('.shoot-info p.starring');
|
||||||
|
|
||||||
|
const thumbnails = $('.gallery .thumb img').map((thumbnailIndex, thumbnailElement) => `https://cdnp.kink.com${$(thumbnailElement).attr('data-image-file')}`).toArray();
|
||||||
|
const trailerVideo = $('.player span[data-type="trailer-src"]').attr('data-url');
|
||||||
|
const trailerPoster = $('.player video#kink-player').attr('poster');
|
||||||
|
|
||||||
const date = moment.utc($(actorsRaw)
|
const date = moment.utc($(actorsRaw)
|
||||||
.prev()
|
.prev()
|
||||||
.text()
|
.text()
|
||||||
|
@ -78,6 +85,15 @@ async function scrapeScene(html, url, shootId, ratingRes, site) {
|
||||||
date,
|
date,
|
||||||
actors,
|
actors,
|
||||||
description,
|
description,
|
||||||
|
thumbnails,
|
||||||
|
trailer: {
|
||||||
|
video: {
|
||||||
|
default: trailerVideo,
|
||||||
|
sd: trailerVideo,
|
||||||
|
hd: trailerVideo.replace('480p', '720p'),
|
||||||
|
},
|
||||||
|
poster: trailerPoster,
|
||||||
|
},
|
||||||
rating: {
|
rating: {
|
||||||
stars,
|
stars,
|
||||||
},
|
},
|
||||||
|
|
|
@ -12,6 +12,9 @@ function initServer() {
|
||||||
const app = express();
|
const app = express();
|
||||||
const router = Router();
|
const router = Router();
|
||||||
|
|
||||||
|
app.use(express.static(config.thumbnailPath));
|
||||||
|
app.use(express.static('public'));
|
||||||
|
|
||||||
app.set('views', path.join(__dirname, '../../assets/views'));
|
app.set('views', path.join(__dirname, '../../assets/views'));
|
||||||
app.set('view engine', 'jsx');
|
app.set('view engine', 'jsx');
|
||||||
app.engine('jsx', createEngine());
|
app.engine('jsx', createEngine());
|
||||||
|
|
Loading…
Reference in New Issue