diff --git a/assets/components/releases/release.vue b/assets/components/releases/release.vue
index 14da7b86..f3fa7db4 100644
--- a/assets/components/releases/release.vue
+++ b/assets/components/releases/release.vue
@@ -231,7 +231,7 @@
v-if="release.productionDate"
class="row-tidbit"
>
- Production date
+ Shoot date
{{ formatDate(release.productionDate, 'MMMM D, YYYY') }}
diff --git a/assets/img/favicon/border/android-chrome-192x192.png b/assets/img/favicon/border/android-chrome-192x192.png
new file mode 100644
index 00000000..7d75fa0f
Binary files /dev/null and b/assets/img/favicon/border/android-chrome-192x192.png differ
diff --git a/assets/img/favicon/border/android-chrome-512x512.png b/assets/img/favicon/border/android-chrome-512x512.png
new file mode 100644
index 00000000..7092374b
Binary files /dev/null and b/assets/img/favicon/border/android-chrome-512x512.png differ
diff --git a/assets/img/favicon/border/apple-touch-icon.png b/assets/img/favicon/border/apple-touch-icon.png
new file mode 100644
index 00000000..26bcf554
Binary files /dev/null and b/assets/img/favicon/border/apple-touch-icon.png differ
diff --git a/assets/img/favicon/border/browserconfig.xml b/assets/img/favicon/border/browserconfig.xml
new file mode 100644
index 00000000..50c09863
--- /dev/null
+++ b/assets/img/favicon/border/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #ff6c88
+
+
+
diff --git a/assets/img/favicon/border/favicon-16x16.png b/assets/img/favicon/border/favicon-16x16.png
new file mode 100644
index 00000000..57206671
Binary files /dev/null and b/assets/img/favicon/border/favicon-16x16.png differ
diff --git a/assets/img/favicon/border/favicon-32x32.png b/assets/img/favicon/border/favicon-32x32.png
new file mode 100644
index 00000000..71dfc35c
Binary files /dev/null and b/assets/img/favicon/border/favicon-32x32.png differ
diff --git a/assets/img/favicon/border/favicon.ico b/assets/img/favicon/border/favicon.ico
new file mode 100644
index 00000000..afc5cac9
Binary files /dev/null and b/assets/img/favicon/border/favicon.ico differ
diff --git a/assets/img/favicon/border/mstile-150x150.png b/assets/img/favicon/border/mstile-150x150.png
new file mode 100644
index 00000000..4626b985
Binary files /dev/null and b/assets/img/favicon/border/mstile-150x150.png differ
diff --git a/assets/img/favicon/border/safari-pinned-tab.svg b/assets/img/favicon/border/safari-pinned-tab.svg
new file mode 100644
index 00000000..3cff570e
--- /dev/null
+++ b/assets/img/favicon/border/safari-pinned-tab.svg
@@ -0,0 +1,28 @@
+
+
+
diff --git a/assets/img/favicon/border/site.webmanifest b/assets/img/favicon/border/site.webmanifest
new file mode 100644
index 00000000..fb7aee98
--- /dev/null
+++ b/assets/img/favicon/border/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "",
+ "short_name": "",
+ "icons": [
+ {
+ "src": "/img/favicon/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/img/favicon/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#ff6c88",
+ "background_color": "#ff6c88",
+ "display": "standalone"
+}
diff --git a/assets/img/favicon/favicon.png b/assets/img/favicon/favicon.png
new file mode 100644
index 00000000..9cb66580
Binary files /dev/null and b/assets/img/favicon/favicon.png differ
diff --git a/assets/img/favicon/favicon.svg b/assets/img/favicon/favicon.svg
new file mode 100644
index 00000000..76cf9c77
--- /dev/null
+++ b/assets/img/favicon/favicon.svg
@@ -0,0 +1,75 @@
+
+
diff --git a/assets/img/favicon/favicon_border.png b/assets/img/favicon/favicon_border.png
new file mode 100644
index 00000000..4d91f9b7
Binary files /dev/null and b/assets/img/favicon/favicon_border.png differ
diff --git a/public/img/favicon/favicon-16x16.ico b/assets/img/favicon/old/favicon-16x16.ico
similarity index 100%
rename from public/img/favicon/favicon-16x16.ico
rename to assets/img/favicon/old/favicon-16x16.ico
diff --git a/public/img/favicon/favicon-32x32.ico b/assets/img/favicon/old/favicon-32x32.ico
similarity index 100%
rename from public/img/favicon/favicon-32x32.ico
rename to assets/img/favicon/old/favicon-32x32.ico
diff --git a/public/img/favicon/favicon-64x64.ico b/assets/img/favicon/old/favicon-64x64.ico
similarity index 100%
rename from public/img/favicon/favicon-64x64.ico
rename to assets/img/favicon/old/favicon-64x64.ico
diff --git a/public/img/favicon/favicon-64x64.png b/assets/img/favicon/old/favicon-64x64.png
similarity index 100%
rename from public/img/favicon/favicon-64x64.png
rename to assets/img/favicon/old/favicon-64x64.png
diff --git a/public/img/favicon/favicon-dark-16x16.ico b/assets/img/favicon/old/favicon-dark-16x16.ico
similarity index 100%
rename from public/img/favicon/favicon-dark-16x16.ico
rename to assets/img/favicon/old/favicon-dark-16x16.ico
diff --git a/public/img/favicon/favicon-dark-32x32.ico b/assets/img/favicon/old/favicon-dark-32x32.ico
similarity index 100%
rename from public/img/favicon/favicon-dark-32x32.ico
rename to assets/img/favicon/old/favicon-dark-32x32.ico
diff --git a/public/img/favicon/favicon-dark-64x64.ico b/assets/img/favicon/old/favicon-dark-64x64.ico
similarity index 100%
rename from public/img/favicon/favicon-dark-64x64.ico
rename to assets/img/favicon/old/favicon-dark-64x64.ico
diff --git a/public/img/favicon/favicon.png b/assets/img/favicon/old/favicon.png
similarity index 100%
rename from public/img/favicon/favicon.png
rename to assets/img/favicon/old/favicon.png
diff --git a/assets/img/logo.svg b/assets/img/logo.svg
index 0def5f49..2384a4e1 100644
--- a/assets/img/logo.svg
+++ b/assets/img/logo.svg
@@ -1,12 +1,95 @@
-
diff --git a/assets/img/logo_old.svg b/assets/img/logo_old.svg
new file mode 100644
index 00000000..0def5f49
--- /dev/null
+++ b/assets/img/logo_old.svg
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/assets/index.ejs b/assets/index.ejs
index 94a2d421..df4dd18f 100644
--- a/assets/index.ejs
+++ b/assets/index.ejs
@@ -3,15 +3,20 @@
-
+
traxxx
-
-
-
+
+
+
+
+
+
+
+
diff --git a/assets/js/actors/actions.js b/assets/js/actors/actions.js
index 1be909ab..0a26b4bb 100644
--- a/assets/js/actors/actions.js
+++ b/assets/js/actors/actions.js
@@ -80,7 +80,7 @@ function initActorActions(store, router) {
lazy
hash
comment
- copyright
+ credit
sfw: sfwMedia {
id
thumbnail
@@ -111,7 +111,7 @@ function initActorActions(store, router) {
lazy
hash
comment
- copyright
+ credit
sfw: sfwMedia {
id
thumbnail
@@ -314,7 +314,7 @@ function initActorActions(store, router) {
thumbnail
lazy
comment
- copyright
+ credit
sfw: sfwMedia {
id
thumbnail
diff --git a/migrations/20190325001339_releases.js b/migrations/20190325001339_releases.js
index 33fe19f1..86478470 100644
--- a/migrations/20190325001339_releases.js
+++ b/migrations/20190325001339_releases.js
@@ -621,14 +621,14 @@ exports.up = knex => Promise.resolve()
table.text('title');
table.text('slug');
- table.date('date');
+ table.timestamp('date');
table.index('date');
+ table.date('production_date');
+
table.enum('date_precision', ['year', 'month', 'day', 'hour', 'minute', 'second'])
.defaultTo('day');
- table.date('production_date');
-
table.text('description');
table.integer('duration')
diff --git a/package-lock.json b/package-lock.json
index 2f9e70b5..0c4cb4c2 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1490,21 +1490,22 @@
"acorn": {
"version": "7.1.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
- "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ=="
+ "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==",
+ "dev": true
},
"acorn-globals": {
- "version": "4.3.4",
- "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz",
- "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==",
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz",
+ "integrity": "sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==",
"requires": {
- "acorn": "^6.0.1",
- "acorn-walk": "^6.0.1"
+ "acorn": "^7.1.1",
+ "acorn-walk": "^7.1.1"
},
"dependencies": {
"acorn": {
- "version": "6.4.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.0.tgz",
- "integrity": "sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw=="
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
+ "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA=="
}
}
},
@@ -1515,9 +1516,9 @@
"dev": true
},
"acorn-walk": {
- "version": "6.2.0",
- "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz",
- "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA=="
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
+ "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA=="
},
"adm-zip": {
"version": "0.4.14",
@@ -1654,11 +1655,6 @@
"resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
"integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8="
},
- "array-equal": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz",
- "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM="
- },
"array-find-index": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
@@ -2211,9 +2207,9 @@
"dev": true
},
"browser-process-hrtime": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz",
- "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw=="
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz",
+ "integrity": "sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow=="
},
"browserify-aes": {
"version": "1.2.0",
@@ -3111,9 +3107,9 @@
"integrity": "sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw=="
},
"cssstyle": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.2.0.tgz",
- "integrity": "sha512-sEb3XFPx3jNnCAMtqrXPDeSgQr+jojtCeNf8cvMNMh1cG970+lljssvQDzPq6lmmJu2Vhqood/gtEomBiHOGnA==",
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz",
+ "integrity": "sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==",
"requires": {
"cssom": "~0.3.6"
},
@@ -3181,13 +3177,13 @@
}
},
"data-urls": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz",
- "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz",
+ "integrity": "sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==",
"requires": {
- "abab": "^2.0.0",
- "whatwg-mimetype": "^2.2.0",
- "whatwg-url": "^7.0.0"
+ "abab": "^2.0.3",
+ "whatwg-mimetype": "^2.3.0",
+ "whatwg-url": "^8.0.0"
}
},
"dayjs": {
@@ -3214,6 +3210,11 @@
"resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
"integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
},
+ "decimal.js": {
+ "version": "10.2.0",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz",
+ "integrity": "sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw=="
+ },
"decode-uri-component": {
"version": "0.2.0",
"resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
@@ -3386,11 +3387,18 @@
"integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w=="
},
"domexception": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz",
- "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz",
+ "integrity": "sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==",
"requires": {
- "webidl-conversions": "^4.0.2"
+ "webidl-conversions": "^5.0.0"
+ },
+ "dependencies": {
+ "webidl-conversions": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+ "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
+ }
}
},
"domhandler": {
@@ -3635,9 +3643,9 @@
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
},
"escodegen": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.1.tgz",
- "integrity": "sha512-Bmt7NcRySdIfNPfU2ZoXDrrXsG9ZjvDxcAlMfDUgRBjLOWTuIACXPBFJH7Z+cLb40JeQco5toikyc9t9P8E9SQ==",
+ "version": "1.14.3",
+ "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz",
+ "integrity": "sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw==",
"requires": {
"esprima": "^4.0.1",
"estraverse": "^4.2.0",
@@ -5761,11 +5769,11 @@
"dev": true
},
"html-encoding-sniffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz",
- "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==",
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz",
+ "integrity": "sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==",
"requires": {
- "whatwg-encoding": "^1.0.1"
+ "whatwg-encoding": "^1.0.5"
}
},
"htmlparser2": {
@@ -6273,6 +6281,11 @@
"isobject": "^3.0.1"
}
},
+ "is-potential-custom-element-name": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz",
+ "integrity": "sha1-DFLlS8yjkbssSUsh6GJtczbG45c="
+ },
"is-promise": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-promise/-/is-promise-2.1.0.tgz",
@@ -6408,42 +6421,47 @@
"integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
},
"jsdom": {
- "version": "15.2.1",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-15.2.1.tgz",
- "integrity": "sha512-fAl1W0/7T2G5vURSyxBzrJ1LSdQn6Tr5UX/xD4PXDx/PDgwygedfW6El/KIj3xJ7FU61TTYnc/l/B7P49Eqt6g==",
+ "version": "16.3.0",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-16.3.0.tgz",
+ "integrity": "sha512-zggeX5UuEknpdZzv15+MS1dPYG0J/TftiiNunOeNxSl3qr8Z6cIlQpN0IdJa44z9aFxZRIVqRncvEhQ7X5DtZg==",
"requires": {
- "abab": "^2.0.0",
- "acorn": "^7.1.0",
- "acorn-globals": "^4.3.2",
- "array-equal": "^1.0.0",
- "cssom": "^0.4.1",
- "cssstyle": "^2.0.0",
- "data-urls": "^1.1.0",
- "domexception": "^1.0.1",
- "escodegen": "^1.11.1",
- "html-encoding-sniffer": "^1.0.2",
+ "abab": "^2.0.3",
+ "acorn": "^7.1.1",
+ "acorn-globals": "^6.0.0",
+ "cssom": "^0.4.4",
+ "cssstyle": "^2.2.0",
+ "data-urls": "^2.0.0",
+ "decimal.js": "^10.2.0",
+ "domexception": "^2.0.1",
+ "escodegen": "^1.14.1",
+ "html-encoding-sniffer": "^2.0.1",
+ "is-potential-custom-element-name": "^1.0.0",
"nwsapi": "^2.2.0",
- "parse5": "5.1.0",
- "pn": "^1.1.0",
- "request": "^2.88.0",
- "request-promise-native": "^1.0.7",
- "saxes": "^3.1.9",
- "symbol-tree": "^3.2.2",
+ "parse5": "5.1.1",
+ "request": "^2.88.2",
+ "request-promise-native": "^1.0.8",
+ "saxes": "^5.0.0",
+ "symbol-tree": "^3.2.4",
"tough-cookie": "^3.0.1",
- "w3c-hr-time": "^1.0.1",
- "w3c-xmlserializer": "^1.1.2",
- "webidl-conversions": "^4.0.2",
+ "w3c-hr-time": "^1.0.2",
+ "w3c-xmlserializer": "^2.0.0",
+ "webidl-conversions": "^6.1.0",
"whatwg-encoding": "^1.0.5",
"whatwg-mimetype": "^2.3.0",
- "whatwg-url": "^7.0.0",
- "ws": "^7.0.0",
+ "whatwg-url": "^8.0.0",
+ "ws": "^7.2.3",
"xml-name-validator": "^3.0.0"
},
"dependencies": {
+ "acorn": {
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz",
+ "integrity": "sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA=="
+ },
"parse5": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.0.tgz",
- "integrity": "sha512-fxNG2sQjHvlVAYmzBZS9YlDp6PTSSDwa98vkD4QgVDDCAo84z5X1t5XyJQ62ImdLXx5NdIIfihey6xpum9/gRQ=="
+ "version": "5.1.1",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz",
+ "integrity": "sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug=="
}
}
},
@@ -8331,11 +8349,6 @@
"resolved": "https://registry.npmjs.org/pluralize/-/pluralize-7.0.0.tgz",
"integrity": "sha512-ARhBOdzS3e41FbkW/XWrTEtukqqLoK5+Z/4UeDaLuSW+39JPeFgs4gCGqsrJHVZX0fUrx//4OF0K1CUGwlIFow=="
},
- "pn": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz",
- "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA=="
- },
"popper.js": {
"version": "1.16.1",
"resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz",
@@ -9561,11 +9574,11 @@
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
},
"saxes": {
- "version": "3.1.11",
- "resolved": "https://registry.npmjs.org/saxes/-/saxes-3.1.11.tgz",
- "integrity": "sha512-Ydydq3zC+WYDJK1+gRxRapLIED9PWeSuuS41wqyoRmzvhhh9nc+QQrVMKJYzJFULazeGhzSV0QleN2wD3boh2g==",
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz",
+ "integrity": "sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==",
"requires": {
- "xmlchars": "^2.1.1"
+ "xmlchars": "^2.2.0"
}
},
"scheduler": {
@@ -10946,11 +10959,11 @@
}
},
"tr46": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz",
- "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=",
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-2.0.2.tgz",
+ "integrity": "sha512-3n1qG+/5kg+jrbTzwAykB5yRYtQCTqOGKq5U5PE3b0a1/mzo6snDhjGS0zJVJunO0NrT3Dg1MLy5TjWP/UJppg==",
"requires": {
- "punycode": "^2.1.0"
+ "punycode": "^2.1.1"
}
},
"traverse": {
@@ -11560,20 +11573,18 @@
"integrity": "sha512-ha3jNLJqNhhrAemDXcmMJMKf1Zu4sybMPr9KxJIuOpVcsDQlTBYLLladav2U+g1AvdYDG5Gs0xBTb0M5pXXYFQ=="
},
"w3c-hr-time": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz",
- "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=",
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz",
+ "integrity": "sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==",
"requires": {
- "browser-process-hrtime": "^0.1.2"
+ "browser-process-hrtime": "^1.0.0"
}
},
"w3c-xmlserializer": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-1.1.2.tgz",
- "integrity": "sha512-p10l/ayESzrBMYWRID6xbuCKh2Fp77+sA0doRuGn4tTIMrrZVeqfpKjXHY+oDh3K4nLdPgNwMTVP6Vp4pvqbNg==",
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz",
+ "integrity": "sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==",
"requires": {
- "domexception": "^1.0.1",
- "webidl-conversions": "^4.0.2",
"xml-name-validator": "^3.0.0"
}
},
@@ -11597,9 +11608,9 @@
}
},
"webidl-conversions": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz",
- "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg=="
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz",
+ "integrity": "sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w=="
},
"webpack": {
"version": "4.41.6",
@@ -11847,13 +11858,20 @@
"integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g=="
},
"whatwg-url": {
- "version": "7.1.0",
- "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz",
- "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==",
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.1.0.tgz",
+ "integrity": "sha512-vEIkwNi9Hqt4TV9RdnaBPNt+E2Sgmo3gePebCRgZ1R7g6d23+53zCTnuB0amKI4AXq6VM8jj2DUAa0S1vjJxkw==",
"requires": {
"lodash.sortby": "^4.7.0",
- "tr46": "^1.0.1",
- "webidl-conversions": "^4.0.2"
+ "tr46": "^2.0.2",
+ "webidl-conversions": "^5.0.0"
+ },
+ "dependencies": {
+ "webidl-conversions": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz",
+ "integrity": "sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA=="
+ }
}
},
"which": {
@@ -11999,9 +12017,9 @@
}
},
"ws": {
- "version": "7.2.1",
- "resolved": "https://registry.npmjs.org/ws/-/ws-7.2.1.tgz",
- "integrity": "sha512-sucePNSafamSKoOqoNfBd8V0StlkzJKL2ZAhGQinCfNQ+oacw+Pk7lcdAElecBF2VkLNZRiIb5Oi1Q5lVUVt2A=="
+ "version": "7.3.1",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
+ "integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
},
"xml-name-validator": {
"version": "3.0.0",
diff --git a/package.json b/package.json
index eb322380..5831cfca 100644
--- a/package.json
+++ b/package.json
@@ -94,7 +94,7 @@
"fs-extra": "^7.0.1",
"graphile-utils": "^4.5.6",
"iconv-lite": "^0.5.1",
- "jsdom": "^15.2.1",
+ "jsdom": "^16.3.0",
"knex": "^0.20.10",
"knex-migrate": "^1.7.4",
"longjohn": "^0.2.12",
diff --git a/public/img/favicon/android-chrome-192x192.png b/public/img/favicon/android-chrome-192x192.png
new file mode 100644
index 00000000..21cfdffb
Binary files /dev/null and b/public/img/favicon/android-chrome-192x192.png differ
diff --git a/public/img/favicon/android-chrome-512x512.png b/public/img/favicon/android-chrome-512x512.png
new file mode 100644
index 00000000..314d1bda
Binary files /dev/null and b/public/img/favicon/android-chrome-512x512.png differ
diff --git a/public/img/favicon/apple-touch-icon.png b/public/img/favicon/apple-touch-icon.png
new file mode 100644
index 00000000..5cea8b44
Binary files /dev/null and b/public/img/favicon/apple-touch-icon.png differ
diff --git a/public/img/favicon/browserconfig.xml b/public/img/favicon/browserconfig.xml
new file mode 100644
index 00000000..50c09863
--- /dev/null
+++ b/public/img/favicon/browserconfig.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+ #ff6c88
+
+
+
diff --git a/public/img/favicon/favicon-16x16.png b/public/img/favicon/favicon-16x16.png
new file mode 100644
index 00000000..cb9a2ad2
Binary files /dev/null and b/public/img/favicon/favicon-16x16.png differ
diff --git a/public/img/favicon/favicon-32x32.png b/public/img/favicon/favicon-32x32.png
new file mode 100644
index 00000000..73f82de6
Binary files /dev/null and b/public/img/favicon/favicon-32x32.png differ
diff --git a/public/img/favicon/favicon.ico b/public/img/favicon/favicon.ico
new file mode 100644
index 00000000..7fbb90b7
Binary files /dev/null and b/public/img/favicon/favicon.ico differ
diff --git a/public/img/favicon/mstile-150x150.png b/public/img/favicon/mstile-150x150.png
new file mode 100644
index 00000000..08ae5704
Binary files /dev/null and b/public/img/favicon/mstile-150x150.png differ
diff --git a/public/img/favicon/safari-pinned-tab.svg b/public/img/favicon/safari-pinned-tab.svg
new file mode 100644
index 00000000..5f5a3689
--- /dev/null
+++ b/public/img/favicon/safari-pinned-tab.svg
@@ -0,0 +1,48 @@
+
+
+
+
+Created by potrace 1.11, written by Peter Selinger 2001-2013
+
+
+
+
+
diff --git a/public/img/favicon/site.webmanifest b/public/img/favicon/site.webmanifest
new file mode 100644
index 00000000..ed370de3
--- /dev/null
+++ b/public/img/favicon/site.webmanifest
@@ -0,0 +1,19 @@
+{
+ "name": "traxxx",
+ "short_name": "traxxx",
+ "icons": [
+ {
+ "src": "/img/favicon/android-chrome-192x192.png",
+ "sizes": "192x192",
+ "type": "image/png"
+ },
+ {
+ "src": "/img/favicon/android-chrome-512x512.png",
+ "sizes": "512x512",
+ "type": "image/png"
+ }
+ ],
+ "theme_color": "#ffffff",
+ "background_color": "#ffffff",
+ "display": "standalone"
+}
diff --git a/public/img/logos/elegantangel/elegantangel.png b/public/img/logos/elegantangel/elegantangel.png
new file mode 100644
index 00000000..46e594d1
Binary files /dev/null and b/public/img/logos/elegantangel/elegantangel.png differ
diff --git a/public/img/logos/elegantangel/network.png b/public/img/logos/elegantangel/network.png
new file mode 100644
index 00000000..46e594d1
Binary files /dev/null and b/public/img/logos/elegantangel/network.png differ
diff --git a/public/img/logos/mikeadriano/lazy/allanal.png b/public/img/logos/mikeadriano/lazy/allanal.png
index 9bfc7ee2..c3363527 100644
Binary files a/public/img/logos/mikeadriano/lazy/allanal.png and b/public/img/logos/mikeadriano/lazy/allanal.png differ
diff --git a/public/img/logos/mikeadriano/lazy/favicon.png b/public/img/logos/mikeadriano/lazy/favicon.png
index 2e58f81f..1958930d 100644
Binary files a/public/img/logos/mikeadriano/lazy/favicon.png and b/public/img/logos/mikeadriano/lazy/favicon.png differ
diff --git a/public/img/logos/mikeadriano/lazy/network.png b/public/img/logos/mikeadriano/lazy/network.png
index 9eecf599..1ee18ec9 100644
Binary files a/public/img/logos/mikeadriano/lazy/network.png and b/public/img/logos/mikeadriano/lazy/network.png differ
diff --git a/public/img/logos/mikeadriano/lazy/nympho.png b/public/img/logos/mikeadriano/lazy/nympho.png
index 343b226a..aa8bd79c 100644
Binary files a/public/img/logos/mikeadriano/lazy/nympho.png and b/public/img/logos/mikeadriano/lazy/nympho.png differ
diff --git a/public/img/logos/mikeadriano/lazy/swallowed.png b/public/img/logos/mikeadriano/lazy/swallowed.png
index b503bf05..84bbf963 100644
Binary files a/public/img/logos/mikeadriano/lazy/swallowed.png and b/public/img/logos/mikeadriano/lazy/swallowed.png differ
diff --git a/public/img/logos/mikeadriano/lazy/trueanal.png b/public/img/logos/mikeadriano/lazy/trueanal.png
index 7aa57757..933f2e07 100644
Binary files a/public/img/logos/mikeadriano/lazy/trueanal.png and b/public/img/logos/mikeadriano/lazy/trueanal.png differ
diff --git a/public/img/logos/mikeadriano/misc/mike-adriano_2.png b/public/img/logos/mikeadriano/misc/mike-adriano_2.png
new file mode 100644
index 00000000..f806e8f6
Binary files /dev/null and b/public/img/logos/mikeadriano/misc/mike-adriano_2.png differ
diff --git a/public/img/logos/mikeadriano/network.png b/public/img/logos/mikeadriano/network.png
index f806e8f6..89f89b9c 100644
Binary files a/public/img/logos/mikeadriano/network.png and b/public/img/logos/mikeadriano/network.png differ
diff --git a/public/img/logos/mikeadriano/thumbs/allanal.png b/public/img/logos/mikeadriano/thumbs/allanal.png
index a5b31fba..3d513cb1 100644
Binary files a/public/img/logos/mikeadriano/thumbs/allanal.png and b/public/img/logos/mikeadriano/thumbs/allanal.png differ
diff --git a/public/img/logos/mikeadriano/thumbs/favicon.png b/public/img/logos/mikeadriano/thumbs/favicon.png
index 2e58f81f..1958930d 100644
Binary files a/public/img/logos/mikeadriano/thumbs/favicon.png and b/public/img/logos/mikeadriano/thumbs/favicon.png differ
diff --git a/public/img/logos/mikeadriano/thumbs/network.png b/public/img/logos/mikeadriano/thumbs/network.png
index d0c32e62..4589a111 100644
Binary files a/public/img/logos/mikeadriano/thumbs/network.png and b/public/img/logos/mikeadriano/thumbs/network.png differ
diff --git a/public/img/logos/mikeadriano/thumbs/nympho.png b/public/img/logos/mikeadriano/thumbs/nympho.png
index e7393fe1..2884107a 100644
Binary files a/public/img/logos/mikeadriano/thumbs/nympho.png and b/public/img/logos/mikeadriano/thumbs/nympho.png differ
diff --git a/public/img/logos/mikeadriano/thumbs/swallowed.png b/public/img/logos/mikeadriano/thumbs/swallowed.png
index a0bce4d2..f8ec87b0 100644
Binary files a/public/img/logos/mikeadriano/thumbs/swallowed.png and b/public/img/logos/mikeadriano/thumbs/swallowed.png differ
diff --git a/public/img/logos/mikeadriano/thumbs/trueanal.png b/public/img/logos/mikeadriano/thumbs/trueanal.png
index 0a8a97c0..05735bd7 100644
Binary files a/public/img/logos/mikeadriano/thumbs/trueanal.png and b/public/img/logos/mikeadriano/thumbs/trueanal.png differ
diff --git a/seeds/01_networks.js b/seeds/01_networks.js
index 708df9e3..e26f5d7d 100644
--- a/seeds/01_networks.js
+++ b/seeds/01_networks.js
@@ -305,8 +305,7 @@ const networks = [
{
slug: 'mikeadriano',
name: 'Mike Adriano',
- url: null,
- description: null,
+ url: 'https://www.mikeadriano.com',
},
{
slug: 'milehighmedia',
diff --git a/seeds/02_sites.js b/seeds/02_sites.js
index 8e229c8a..cff532f7 100644
--- a/seeds/02_sites.js
+++ b/seeds/02_sites.js
@@ -1821,6 +1821,12 @@ const sites = [
description: '',
parent: 'dogfartnetwork',
},
+ // ELEGANT ANGEL
+ {
+ slug: 'elegantangel',
+ name: 'Elegant Angel',
+ url: 'https://www.elegantangel.com',
+ },
// EVIL ANGEL
{
slug: 'evilangel',
diff --git a/src/scrapers/killergram.js b/src/scrapers/killergram.js
index ff4b3f82..66cd60ff 100644
--- a/src/scrapers/killergram.js
+++ b/src/scrapers/killergram.js
@@ -68,7 +68,7 @@ async function fetchActorReleases({ query }, url, remainingPages, actorName, acc
return accReleases.concat(releases);
}
-async function scrapeProfile({ query, window }, actorName, url, include) {
+async function scrapeProfile({ query }, actorName, url, include) {
const profile = {};
profile.avatar = {
@@ -85,7 +85,7 @@ async function scrapeProfile({ query, window }, actorName, url, include) {
if (include.releases) {
const availablePages = query.all('.pageboxdropdown option', 'value');
- profile.releases = await fetchActorReleases(qu.init(query.q('#episodes > table'), window), url, availablePages.slice(1), actorName);
+ profile.releases = await fetchActorReleases(qu.init(query.q('#episodes > table')), url, availablePages.slice(1), actorName);
}
return profile;
@@ -105,7 +105,9 @@ async function fetchScene(url, channel) {
async function fetchProfile(actorName, entity, include) {
const url = `http://killergram.com/episodes.asp?page=episodes&model=${encodeURI(actorName)}&ct=model`;
- const res = await qu.get(url, '#content');
+ const res = await qu.get(url, '#content', null, {
+ followRedirects: false,
+ });
return res.ok ? scrapeProfile(res.item, actorName, url, include) : res.status;
}
diff --git a/src/scrapers/mikeadriano.js b/src/scrapers/mikeadriano.js
index cc2d586f..ab201835 100644
--- a/src/scrapers/mikeadriano.js
+++ b/src/scrapers/mikeadriano.js
@@ -1,237 +1,88 @@
'use strict';
-/* eslint-disable newline-per-chained-call */
-const { JSDOM } = require('jsdom');
-const cheerio = require('cheerio');
-const moment = require('moment');
-// const bhttp = require('bhttp');
+const qu = require('../utils/qu');
-const { get } = require('../utils/http');
-
-const descriptionTags = {
- 'anal cream pie': 'anal creampie',
- 'ass to mouth': 'ass to mouth',
- 'cream pie in her ass': 'anal creampie',
- 'eats ass': 'ass eating',
- facial: 'facial',
- gaped: 'gaping',
- gapes: 'gaping',
- gape: 'gaping',
- 'rectal cream pie': 'anal creampie',
- rimming: 'ass eating',
-};
-
-function deriveTagsFromDescription(description) {
- const matches = (description || '').toLowerCase().match(new RegExp(Object.keys(descriptionTags).join('|'), 'g'));
-
- return matches
- ? matches.map(match => descriptionTags[match])
- : [];
-}
-
-async function scrapeLatestA(html, site) {
- const { document } = new JSDOM(html).window;
- const sceneElements = document.querySelectorAll('.content-item-large, .content-item');
-
- return Promise.all(Array.from(sceneElements, async (element) => {
- const $ = cheerio.load(element.innerHTML, { normalizeWhitespace: true });
-
- const titleElement = element.querySelector('h3.title a');
- const title = titleElement.textContent;
- const url = titleElement.href;
- const entryId = url.split('/').slice(-2)[0];
-
- const descriptionElement = element.querySelector('.desc');
- const description = descriptionElement && descriptionElement.textContent.trim();
- const date = moment(element.querySelector('.date, time').textContent, 'Do MMM YYYY').toDate();
-
- const actors = Array.from(element.querySelectorAll('h4.models a'), actorElement => actorElement.textContent);
-
- const durationString = element.querySelector('.total-time').textContent.trim();
- // timestamp is sometimes 00:00, sometimes 0:00:00
- const duration = durationString.split(':').length === 3
- ? moment.duration(durationString).asSeconds()
- : moment.duration(`00:${durationString}`).asSeconds();
-
- const ratingElement = element.querySelector('.rating');
- const stars = ratingElement && ratingElement.dataset.rating;
-
- const [poster, ...primaryPhotos] = Array.from(element.querySelectorAll('img'), imageElement => imageElement.src);
- const secondaryPhotos = $('.thumb-top, .thumb-bottom')
- .map((photoIndex, photoElement) => $(photoElement).css()['background-image'])
- .toArray()
- .map(photoUrl => photoUrl.slice(photoUrl.indexOf('http'), photoUrl.indexOf('.jpg') + 4));
-
- const photos = [...primaryPhotos, ...secondaryPhotos];
- const tags = deriveTagsFromDescription(description);
-
- const scene = {
- url,
- entryId,
- title,
- description,
- actors,
- director: 'Mike Adriano',
- date,
- duration,
- tags,
- poster,
- photos,
- rating: {
- stars,
- },
- site,
- };
-
- return scene;
- }));
-}
-
-async function scrapeLatestB(html) {
- const { document } = new JSDOM(html).window;
- const sceneElements = document.querySelectorAll('.content-border');
-
- return Promise.all(Array.from(sceneElements, async (element) => {
- const $ = cheerio.load(element.innerHTML, { normalizeWhitespace: true });
+async function scrapeAll(scenes) {
+ return scenes.map(({ query }) => {
const release = {
director: 'Mike Adriano',
};
- const titleElement = element.querySelector('.content-title-wrap a');
- release.title = titleElement.title || titleElement.textContent.trim();
- release.url = titleElement.href;
- release.entryId = release.url.split('/').slice(-2)[0];
+ release.title = query.cnt('h3.title a, .content-title-wrap a');
+ release.url = query.url('h3.title a, .content-title-wrap a');
+ release.entryId = new URL(release.url).pathname.match(/\/view\/(\d+)/)[1];
- release.description = element.querySelector('.content-description').textContent.trim();
- release.date = (moment(element.querySelector('.mobile-date').textContent, 'MM/DD/YYYY')
- || moment(element.querySelector('.date').textContent, 'Do MMM YYYY')).toDate();
- release.actors = Array.from(element.querySelectorAll('.content-models a'), actorElement => actorElement.textContent);
+ release.description = query.cnt('.desc, .content-description');
+ release.date = query.date('.date, time, .hide', 'Do MMM YYYY');
- const durationString = element.querySelector('.total-time').textContent.trim();
- // timestamp is somethines 00:00, sometimes 0:00:00
- release.duration = durationString.split(':').length === 3
- ? moment.duration(durationString).asSeconds()
- : moment.duration(`00:${durationString}`).asSeconds();
+ release.actors = query.cnts('h4.models a, .content-models a');
+ release.duration = query.dur('.total-time');
- const [poster, ...primaryPhotos] = Array.from(element.querySelectorAll('a img'), imageElement => imageElement.src);
- const secondaryPhotos = $('.thumb-mouseover')
- .map((photoIndex, photoElement) => $(photoElement).css()['background-image'])
- .toArray()
- .map(photoUrl => photoUrl.slice(photoUrl.indexOf('http'), photoUrl.indexOf('.jpg') + 4));
+ const [poster, ...primaryPhotos] = query.imgs('a img');
+ const secondaryPhotos = query.styles('.thumb-top, .thumb-bottom, .thumb-mouseover', 'background-image').map(style => style.match(/url\((.*)\)/)[1]);
release.poster = poster;
- release.photos = [...primaryPhotos, ...secondaryPhotos];
+ release.photos = primaryPhotos.concat(secondaryPhotos);
- release.tags = deriveTagsFromDescription(release.description);
return release;
- }));
+ });
}
-async function scrapeSceneA(html, url) {
- const { document } = new JSDOM(html).window;
- const element = document.querySelector('.content-page-info');
- const release = {
- url,
- director: 'Mike Adriano',
- };
+function scrapeScene({ query }, url) {
+ const release = { director: 'Mike Adriano' };
- release.entryId = url.split('/').slice(-2)[0];
- release.title = element.querySelector('.title').textContent.trim();
- release.description = element.querySelector('.desc').textContent.trim();
- release.date = moment(element.querySelector('.post-date').textContent.trim(), 'Do MMM YYYY').toDate();
+ if (query.exists('a[href*="stackpath.com"]')) {
+ throw new Error('URL blocked by StackPath');
+ }
- release.actors = Array.from(element.querySelectorAll('.models a'), actorElement => actorElement.textContent);
+ release.entryId = new URL(url).pathname.match(/\/view\/(\d+)/)[1];
- const durationString = element.querySelector('.total-time').textContent.trim();
- // timestamp is sometimes 00:00, sometimes 0:00:00
- release.duration = durationString.split(':').length === 3
- ? moment.duration(durationString).asSeconds()
- : moment.duration(`00:${durationString}`).asSeconds();
+ release.title = query.cnt('.content-page-info .title');
+ release.description = query.cnt('.content-page-info .desc');
+ release.date = query.date('.content-page-info .date, .content-page-info .hide', 'Do MMM YYYY');
- const { poster } = document.querySelector('.content-page-header video');
- const { src, type } = document.querySelector('.content-page-header source');
+ release.actors = query.cnts('.content-page-info .models a');
+ release.duration = query.dur('.content-page-info .total-time:last-child');
- release.poster = poster;
- release.trailer = { src, type };
+ release.poster = query.poster('.content-page-header video, .content-page-header-inner video');
- release.tags = deriveTagsFromDescription(release.description);
+ const trailerEl = query.q('.content-page-header source, .content-page-header-inner source');
+
+ if (trailerEl) {
+ release.trailer = {
+ src: trailerEl.src,
+ type: trailerEl.type,
+ };
+ }
return release;
}
-async function scrapeSceneB(html, url, site) {
- const { document } = new JSDOM(html).window;
- const element = document.querySelector('.content-page-info');
-
- const entryId = url.split('/').slice(-2)[0];
- const title = element.querySelector('.title').textContent.trim();
- const description = element.querySelector('.desc').textContent.trim();
- const date = moment(element.querySelector('.date').textContent.trim(), 'Do MMM YYYY').toDate();
-
- const actors = Array.from(element.querySelectorAll('.models a'), actorElement => actorElement.textContent);
-
- const durationString = element.querySelector('.total-time').textContent.trim();
- // timestamp is somethines 00:00, sometimes 0:00:00
- const duration = durationString.split(':').length === 3
- ? moment.duration(durationString).asSeconds()
- : moment.duration(`00:${durationString}`).asSeconds();
-
- const { poster } = document.querySelector('.content-page-header-inner video');
- const { src, type } = document.querySelector('.content-page-header-inner source');
-
- const tags = deriveTagsFromDescription(description);
-
- const scene = {
- url,
- entryId,
- title,
- description,
- actors,
- director: 'Mike Adriano',
- date,
- duration,
- tags,
- poster,
- trailer: {
- src,
- type,
- },
- site,
- };
-
- return scene;
-}
-
-async function fetchLatest(site, page = 1) {
- const { host } = new URL(site.url);
+async function fetchLatest(channel, page = 1) {
+ const { host } = new URL(channel.url);
const url = `https://tour.${host}/videos?page=${page}`;
- const res = await get(url);
+ const res = await qu.get(url);
- if (res.code === 200) {
- if (host === 'trueanal.com' || host === 'swallowed.com') {
- return scrapeLatestA(res.html, site);
+ if (res.ok) {
+ if (res.item.query.exists('a[href*="stackpath.com"]')) {
+ throw new Error('URL blocked by StackPath');
}
- return scrapeLatestB(res.html, site);
+ return scrapeAll(qu.initAll(res.item.el, '.content-item-large, .content-item, .content-border'), channel);
}
- return res.code;
+ return res.status;
}
-async function fetchScene(url, site) {
- const { host } = new URL(site.url);
- const res = await get(url);
+async function fetchScene(url, channel) {
+ const res = await qu.get(url);
- if (res.code === 200) {
- if (host === 'trueanal.com' || host === 'swallowed.com') {
- return scrapeSceneA(res.body.toString(), url, site);
- }
-
- return scrapeSceneB(res.body.toString(), url, site);
+ if (res.ok) {
+ return scrapeScene(res.item, url, channel);
}
- return res.code;
+ return res.status;
}
/* API protected
diff --git a/src/scrapers/vixen.js b/src/scrapers/vixen.js
index 71df674c..f9d2a736 100644
--- a/src/scrapers/vixen.js
+++ b/src/scrapers/vixen.js
@@ -78,7 +78,7 @@ function scrapeAll(scenes, site, origin) {
release.url = `${site?.url || origin}${scene.targetUrl}`;
release.date = moment.utc(scene.releaseDate).toDate();
- release.shootDate = moment.utc(scene.shootDate).toDate();
+ release.datePrecision = 'minute';
release.actors = scene.models;
release.stars = Number(scene.textRating) / 2;
@@ -104,7 +104,7 @@ function scrapeUpcoming(scene, site) {
release.url = `${site.url}${scene.targetUrl}`;
release.date = moment.utc(scene.releaseDate).toDate();
- release.shootDate = moment.utc(scene.shootDate).toDate();
+ release.datePrecision = 'minute';
release.actors = scene.models;
@@ -133,7 +133,8 @@ async function scrapeScene(data, url, site, baseRelease) {
release.entryId = scene.newId;
release.date = moment.utc(scene.releaseDate).toDate();
- release.shootDate = moment.utc(scene.shootDate).toDate();
+ release.productionDate = moment.utc(scene.shootDate).toDate();
+ release.datePrecision = 'minute';
release.actors = baseRelease?.actors || scene.models;
diff --git a/src/store-releases.js b/src/store-releases.js
index dcba2b00..cbc08192 100644
--- a/src/store-releases.js
+++ b/src/store-releases.js
@@ -31,6 +31,7 @@ function curateReleaseEntry(release, batchId, existingRelease) {
shoot_id: release.shootId || null,
url: release.url,
date: Number(release.date) ? release.date : null,
+ production_date: Number(release.productionDate) ? release.productionDate : null,
date_precision: release.datePrecision,
slug,
description: release.description,
diff --git a/src/utils/jsdom-url.js b/src/utils/jsdom-url.js
new file mode 100644
index 00000000..85b05108
--- /dev/null
+++ b/src/utils/jsdom-url.js
@@ -0,0 +1,17 @@
+'use strict';
+
+const { JSDOM } = require('jsdom');
+
+const el = new JSDOM(`
+
+
+
+
+
+`).window.document;
+
+console.log(el.querySelector('#url').style.backgroundImage);
+console.log(el.querySelector('#urlQuotes').style.backgroundImage);
+console.log(el.querySelector('#color').style.color);
+console.log(el.querySelector('#urlSpaces').style.backgroundImage);
+console.log(el.querySelector('#colorSpaces').style.color);
diff --git a/src/utils/qu.js b/src/utils/qu.js
index f25a0944..5d8058bd 100644
--- a/src/utils/qu.js
+++ b/src/utils/qu.js
@@ -4,9 +4,11 @@ const { JSDOM } = require('jsdom');
const moment = require('moment');
const http = require('./http');
+const { window: globalWindow } = new JSDOM('');
+
function trim(str) {
if (typeof str !== 'string') {
- return null;
+ return str;
}
return str.trim().replace(/\s+/g, ' ');
@@ -55,9 +57,9 @@ function q(context, selector, attrArg, applyTrim = true) {
if (attr) {
const value = selector
? context.querySelector(selector)?.[attr] || context.querySelector(selector)?.attributes[attr]?.value
- : context[attr] || context.attributes[attr]?.value;
+ : context[attr] || context.getAttribute(attr);
- return applyTrim && value ? trim(value) : value;
+ return applyTrim && typeof value === 'string' ? trim(value) : value;
}
return selector ? context.querySelector(selector) : context;
@@ -77,6 +79,14 @@ function exists(context, selector) {
return !!q(context, selector);
}
+function content(context, selector, applyTrim = true) {
+ return q(context, selector, 'textContent', applyTrim);
+}
+
+function contents(context, selector, applyTrim) {
+ return all(context, selector, 'textContent', applyTrim);
+}
+
function html(context, selector) {
const el = q(context, selector, null, true);
@@ -103,6 +113,33 @@ function text(context, selector, applyTrim = true) {
return applyTrim ? trim(textValue) : textValue;
}
+function removeStyleFunctionSpaces(el) {
+ // jsdom appears to have a bug where it ignores inline CSS attributes set to a function() containing spaces, e.g. url( image.png )
+ el.setAttribute('style', el.getAttribute('style').replace(/\(\s+(.*)\s+\)/g, (match, cssArgs) => `(${cssArgs})`));
+}
+
+function style(context, selector, styleAttr) {
+ const el = q(context, selector);
+
+ if (el) {
+ removeStyleFunctionSpaces(el);
+
+ return styleAttr ? el.style[styleAttr] : el.style;
+ }
+
+ return null;
+}
+
+function styles(context, selector, styleAttr) {
+ const elStyles = Array.from(context.querySelectorAll(selector), (el) => {
+ removeStyleFunctionSpaces(el);
+
+ return styleAttr ? el.style[styleAttr] : el.style;
+ });
+
+ return elStyles;
+}
+
function number(context, selector, attr = true) {
const value = q(context, selector, attr);
@@ -236,6 +273,10 @@ const legacyFuncs = {
const quFuncs = {
all,
html,
+ content,
+ contents,
+ cnt: content,
+ cnts: contents,
date,
dur: duration,
duration,
@@ -250,6 +291,8 @@ const quFuncs = {
num: number,
poster,
q,
+ style,
+ styles,
text,
texts,
trailer: video,
@@ -265,7 +308,7 @@ function init(element, window) {
const legacyContextFuncs = Object.entries(legacyFuncs) // dynamically attach methods with context
.reduce((acc, [key, func]) => ({
...acc,
- [key]: (...args) => (window && args[0] instanceof window.HTMLElement // allow for different context
+ [key]: (...args) => (args[0] instanceof globalWindow.HTMLElement // allow for different context
? func(...args)
: func(element, ...args)),
}), {});
@@ -273,7 +316,7 @@ function init(element, window) {
const quContextFuncs = Object.entries(quFuncs) // dynamically attach methods with context
.reduce((acc, [key, func]) => ({
...acc,
- [key]: (...args) => (window && args[0] instanceof window.HTMLElement // allow for different context
+ [key]: (...args) => (args[0] instanceof globalWindow.HTMLElement // allow for different context
? func(...args)
: func(element, ...args)),
}), {});
@@ -319,7 +362,7 @@ function extractAll(htmlValue, selector) {
}
async function get(urlValue, selector, headers, options, queryAll = false) {
- const res = await http.get(urlValue, headers);
+ const res = await http.get(urlValue, headers, options);
if (res.statusCode === 200) {
const item = queryAll