Compare commits
1 Commits
e11dbe19b8
...
6366d6861c
Author | SHA1 | Date | |
---|---|---|---|
6366d6861c |
@@ -9,11 +9,6 @@ const nextConfig = {
|
||||
destination: '/find',
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: '/:langcode(\\w{2})/:slug*',
|
||||
destination: '/:slug*',
|
||||
permanent: true,
|
||||
},
|
||||
];
|
||||
},
|
||||
images: {
|
||||
|
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "libremdb",
|
||||
"version": "4.2.0",
|
||||
"version": "4.1.0",
|
||||
"description": "a free & open source IMDb front-end",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
|
186
pnpm-lock.yaml
generated
186
pnpm-lock.yaml
generated
@@ -18,8 +18,8 @@ importers:
|
||||
specifier: ^5.3.2
|
||||
version: 5.3.2
|
||||
next:
|
||||
specifier: 12.2.5
|
||||
version: 12.2.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.62.1)
|
||||
specifier: 12.3.7
|
||||
version: 12.3.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.62.1)
|
||||
react:
|
||||
specifier: 18.2.0
|
||||
version: 18.2.0
|
||||
@@ -43,8 +43,8 @@ importers:
|
||||
specifier: 8.22.0
|
||||
version: 8.22.0
|
||||
eslint-config-next:
|
||||
specifier: 12.2.5
|
||||
version: 12.2.5(eslint@8.22.0)(typescript@4.7.4)
|
||||
specifier: 12.3.7
|
||||
version: 12.3.7(eslint@8.22.0)(typescript@4.7.4)
|
||||
sass:
|
||||
specifier: ^1.62.1
|
||||
version: 1.62.1
|
||||
@@ -68,12 +68,14 @@ packages:
|
||||
'@humanwhocodes/config-array@0.10.7':
|
||||
resolution: {integrity: sha512-MDl6D6sBsaV452/QSdX+4CXIjZhIcI0PELsxUjk4U828yd58vk3bTIvk/6w5FY+4hIy9sLW0sfrV7K7Kc++j/w==}
|
||||
engines: {node: '>=10.10.0'}
|
||||
deprecated: Use @eslint/config-array instead
|
||||
|
||||
'@humanwhocodes/gitignore-to-minimatch@1.0.2':
|
||||
resolution: {integrity: sha512-rSqmMJDdLFUsyxR6FMtD00nfQKKLFb1kv+qBbOVKqErvloEIJLo5bDTJTQNTYgeyp78JsA7u/NPi5jT1GR/MuA==}
|
||||
|
||||
'@humanwhocodes/object-schema@1.2.1':
|
||||
resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==}
|
||||
deprecated: Use @eslint/object-schema instead
|
||||
|
||||
'@img/sharp-darwin-arm64@0.33.1':
|
||||
resolution: {integrity: sha512-esr2BZ1x0bo+wl7Gx2hjssYhjrhUsD88VQulI0FrG8/otRQUOxLWHMBd1Y1qo2Gfg2KUvXNpT0ASnV9BzJCexw==}
|
||||
@@ -191,86 +193,86 @@ packages:
|
||||
'@ioredis/commands@1.2.0':
|
||||
resolution: {integrity: sha512-Sx1pU8EM64o2BrqNpEO1CNLtKQwyhuXuqyfH7oGKCk+1a33d2r5saW8zNwm3j6BTExtjrv2BxTgzzkMwts6vGg==}
|
||||
|
||||
'@next/env@12.2.5':
|
||||
resolution: {integrity: sha512-vLPLV3cpPGjUPT3PjgRj7e3nio9t6USkuew3JE/jMeon/9Mvp1WyR18v3iwnCuX7eUAm1HmAbJHHLAbcu/EJcw==}
|
||||
'@next/env@12.3.7':
|
||||
resolution: {integrity: sha512-gCw4sTeHoNr0EUO+Nk9Ll21OzF3PnmM0GlHaKgsY2AWQSqQlMgECvB0YI4k21M9iGy+tQ5RMyXQuoIMpzhtxww==}
|
||||
|
||||
'@next/eslint-plugin-next@12.2.5':
|
||||
resolution: {integrity: sha512-VBjVbmqEzGiOTBq4+wpeVXt/KgknnGB6ahvC/AxiIGnN93/RCSyXhFRI4uSfftM2Ba3w7ZO7076bfKasZsA0fw==}
|
||||
'@next/eslint-plugin-next@12.3.7':
|
||||
resolution: {integrity: sha512-L3WEJJBd1CUUsuxSEThheAV5Nh6/mzCagwj4LHaYlANBkW8Hmg8Ne8l/Vx/sPyfyE7FjuKyiNYWbSVpXRvrmaw==}
|
||||
|
||||
'@next/swc-android-arm-eabi@12.2.5':
|
||||
resolution: {integrity: sha512-cPWClKxGhgn2dLWnspW+7psl3MoLQUcNqJqOHk2BhNcou9ARDtC0IjQkKe5qcn9qg7I7U83Gp1yh2aesZfZJMA==}
|
||||
'@next/swc-android-arm-eabi@12.3.4':
|
||||
resolution: {integrity: sha512-cM42Cw6V4Bz/2+j/xIzO8nK/Q3Ly+VSlZJTa1vHzsocJRYz8KT6MrreXaci2++SIZCF1rVRCDgAg5PpqRibdIA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [android]
|
||||
|
||||
'@next/swc-android-arm64@12.2.5':
|
||||
resolution: {integrity: sha512-vMj0efliXmC5b7p+wfcQCX0AfU8IypjkzT64GiKJD9PgiA3IILNiGJr1fw2lyUDHkjeWx/5HMlMEpLnTsQslwg==}
|
||||
'@next/swc-android-arm64@12.3.4':
|
||||
resolution: {integrity: sha512-5jf0dTBjL+rabWjGj3eghpLUxCukRhBcEJgwLedewEA/LJk2HyqCvGIwj5rH+iwmq1llCWbOky2dO3pVljrapg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [android]
|
||||
|
||||
'@next/swc-darwin-arm64@12.2.5':
|
||||
resolution: {integrity: sha512-VOPWbO5EFr6snla/WcxUKtvzGVShfs302TEMOtzYyWni6f9zuOetijJvVh9CCTzInnXAZMtHyNhefijA4HMYLg==}
|
||||
'@next/swc-darwin-arm64@12.3.4':
|
||||
resolution: {integrity: sha512-DqsSTd3FRjQUR6ao0E1e2OlOcrF5br+uegcEGPVonKYJpcr0MJrtYmPxd4v5T6UCJZ+XzydF7eQo5wdGvSZAyA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [darwin]
|
||||
|
||||
'@next/swc-darwin-x64@12.2.5':
|
||||
resolution: {integrity: sha512-5o8bTCgAmtYOgauO/Xd27vW52G2/m3i5PX7MUYePquxXAnX73AAtqA3WgPXBRitEB60plSKZgOTkcpqrsh546A==}
|
||||
'@next/swc-darwin-x64@12.3.4':
|
||||
resolution: {integrity: sha512-PPF7tbWD4k0dJ2EcUSnOsaOJ5rhT3rlEt/3LhZUGiYNL8KvoqczFrETlUx0cUYaXe11dRA3F80Hpt727QIwByQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [darwin]
|
||||
|
||||
'@next/swc-freebsd-x64@12.2.5':
|
||||
resolution: {integrity: sha512-yYUbyup1JnznMtEBRkK4LT56N0lfK5qNTzr6/DEyDw5TbFVwnuy2hhLBzwCBkScFVjpFdfiC6SQAX3FrAZzuuw==}
|
||||
'@next/swc-freebsd-x64@12.3.4':
|
||||
resolution: {integrity: sha512-KM9JXRXi/U2PUM928z7l4tnfQ9u8bTco/jb939pdFUHqc28V43Ohd31MmZD1QzEK4aFlMRaIBQOWQZh4D/E5lQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [freebsd]
|
||||
|
||||
'@next/swc-linux-arm-gnueabihf@12.2.5':
|
||||
resolution: {integrity: sha512-2ZE2/G921Acks7UopJZVMgKLdm4vN4U0yuzvAMJ6KBavPzqESA2yHJlm85TV/K9gIjKhSk5BVtauIUntFRP8cg==}
|
||||
'@next/swc-linux-arm-gnueabihf@12.3.4':
|
||||
resolution: {integrity: sha512-3zqD3pO+z5CZyxtKDTnOJ2XgFFRUBciOox6EWkoZvJfc9zcidNAQxuwonUeNts6Xbm8Wtm5YGIRC0x+12YH7kw==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-linux-arm64-gnu@12.2.5':
|
||||
resolution: {integrity: sha512-/I6+PWVlz2wkTdWqhlSYYJ1pWWgUVva6SgX353oqTh8njNQp1SdFQuWDqk8LnM6ulheVfSsgkDzxrDaAQZnzjQ==}
|
||||
'@next/swc-linux-arm64-gnu@12.3.4':
|
||||
resolution: {integrity: sha512-kiX0vgJGMZVv+oo1QuObaYulXNvdH/IINmvdZnVzMO/jic/B8EEIGlZ8Bgvw8LCjH3zNVPO3mGrdMvnEEPEhKA==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-linux-arm64-musl@12.2.5':
|
||||
resolution: {integrity: sha512-LPQRelfX6asXyVr59p5sTpx5l+0yh2Vjp/R8Wi4X9pnqcayqT4CUJLiHqCvZuLin3IsFdisJL0rKHMoaZLRfmg==}
|
||||
'@next/swc-linux-arm64-musl@12.3.4':
|
||||
resolution: {integrity: sha512-EETZPa1juczrKLWk5okoW2hv7D7WvonU+Cf2CgsSoxgsYbUCZ1voOpL4JZTOb6IbKMDo6ja+SbY0vzXZBUMvkQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-linux-x64-gnu@12.2.5':
|
||||
resolution: {integrity: sha512-0szyAo8jMCClkjNK0hknjhmAngUppoRekW6OAezbEYwHXN/VNtsXbfzgYOqjKWxEx3OoAzrT3jLwAF0HdX2MEw==}
|
||||
'@next/swc-linux-x64-gnu@12.3.4':
|
||||
resolution: {integrity: sha512-4csPbRbfZbuWOk3ATyWcvVFdD9/Rsdq5YHKvRuEni68OCLkfy4f+4I9OBpyK1SKJ00Cih16NJbHE+k+ljPPpag==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-linux-x64-musl@12.2.5':
|
||||
resolution: {integrity: sha512-zg/Y6oBar1yVnW6Il1I/08/2ukWtOG6s3acdJdEyIdsCzyQi4RLxbbhkD/EGQyhqBvd3QrC6ZXQEXighQUAZ0g==}
|
||||
'@next/swc-linux-x64-musl@12.3.4':
|
||||
resolution: {integrity: sha512-YeBmI+63Ro75SUiL/QXEVXQ19T++58aI/IINOyhpsRL1LKdyfK/35iilraZEFz9bLQrwy1LYAR5lK200A9Gjbg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [linux]
|
||||
|
||||
'@next/swc-win32-arm64-msvc@12.2.5':
|
||||
resolution: {integrity: sha512-3/90DRNSqeeSRMMEhj4gHHQlLhhKg5SCCoYfE3kBjGpE63EfnblYUqsszGGZ9ekpKL/R4/SGB40iCQr8tR5Jiw==}
|
||||
'@next/swc-win32-arm64-msvc@12.3.4':
|
||||
resolution: {integrity: sha512-Sd0qFUJv8Tj0PukAYbCCDbmXcMkbIuhnTeHm9m4ZGjCf6kt7E/RMs55Pd3R5ePjOkN7dJEuxYBehawTR/aPDSQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [arm64]
|
||||
os: [win32]
|
||||
|
||||
'@next/swc-win32-ia32-msvc@12.2.5':
|
||||
resolution: {integrity: sha512-hGLc0ZRAwnaPL4ulwpp4D2RxmkHQLuI8CFOEEHdzZpS63/hMVzv81g8jzYA0UXbb9pus/iTc3VRbVbAM03SRrw==}
|
||||
'@next/swc-win32-ia32-msvc@12.3.4':
|
||||
resolution: {integrity: sha512-rt/vv/vg/ZGGkrkKcuJ0LyliRdbskQU+91bje+PgoYmxTZf/tYs6IfbmgudBJk6gH3QnjHWbkphDdRQrseRefQ==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [ia32]
|
||||
os: [win32]
|
||||
|
||||
'@next/swc-win32-x64-msvc@12.2.5':
|
||||
resolution: {integrity: sha512-7h5/ahY7NeaO2xygqVrSG/Y8Vs4cdjxIjowTZ5W6CKoTKn7tmnuxlUc2h74x06FKmbhAd9agOjr/AOKyxYYm9Q==}
|
||||
'@next/swc-win32-x64-msvc@12.3.4':
|
||||
resolution: {integrity: sha512-DQ20JEfTBZAgF8QCjYfJhv2/279M6onxFjdG/+5B0Cyj00/EdBxiWb2eGGFgQhrBbNv/lsvzFbbi0Ptf8Vw/bg==}
|
||||
engines: {node: '>= 10'}
|
||||
cpu: [x64]
|
||||
os: [win32]
|
||||
@@ -290,8 +292,8 @@ packages:
|
||||
'@rushstack/eslint-patch@1.2.0':
|
||||
resolution: {integrity: sha512-sXo/qW2/pAcmT43VoRKOJbDOfV3cYpq3szSVfIThQXNt+E4DfKj361vaAt3c88U5tPUxzEswam7GW48PJqtKAg==}
|
||||
|
||||
'@swc/helpers@0.4.3':
|
||||
resolution: {integrity: sha512-6JrF+fdUK2zbGpJIlN7G3v966PQjyx/dPt1T9km2wj+EUBqgrxCk3uX4Kct16MIm9gGxfKRcfax2hVf5jvlTzA==}
|
||||
'@swc/helpers@0.4.11':
|
||||
resolution: {integrity: sha512-rEUrBSGIoSFuYxwBYtlUFMlE2CwGhmW+w9355/5oduSw8e5h2+Tj4UrAGNNgP9915++wj5vkQo0UuOBqOAq4nw==}
|
||||
|
||||
'@types/json5@0.0.29':
|
||||
resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==}
|
||||
@@ -480,7 +482,7 @@ packages:
|
||||
engines: {node: '>= 0.8'}
|
||||
|
||||
concat-map@0.0.1:
|
||||
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
|
||||
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
@@ -592,8 +594,8 @@ packages:
|
||||
resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==}
|
||||
engines: {node: '>=10'}
|
||||
|
||||
eslint-config-next@12.2.5:
|
||||
resolution: {integrity: sha512-SOowilkqPzW6DxKp3a3SYlrfPi5Ajs9MIzp9gVfUDxxH9QFM5ElkR1hX5m/iICJuvCbWgQqFBiA3mCMozluniw==}
|
||||
eslint-config-next@12.3.7:
|
||||
resolution: {integrity: sha512-27XeoFARn0e5DnReggt0Wukgd2QJGepb+ZgdTz1vhJVBAd5uG2ICzbOH4j/ZUUYmJY+waFG+CCrTPd3r+rSAfQ==}
|
||||
peerDependencies:
|
||||
eslint: ^7.23.0 || ^8.0.0
|
||||
typescript: '>=3.3.1'
|
||||
@@ -681,6 +683,7 @@ packages:
|
||||
eslint@8.22.0:
|
||||
resolution: {integrity: sha512-ci4t0sz6vSRKdmkOGmprBo6fmI4PrphDFMy5JEq/fNS0gQkJM3rLmrqcp8ipMcdobH3KtUP40KniAE9W19S4wA==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options.
|
||||
hasBin: true
|
||||
|
||||
espree@9.5.1:
|
||||
@@ -792,9 +795,11 @@ packages:
|
||||
|
||||
glob@7.1.7:
|
||||
resolution: {integrity: sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
|
||||
glob@7.2.3:
|
||||
resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==}
|
||||
deprecated: Glob versions prior to v9 are no longer supported
|
||||
|
||||
globals@13.20.0:
|
||||
resolution: {integrity: sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==}
|
||||
@@ -860,6 +865,7 @@ packages:
|
||||
|
||||
inflight@1.0.6:
|
||||
resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==}
|
||||
deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.
|
||||
|
||||
inherits@2.0.4:
|
||||
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
|
||||
@@ -1052,8 +1058,8 @@ packages:
|
||||
natural-compare@1.4.0:
|
||||
resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==}
|
||||
|
||||
next@12.2.5:
|
||||
resolution: {integrity: sha512-tBdjqX5XC/oFs/6gxrZhjmiq90YWizUYU6qOWAfat7zJwrwapJ+BYgX2PmiacunXMaRpeVT4vz5MSPSLgNkrpA==}
|
||||
next@12.3.7:
|
||||
resolution: {integrity: sha512-3PDn+u77s5WpbkUrslBP6SKLMeUj9cSx251LOt+yP9fgnqXV/ydny81xQsclz9R6RzCLONMCtwK2RvDdLa/mJQ==}
|
||||
engines: {node: '>=12.22.0'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
@@ -1233,6 +1239,7 @@ packages:
|
||||
|
||||
rimraf@3.0.2:
|
||||
resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==}
|
||||
deprecated: Rimraf versions prior to v4 are no longer supported
|
||||
hasBin: true
|
||||
|
||||
run-parallel@1.2.0:
|
||||
@@ -1253,11 +1260,6 @@ packages:
|
||||
resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==}
|
||||
hasBin: true
|
||||
|
||||
semver@7.5.0:
|
||||
resolution: {integrity: sha512-+XC0AD/R7Q2mPSRuy2Id0+CGTZ98+8f+KvwirxOKIEyid+XSx6HbC63p+O4IndTHuX5Z+JxQ0TghCkO5Cg/2HA==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
|
||||
semver@7.5.4:
|
||||
resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==}
|
||||
engines: {node: '>=10'}
|
||||
@@ -1321,8 +1323,8 @@ packages:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
||||
styled-jsx@5.0.4:
|
||||
resolution: {integrity: sha512-sDFWLbg4zR+UkNzfk5lPilyIgtpddfxXEULxhujorr5jtePTUqiPDc5BC0v1NRqTr/WaFBGQQUoYToGlF4B2KQ==}
|
||||
styled-jsx@5.0.7:
|
||||
resolution: {integrity: sha512-b3sUzamS086YLRuvnaDigdAewz1/EFYlHpYBP5mZovKEdQQOIIYq8lApylub3HHZ6xFjV051kkGU7cudJmrXEA==}
|
||||
engines: {node: '>= 12.0.0'}
|
||||
peerDependencies:
|
||||
'@babel/core': '*'
|
||||
@@ -1355,8 +1357,8 @@ packages:
|
||||
tslib@1.14.1:
|
||||
resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==}
|
||||
|
||||
tslib@2.5.0:
|
||||
resolution: {integrity: sha512-336iVw3rtn2BUK7ORdIAHTyxHGRIHVReokCR3XjbckJMK7ms8FysBfhLR8IXnAgy7T0PTPNBWKiH514FOW/WSg==}
|
||||
tslib@2.6.2:
|
||||
resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==}
|
||||
|
||||
tsutils@3.21.0:
|
||||
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
|
||||
@@ -1431,7 +1433,7 @@ snapshots:
|
||||
|
||||
'@emnapi/runtime@0.44.0':
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
tslib: 2.6.2
|
||||
optional: true
|
||||
|
||||
'@eslint/eslintrc@1.4.1':
|
||||
@@ -1537,49 +1539,49 @@ snapshots:
|
||||
|
||||
'@ioredis/commands@1.2.0': {}
|
||||
|
||||
'@next/env@12.2.5': {}
|
||||
'@next/env@12.3.7': {}
|
||||
|
||||
'@next/eslint-plugin-next@12.2.5':
|
||||
'@next/eslint-plugin-next@12.3.7':
|
||||
dependencies:
|
||||
glob: 7.1.7
|
||||
|
||||
'@next/swc-android-arm-eabi@12.2.5':
|
||||
'@next/swc-android-arm-eabi@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-android-arm64@12.2.5':
|
||||
'@next/swc-android-arm64@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-darwin-arm64@12.2.5':
|
||||
'@next/swc-darwin-arm64@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-darwin-x64@12.2.5':
|
||||
'@next/swc-darwin-x64@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-freebsd-x64@12.2.5':
|
||||
'@next/swc-freebsd-x64@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm-gnueabihf@12.2.5':
|
||||
'@next/swc-linux-arm-gnueabihf@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm64-gnu@12.2.5':
|
||||
'@next/swc-linux-arm64-gnu@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-arm64-musl@12.2.5':
|
||||
'@next/swc-linux-arm64-musl@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-x64-gnu@12.2.5':
|
||||
'@next/swc-linux-x64-gnu@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-linux-x64-musl@12.2.5':
|
||||
'@next/swc-linux-x64-musl@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-arm64-msvc@12.2.5':
|
||||
'@next/swc-win32-arm64-msvc@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-ia32-msvc@12.2.5':
|
||||
'@next/swc-win32-ia32-msvc@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@next/swc-win32-x64-msvc@12.2.5':
|
||||
'@next/swc-win32-x64-msvc@12.3.4':
|
||||
optional: true
|
||||
|
||||
'@nodelib/fs.scandir@2.1.5':
|
||||
@@ -1596,9 +1598,9 @@ snapshots:
|
||||
|
||||
'@rushstack/eslint-patch@1.2.0': {}
|
||||
|
||||
'@swc/helpers@0.4.3':
|
||||
'@swc/helpers@0.4.11':
|
||||
dependencies:
|
||||
tslib: 2.5.0
|
||||
tslib: 2.6.2
|
||||
|
||||
'@types/json5@0.0.29': {}
|
||||
|
||||
@@ -1644,7 +1646,7 @@ snapshots:
|
||||
debug: 4.3.4
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
semver: 7.5.0
|
||||
semver: 7.5.4
|
||||
tsutils: 3.21.0(typescript@4.7.4)
|
||||
optionalDependencies:
|
||||
typescript: 4.7.4
|
||||
@@ -1988,9 +1990,9 @@ snapshots:
|
||||
|
||||
escape-string-regexp@4.0.0: {}
|
||||
|
||||
eslint-config-next@12.2.5(eslint@8.22.0)(typescript@4.7.4):
|
||||
eslint-config-next@12.3.7(eslint@8.22.0)(typescript@4.7.4):
|
||||
dependencies:
|
||||
'@next/eslint-plugin-next': 12.2.5
|
||||
'@next/eslint-plugin-next': 12.3.7
|
||||
'@rushstack/eslint-patch': 1.2.0
|
||||
'@typescript-eslint/parser': 5.59.1(eslint@8.22.0)(typescript@4.7.4)
|
||||
eslint: 8.22.0
|
||||
@@ -2543,30 +2545,30 @@ snapshots:
|
||||
|
||||
natural-compare@1.4.0: {}
|
||||
|
||||
next@12.2.5(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.62.1):
|
||||
next@12.3.7(react-dom@18.2.0(react@18.2.0))(react@18.2.0)(sass@1.62.1):
|
||||
dependencies:
|
||||
'@next/env': 12.2.5
|
||||
'@swc/helpers': 0.4.3
|
||||
'@next/env': 12.3.7
|
||||
'@swc/helpers': 0.4.11
|
||||
caniuse-lite: 1.0.30001574
|
||||
postcss: 8.4.14
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
styled-jsx: 5.0.4(react@18.2.0)
|
||||
styled-jsx: 5.0.7(react@18.2.0)
|
||||
use-sync-external-store: 1.2.0(react@18.2.0)
|
||||
optionalDependencies:
|
||||
'@next/swc-android-arm-eabi': 12.2.5
|
||||
'@next/swc-android-arm64': 12.2.5
|
||||
'@next/swc-darwin-arm64': 12.2.5
|
||||
'@next/swc-darwin-x64': 12.2.5
|
||||
'@next/swc-freebsd-x64': 12.2.5
|
||||
'@next/swc-linux-arm-gnueabihf': 12.2.5
|
||||
'@next/swc-linux-arm64-gnu': 12.2.5
|
||||
'@next/swc-linux-arm64-musl': 12.2.5
|
||||
'@next/swc-linux-x64-gnu': 12.2.5
|
||||
'@next/swc-linux-x64-musl': 12.2.5
|
||||
'@next/swc-win32-arm64-msvc': 12.2.5
|
||||
'@next/swc-win32-ia32-msvc': 12.2.5
|
||||
'@next/swc-win32-x64-msvc': 12.2.5
|
||||
'@next/swc-android-arm-eabi': 12.3.4
|
||||
'@next/swc-android-arm64': 12.3.4
|
||||
'@next/swc-darwin-arm64': 12.3.4
|
||||
'@next/swc-darwin-x64': 12.3.4
|
||||
'@next/swc-freebsd-x64': 12.3.4
|
||||
'@next/swc-linux-arm-gnueabihf': 12.3.4
|
||||
'@next/swc-linux-arm64-gnu': 12.3.4
|
||||
'@next/swc-linux-arm64-musl': 12.3.4
|
||||
'@next/swc-linux-x64-gnu': 12.3.4
|
||||
'@next/swc-linux-x64-musl': 12.3.4
|
||||
'@next/swc-win32-arm64-msvc': 12.3.4
|
||||
'@next/swc-win32-ia32-msvc': 12.3.4
|
||||
'@next/swc-win32-x64-msvc': 12.3.4
|
||||
sass: 1.62.1
|
||||
transitivePeerDependencies:
|
||||
- '@babel/core'
|
||||
@@ -2759,10 +2761,6 @@ snapshots:
|
||||
|
||||
semver@6.3.0: {}
|
||||
|
||||
semver@7.5.0:
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
|
||||
semver@7.5.4:
|
||||
dependencies:
|
||||
lru-cache: 6.0.0
|
||||
@@ -2856,7 +2854,7 @@ snapshots:
|
||||
|
||||
strip-json-comments@3.1.1: {}
|
||||
|
||||
styled-jsx@5.0.4(react@18.2.0):
|
||||
styled-jsx@5.0.7(react@18.2.0):
|
||||
dependencies:
|
||||
react: 18.2.0
|
||||
|
||||
@@ -2881,7 +2879,7 @@ snapshots:
|
||||
|
||||
tslib@1.14.1: {}
|
||||
|
||||
tslib@2.5.0: {}
|
||||
tslib@2.6.2: {}
|
||||
|
||||
tsutils@3.21.0(typescript@4.7.4):
|
||||
dependencies:
|
||||
|
@@ -1,2 +0,0 @@
|
||||
onlyBuiltDependencies:
|
||||
- sharp
|
@@ -1,7 +0,0 @@
|
||||
<OpenSearchDescription xmlns="http://a9.com/-/spec/opensearch/1.1/">
|
||||
<ShortName>libremdb</ShortName>
|
||||
<Description>Search libremdb</Description>
|
||||
<InputEncoding>UTF-8</InputEncoding>
|
||||
<Image width="16" height="16" type="image/x-icon">https://libremdb.iket.me/favicon.ico</Image>
|
||||
<Url type="text/html" method="get" template="https://libremdb.iket.me/find?q={searchTerms}"/>
|
||||
</OpenSearchDescription>
|
@@ -11,7 +11,6 @@ type Props = {
|
||||
message: string;
|
||||
statusCode?: number;
|
||||
originalPath?: string;
|
||||
stack?: string;
|
||||
/** props specific to error boundary. */
|
||||
misc?: {
|
||||
subtext: string;
|
||||
@@ -20,9 +19,7 @@ type Props = {
|
||||
};
|
||||
};
|
||||
|
||||
const isDev = process.env.NODE_ENV === 'development';
|
||||
|
||||
const ErrorInfo = ({ message, statusCode, misc, originalPath, stack }: Props) => {
|
||||
const ErrorInfo = ({ message, statusCode, misc, originalPath }: Props) => {
|
||||
const title = statusCode ? `${message} (${statusCode})` : message;
|
||||
return (
|
||||
<>
|
||||
@@ -42,11 +39,6 @@ const ErrorInfo = ({ message, statusCode, misc, originalPath, stack }: Props) =>
|
||||
<use href='/svg/sadgnu.svg#sad-gnu'></use>
|
||||
</svg>
|
||||
<h1 className={`heading heading__primary ${styles.heading}`}>{title}</h1>
|
||||
{Boolean(stack && isDev) && (
|
||||
<pre className={styles.stack}>
|
||||
<code>{stack}</code>
|
||||
</pre>
|
||||
)}
|
||||
{misc ? (
|
||||
<>
|
||||
<p>{misc.subtext}</p>
|
||||
@@ -72,13 +64,6 @@ const ErrorInfo = ({ message, statusCode, misc, originalPath, stack }: Props) =>
|
||||
.
|
||||
</p>
|
||||
)}
|
||||
<p>
|
||||
If you think this shouldn't happen,{' '}
|
||||
<Link href='/contact'>
|
||||
<a className='link'>let it be known</a>
|
||||
</Link>
|
||||
.
|
||||
</p>
|
||||
</Layout>
|
||||
</>
|
||||
);
|
||||
|
@@ -14,41 +14,32 @@ type Props = {
|
||||
const Media = ({ className, media }: Props) => {
|
||||
return (
|
||||
<div className={`${className} ${styles.media}`}>
|
||||
{(media.trailers?.length || !!media.videos.total) && (
|
||||
{(media.trailer || !!media.videos.total) && (
|
||||
<section className={styles.videos}>
|
||||
<h2 className='heading heading__secondary'>Videos</h2>
|
||||
|
||||
<div className={styles.videos__container}>
|
||||
{media.trailers?.map(trailer => (
|
||||
<div className={styles.trailer} key={trailer.id}>
|
||||
{media.trailer && (
|
||||
<div className={styles.trailer}>
|
||||
<video
|
||||
aria-label={trailer.caption ?? 'trailer video'}
|
||||
aria-label='trailer video'
|
||||
controls
|
||||
playsInline
|
||||
poster={getProxiedIMDbImgUrl(modifyIMDbImg(trailer.thumbnail))}
|
||||
poster={getProxiedIMDbImgUrl(modifyIMDbImg(media.trailer.thumbnail))}
|
||||
className={styles.trailer__video}
|
||||
preload='none'
|
||||
muted
|
||||
>
|
||||
{trailer.urls.map(source => (
|
||||
{media.trailer.urls.map(source => (
|
||||
<source
|
||||
key={source.url}
|
||||
type='video/mp4'
|
||||
type={source.mimeType ?? undefined}
|
||||
src={getProxiedIMDbImgUrl(source.url)}
|
||||
media={source.resolution !== 'SD' ? '(min-width: 450px)' : undefined}
|
||||
data-res={source.resolution}
|
||||
/>
|
||||
))}
|
||||
|
||||
<p>
|
||||
{trailer.caption}:{' '}
|
||||
<Link href={getProxiedIMDbImgUrl(trailer.urls[0]?.url)}>
|
||||
<a className='link'>link</a>
|
||||
</Link>
|
||||
</p>
|
||||
</video>
|
||||
</div>
|
||||
))}
|
||||
)}
|
||||
|
||||
{!!media.videos.total &&
|
||||
media.videos.videos.map(video => (
|
||||
|
@@ -36,13 +36,6 @@ const Meta = ({
|
||||
<meta property='og:locale' content='en_US' />
|
||||
<meta property='og:type' content='video.movie' />
|
||||
<meta property='og:image' content={url.toString()} />
|
||||
|
||||
<link
|
||||
rel='search'
|
||||
type='application/opensearchdescription+xml'
|
||||
href='/opensearch.xml'
|
||||
title='libremdb'
|
||||
></link>
|
||||
</Head>
|
||||
);
|
||||
};
|
||||
|
@@ -9,54 +9,43 @@ type Props = {
|
||||
const DidYouKnow = ({ data }: Props) => (
|
||||
<section className={styles.container}>
|
||||
<h2 className='heading heading__secondary'>Did you know</h2>
|
||||
{isEmpty(data) ? (
|
||||
<p>Nothing interesting to show.</p>
|
||||
) : (
|
||||
<>
|
||||
{!!data.trivia?.total && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Trivia</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: data.trivia.html }}></div>
|
||||
</section>
|
||||
)}
|
||||
{!!data.quotes?.total && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Quotes</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: data.quotes.html }}></div>
|
||||
</section>
|
||||
)}
|
||||
{!!data.trademark?.total && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Trademark</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: data.trademark.html }}></div>
|
||||
</section>
|
||||
)}
|
||||
{!!data.nicknames.length && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Nicknames</h3>
|
||||
<p>{data.nicknames.join(', ')}</p>
|
||||
</section>
|
||||
)}
|
||||
{!!data.salary?.total && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Salary</h3>
|
||||
<p>
|
||||
<span>{data.salary.value} in </span>
|
||||
<Link href={`/title/${data.salary.title.id}`}>
|
||||
<a className={'link'}>{data.salary.title.text}</a>
|
||||
</Link>
|
||||
<span> ({data.salary.title.year})</span>
|
||||
</p>
|
||||
</section>
|
||||
)}
|
||||
</>
|
||||
{!!data.trivia?.total && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Trivia</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: data.trivia.html }}></div>
|
||||
</section>
|
||||
)}
|
||||
{!!data.quotes?.total && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Quotes</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: data.quotes.html }}></div>
|
||||
</section>
|
||||
)}
|
||||
{!!data.trademark?.total && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Trademark</h3>
|
||||
<div dangerouslySetInnerHTML={{ __html: data.trademark.html }}></div>
|
||||
</section>
|
||||
)}
|
||||
{!!data.nicknames.length && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Nicknames</h3>
|
||||
<p>{data.nicknames.join(', ')}</p>
|
||||
</section>
|
||||
)}
|
||||
{!!data.salary?.total && (
|
||||
<section>
|
||||
<h3 className='heading heading__tertiary'>Salary</h3>
|
||||
<p>
|
||||
<span>{data.salary.value} in </span>
|
||||
<Link href={`/title/${data.salary.title.id}`}>
|
||||
<a className={'link'}>{data.salary.title.text}</a>
|
||||
</Link>
|
||||
<span> ({data.salary.title.year})</span>
|
||||
</p>
|
||||
</section>
|
||||
)}
|
||||
</section>
|
||||
);
|
||||
|
||||
export default DidYouKnow;
|
||||
|
||||
const isEmpty = (data: Props['data']) =>
|
||||
Boolean(
|
||||
!data.nicknames.length && !data.quotes && !data.salary && !data.trademark && !data.trivia
|
||||
);
|
@@ -86,21 +86,6 @@ const Basic = ({ data, className }: Props) => {
|
||||
))}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{!!data.interests.length && (
|
||||
<p className={styles.genres}>
|
||||
<span className={styles.genres__heading}>Interests: </span>
|
||||
{data.interests.map((interest, i) => (
|
||||
<Fragment key={interest.id}>
|
||||
{i > 0 && ', '}
|
||||
<Link href={`/interest/${interest.id}`}>
|
||||
<a className={styles.link}>{interest.text}</a>
|
||||
</Link>
|
||||
</Fragment>
|
||||
))}
|
||||
</p>
|
||||
)}
|
||||
|
||||
<p className={styles.overview}>
|
||||
<span className={styles.overview__heading}>Plot: </span>
|
||||
<span className={styles.overview__text}>{data.plot || '-'}</span>
|
||||
|
@@ -7,13 +7,7 @@ type Props = {
|
||||
};
|
||||
|
||||
const DidYouKnow = ({ data }: Props) => {
|
||||
if (!Object.keys(data).length)
|
||||
return (
|
||||
<section className={styles.didYouKnow}>
|
||||
<h2 className='heading heading__secondary'>Did you know</h2>
|
||||
<p>Nothing interesting to show.</p>
|
||||
</section>
|
||||
);
|
||||
if (!Object.keys(data).length) return <></>;
|
||||
return (
|
||||
<section className={styles.didYouKnow}>
|
||||
<h2 className='heading heading__secondary'>Did you know</h2>
|
||||
|
@@ -1,127 +1,82 @@
|
||||
import { useRouter } from 'next/router';
|
||||
import Link from 'next/link';
|
||||
import type { Reviews as TReviews } from 'src/interfaces/shared/title';
|
||||
import { Reviews } from 'src/interfaces/shared/title';
|
||||
import { formatNumber } from 'src/utils/helpers';
|
||||
import styles from 'src/styles/modules/components/title/reviews.module.scss';
|
||||
|
||||
type Props = {
|
||||
reviews: TReviews;
|
||||
reviews: Reviews;
|
||||
};
|
||||
|
||||
const Reviews = ({ reviews }: Props) => {
|
||||
return (
|
||||
<section className={styles.reviews}>
|
||||
<h2 className='heading heading__secondary'>Reviews</h2>
|
||||
|
||||
<RatingsDistribution ratings={reviews.ratingsDistribution} />
|
||||
|
||||
<section className={styles.userReviews}>
|
||||
<h3 className='heading heading__tertiary'>User Reviews</h3>
|
||||
{reviews.featuredReviews ? (
|
||||
<ul className={styles.userReviews__list} role='list'>
|
||||
{reviews.featuredReviews.map(featuredReview => (
|
||||
<li key={featuredReview.id}>
|
||||
<details className={styles.review}>
|
||||
<summary className={styles.review__summary}>
|
||||
<strong>{featuredReview.review.summary}</strong>
|
||||
</summary>
|
||||
<div
|
||||
className={styles.review__text}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: featuredReview.review.html,
|
||||
}}
|
||||
></div>
|
||||
<footer className={styles.review__metadata}>
|
||||
<p>
|
||||
{featuredReview.rating && <span>Rated {featuredReview.rating}/10</span>}
|
||||
<span>
|
||||
{' '}
|
||||
by{' '}
|
||||
<Link href={`/user/${featuredReview.reviewer.id}`}>
|
||||
<a className='link'>{featuredReview.reviewer.name}</a>
|
||||
</Link>
|
||||
</span>
|
||||
</p>
|
||||
</footer>
|
||||
</details>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p>No reviews yet.</p>
|
||||
)}
|
||||
</section>
|
||||
|
||||
{reviews.ai?.summary && (
|
||||
<details className={styles.reviewAi}>
|
||||
<summary className='heading heading__tertiary'>AI Summary</summary>
|
||||
<p dangerouslySetInnerHTML={{ __html: reviews.ai.summary }} />
|
||||
<ul>
|
||||
{reviews.ai.themes.map(theme => (
|
||||
<li key={theme.id}>{theme.text}</li>
|
||||
))}
|
||||
</ul>
|
||||
</details>
|
||||
)}
|
||||
|
||||
<ReviewStats reviews={reviews} />
|
||||
</section>
|
||||
);
|
||||
};
|
||||
|
||||
export default Reviews;
|
||||
|
||||
const RatingsDistribution = ({ ratings }: { ratings: Props['reviews']['ratingsDistribution'] }) => {
|
||||
const maxRating = Math.max(...ratings.map(r => r.votes));
|
||||
|
||||
return (
|
||||
<div className={styles.ratingsDistribution}>
|
||||
<h3 className='heading heading__tertiary'>Ratings Distribution</h3>
|
||||
{ratings.length ? (
|
||||
<ul>
|
||||
{ratings.map(rating => (
|
||||
<li
|
||||
key={rating.rating}
|
||||
style={
|
||||
{
|
||||
'--bar-height': `${((rating.votes / maxRating) * 100).toFixed(2)}%`,
|
||||
} as React.CSSProperties
|
||||
}
|
||||
>
|
||||
<span>
|
||||
{rating.rating} <span>({formatNumber(rating.votes)})</span>
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
) : (
|
||||
<p>No ratings yet.</p>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ReviewStats = ({ reviews }: { reviews: Props['reviews'] }) => {
|
||||
const router = useRouter();
|
||||
const { titleId } = router.query;
|
||||
|
||||
return (
|
||||
<div className={styles.reviewStats}>
|
||||
<p>
|
||||
<Link href={`/title/${titleId}/reviews`}>
|
||||
<a className='link'>{formatNumber(reviews.numUserReviews)} User reviews</a>
|
||||
</Link>
|
||||
</p>
|
||||
<p>
|
||||
<Link href={`/title/${titleId}/externalreviews`}>
|
||||
<a className='link'>{formatNumber(reviews.numCriticReviews)} Critic reviews</a>
|
||||
</Link>
|
||||
</p>
|
||||
<p>
|
||||
<Link href={`/title/${titleId}/criticreviews`}>
|
||||
<a className='link'> {reviews.metacriticScore} Metascore</a>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
<section className={styles.reviews}>
|
||||
<h2 className="heading heading__secondary">Reviews</h2>
|
||||
|
||||
{reviews.featuredReview && (
|
||||
<article className={styles.reviews__reviewContainer}>
|
||||
<details className={styles.review}>
|
||||
<summary className={styles.review__summary}>
|
||||
<strong>{reviews.featuredReview.review.summary}</strong>
|
||||
</summary>
|
||||
<div
|
||||
className={styles.review__text}
|
||||
dangerouslySetInnerHTML={{
|
||||
__html: reviews.featuredReview.review.html,
|
||||
}}
|
||||
></div>
|
||||
</details>
|
||||
<footer className={styles.review__metadata}>
|
||||
<p>
|
||||
{reviews.featuredReview.rating && (
|
||||
<span>Rated {reviews.featuredReview.rating}/10</span>
|
||||
)}
|
||||
<span>
|
||||
{' '}
|
||||
by{' '}
|
||||
<Link href={`/user/${reviews.featuredReview.reviewer.id}`}>
|
||||
<a className="link">{reviews.featuredReview.reviewer.name}</a>
|
||||
</Link>
|
||||
</span>
|
||||
<span> on {reviews.featuredReview.date}.</span>
|
||||
</p>
|
||||
<p>
|
||||
<span>
|
||||
{formatNumber(reviews.featuredReview.votes.up)} upvotes
|
||||
</span>
|
||||
<span>
|
||||
, {formatNumber(reviews.featuredReview.votes.down)} downvotes
|
||||
</span>
|
||||
</p>
|
||||
</footer>
|
||||
</article>
|
||||
)}
|
||||
|
||||
<div className={styles.reviews__stats}>
|
||||
<p>
|
||||
<Link href={`/title/${titleId}/reviews`}>
|
||||
<a className="link">
|
||||
{formatNumber(reviews.numUserReviews)} User reviews
|
||||
</a>
|
||||
</Link>
|
||||
</p>
|
||||
<p>
|
||||
<Link href={`/title/${titleId}/externalreviews`}>
|
||||
<a className="link">
|
||||
{formatNumber(reviews.numCriticReviews)} Critic reviews
|
||||
</a>
|
||||
</Link>
|
||||
</p>
|
||||
<p>
|
||||
<Link href={`/title/${titleId}/criticreviews`}>
|
||||
<a className="link"> {reviews.metacriticScore} Metascore</a>
|
||||
</Link>
|
||||
</p>
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
};
|
||||
export default Reviews;
|
||||
|
@@ -143,7 +143,7 @@ export default interface Name {
|
||||
value: string;
|
||||
language: string;
|
||||
};
|
||||
videoMimeType?: string;
|
||||
mimeType?: string;
|
||||
url: string;
|
||||
}>;
|
||||
recommendedTimedTextTrack?: {
|
||||
|
File diff suppressed because it is too large
Load Diff
@@ -1,3 +1,3 @@
|
||||
import { AppError as AppErrorClass } from 'src/utils/helpers';
|
||||
|
||||
export type AppError = Pick<InstanceType<typeof AppErrorClass>, 'message' | 'statusCode' | 'stack'>;
|
||||
export type AppError = Omit<InstanceType<typeof AppErrorClass>, 'name'>;
|
||||
|
@@ -67,13 +67,13 @@ export const getServerSideProps: GetServerSideProps<Data, FindQueryParams> = asy
|
||||
props: { data: { title: query, results: res }, error: null, originalPath },
|
||||
};
|
||||
} catch (error) {
|
||||
const err = getErrorProperties(error);
|
||||
ctx.res.statusCode = err.statusCode;
|
||||
ctx.res.statusMessage = err.message;
|
||||
const { message, statusCode } = getErrorProperties(error);
|
||||
ctx.res.statusCode = statusCode;
|
||||
ctx.res.statusMessage = message;
|
||||
|
||||
return {
|
||||
props: {
|
||||
error: { message: err.message, statusCode: err.statusCode, stack: err.format() },
|
||||
error: { message, statusCode },
|
||||
data: { title: query, results: null },
|
||||
originalPath,
|
||||
},
|
||||
|
@@ -55,17 +55,11 @@ export const getServerSideProps: GetServerSideProps<Data, Params> = async ctx =>
|
||||
|
||||
return { props: { data, error: null, originalPath } };
|
||||
} catch (error) {
|
||||
const err = getErrorProperties(error);
|
||||
ctx.res.statusCode = err.statusCode;
|
||||
ctx.res.statusMessage = err.message;
|
||||
const { message, statusCode } = getErrorProperties(error);
|
||||
ctx.res.statusCode = statusCode;
|
||||
ctx.res.statusMessage = message;
|
||||
|
||||
return {
|
||||
props: {
|
||||
error: { message: err.message, statusCode: err.statusCode, stack: err.format() },
|
||||
data: null,
|
||||
originalPath,
|
||||
},
|
||||
};
|
||||
return { props: { error: { message, statusCode }, data: null, originalPath } };
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -5,7 +5,7 @@ import ErrorInfo from 'src/components/error/ErrorInfo';
|
||||
import Media from 'src/components/media/Media';
|
||||
import { Basic, Cast, DidYouKnow, Info, MoreLikeThis, Reviews } from 'src/components/title';
|
||||
import Title from 'src/interfaces/shared/title';
|
||||
import type { AppError } from 'src/interfaces/shared/error';
|
||||
import { AppError } from 'src/interfaces/shared/error';
|
||||
import getOrSetApiCache from 'src/utils/getOrSetApiCache';
|
||||
import title from 'src/utils/fetchers/title';
|
||||
import { getErrorProperties, getProxiedIMDbImgUrl } from 'src/utils/helpers';
|
||||
@@ -63,18 +63,12 @@ export const getServerSideProps: GetServerSideProps<Data, Params> = async ctx =>
|
||||
const data = await getOrSetApiCache(titleKey(titleId), title, titleId);
|
||||
|
||||
return { props: { data, error: null, originalPath } };
|
||||
} catch (e) {
|
||||
const err = getErrorProperties(e);
|
||||
ctx.res.statusCode = err.statusCode;
|
||||
ctx.res.statusMessage = err.message;
|
||||
} catch (error) {
|
||||
const { message, statusCode } = getErrorProperties(error);
|
||||
ctx.res.statusCode = statusCode;
|
||||
ctx.res.statusMessage = message;
|
||||
|
||||
const error = {
|
||||
message: err.message,
|
||||
statusCode: err.statusCode,
|
||||
stack: err.format(),
|
||||
};
|
||||
console.error(err);
|
||||
return { props: { error, data: null, originalPath } };
|
||||
return { props: { error: { message, statusCode }, data: null, originalPath } };
|
||||
}
|
||||
};
|
||||
|
||||
|
@@ -8,7 +8,7 @@
|
||||
display: grid;
|
||||
justify-content: center;
|
||||
justify-items: center;
|
||||
gap: var(--comp-whitespace);
|
||||
gap: var(--spacer-1);
|
||||
|
||||
@include helper.bp('bp-700') {
|
||||
--doc-whitespace: var(--spacer-5);
|
||||
@@ -31,19 +31,6 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.stack {
|
||||
max-width: 90%;
|
||||
max-height: 20rem;
|
||||
padding: var(--spacer-3);
|
||||
white-space: pre-wrap;
|
||||
overflow: scroll;
|
||||
|
||||
user-select: all;
|
||||
|
||||
border-radius: var(--spacer-1);
|
||||
background-color: var(--clr-bg-muted);
|
||||
}
|
||||
|
||||
.button {
|
||||
align-self: end;
|
||||
|
||||
|
@@ -1,94 +1,26 @@
|
||||
.reviews {
|
||||
display: grid;
|
||||
gap: var(--comp-whitespace);
|
||||
}
|
||||
|
||||
.ratingsDistribution {
|
||||
overflow: hidden;
|
||||
&__reviewContainer {
|
||||
// background-color: antiquewhite;
|
||||
}
|
||||
|
||||
ul {
|
||||
list-style: none;
|
||||
&__stats {
|
||||
display: flex;
|
||||
gap: var(--spacer-2);
|
||||
overflow-x: auto;
|
||||
padding-block: var(--spacer-1);
|
||||
}
|
||||
|
||||
li {
|
||||
text-align: center;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 5em;
|
||||
align-items: center;
|
||||
flex-shrink: 0;
|
||||
|
||||
&::before {
|
||||
display: block;
|
||||
content: '';
|
||||
|
||||
height: var(--bar-height);
|
||||
margin-top: auto;
|
||||
background-color: var(--clr-fill);
|
||||
width: var(--spacer-6);
|
||||
border-radius: var(--spacer-0);
|
||||
}
|
||||
|
||||
span {
|
||||
font-weight: var(--fw-bold);
|
||||
|
||||
> span {
|
||||
font-weight: initial;
|
||||
font-size: 0.9em;
|
||||
color: var(--clr-text-muted);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reviewAi {
|
||||
summary {
|
||||
cursor: pointer;
|
||||
}
|
||||
p {
|
||||
padding-block: var(--spacer-2);
|
||||
}
|
||||
ul {
|
||||
list-style: none;
|
||||
display: flex;
|
||||
gap: var(--spacer-1);
|
||||
flex-wrap: wrap;
|
||||
|
||||
li {
|
||||
padding: var(--spacer-1);
|
||||
background-color: var(--clr-bg-muted);
|
||||
border-radius: var(--spacer-0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.reviewStats {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacer-2);
|
||||
}
|
||||
|
||||
.userReviews {
|
||||
|
||||
&__list {
|
||||
padding-block-start: var(--spacer-1);
|
||||
display: grid;
|
||||
gap: var(--spacer-1);
|
||||
list-style: none;
|
||||
gap: var(--spacer-2);
|
||||
}
|
||||
}
|
||||
|
||||
.review {
|
||||
&__summary {
|
||||
font-size: calc(var(--fs-5) * 1.1);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
&__text,
|
||||
&__metadata {
|
||||
padding-top: var(--spacer-1);
|
||||
padding-top: var(--spacer-2);
|
||||
}
|
||||
}
|
||||
|
@@ -42,18 +42,18 @@ const cleanName = (rawData: RawName) => {
|
||||
},
|
||||
media: {
|
||||
...(main.primaryVideos.edges.length && {
|
||||
trailers: main.primaryVideos.edges.map(trailer => ({
|
||||
id: trailer.node.id,
|
||||
isMature: trailer.node.isMature,
|
||||
thumbnail: trailer.node.thumbnail.url,
|
||||
runtime: trailer.node.runtime.value,
|
||||
caption: trailer.node.description?.value ?? null,
|
||||
urls: trailer.node.playbackURLs.map(url => ({
|
||||
resolution: url.displayName.value as 'SD' | '480p',
|
||||
mimeType: url.videoMimeType ?? null,
|
||||
trailer: {
|
||||
id: main.primaryVideos.edges[0].node.id,
|
||||
isMature: main.primaryVideos.edges[0].node.isMature,
|
||||
thumbnail: main.primaryVideos.edges[0].node.thumbnail.url,
|
||||
runtime: main.primaryVideos.edges[0].node.runtime.value,
|
||||
caption: main.primaryVideos.edges[0].node.description?.value ?? null,
|
||||
urls: main.primaryVideos.edges[0].node.playbackURLs.map(url => ({
|
||||
resolution: url.displayName.value,
|
||||
mimeType: url.mimeType ?? null,
|
||||
url: url.url,
|
||||
})),
|
||||
})),
|
||||
},
|
||||
}),
|
||||
images: {
|
||||
total: misc.images.total,
|
||||
|
@@ -12,7 +12,6 @@ const cleanTitle = (rawData: RawTitle) => {
|
||||
titleId: main.id,
|
||||
basic: {
|
||||
id: main.id,
|
||||
isAdult: main.isAdult,
|
||||
title: main.titleText.text,
|
||||
// ...(main.originalTitleText.text.toLowerCase() !==
|
||||
// main.titleText.text.toLowerCase() && {
|
||||
@@ -51,10 +50,6 @@ const cleanTitle = (rawData: RawTitle) => {
|
||||
id: genre.id,
|
||||
text: genre.text,
|
||||
})),
|
||||
interests: main.interests.edges.map(interest => ({
|
||||
id: interest.node.id,
|
||||
text: interest.node.primaryText.text,
|
||||
})),
|
||||
plot: main.plot?.plotText?.plainText || null,
|
||||
primaryCrew: main.principalCredits.map(type => ({
|
||||
type: { category: type.category.text, id: type.category.id },
|
||||
@@ -81,18 +76,18 @@ const cleanTitle = (rawData: RawTitle) => {
|
||||
})),
|
||||
media: {
|
||||
...(main.primaryVideos.edges.length && {
|
||||
trailers: main.primaryVideos.edges.map(trailer => ({
|
||||
id: trailer.node.id,
|
||||
isMature: trailer.node.isMature,
|
||||
thumbnail: trailer.node.thumbnail.url,
|
||||
runtime: trailer.node.runtime.value,
|
||||
caption: trailer.node.description?.value ?? null,
|
||||
urls: trailer.node.playbackURLs.map(url => ({
|
||||
resolution: url.displayName.value as 'SD' | '480p',
|
||||
mimeType: url.videoMimeType ?? null,
|
||||
trailer: {
|
||||
id: main.primaryVideos.edges[0].node.id,
|
||||
isMature: main.primaryVideos.edges[0].node.isMature,
|
||||
thumbnail: main.primaryVideos.edges[0].node.thumbnail.url,
|
||||
runtime: main.primaryVideos.edges[0].node.runtime.value,
|
||||
caption: main.primaryVideos.edges[0].node.description?.value ?? null,
|
||||
urls: main.primaryVideos.edges[0].node.playbackURLs.map(url => ({
|
||||
resolution: url.displayName.value,
|
||||
mimeType: url.mimeType ?? null,
|
||||
url: url.url,
|
||||
})),
|
||||
})),
|
||||
},
|
||||
}),
|
||||
images: {
|
||||
total: misc.titleMainImages.total,
|
||||
@@ -127,9 +122,6 @@ const cleanTitle = (rawData: RawTitle) => {
|
||||
}),
|
||||
topRating: misc.ratingsSummary.topRanking?.rank || null,
|
||||
},
|
||||
watchlist: {
|
||||
text: main.engagementStatistics?.watchlistStatistics.displayableCount.text || null,
|
||||
},
|
||||
meta: {
|
||||
// for tv episode
|
||||
...(main.series && {
|
||||
@@ -216,34 +208,24 @@ const cleanTitle = (rawData: RawTitle) => {
|
||||
metacriticScore: main.metacritic?.metascore.score || null,
|
||||
numCriticReviews: main.criticReviewsTotal.total,
|
||||
numUserReviews: misc.reviews.total,
|
||||
ratingsDistribution:
|
||||
misc.aggregateRatingsBreakdown.histogram?.histogramValues.map(v => ({
|
||||
rating: v.rating,
|
||||
votes: v.voteCount,
|
||||
})) || [],
|
||||
...(misc.reviewSummary && {
|
||||
ai: {
|
||||
summary: misc.reviewSummary.overall.medium.value.plaidHtml,
|
||||
themes: misc.reviewSummary.themes.map(t => ({
|
||||
text: t.label.value,
|
||||
id: t.themeId,
|
||||
sentiment: t.sentiment as 'POSITIVE' | 'NEGATIVE',
|
||||
})),
|
||||
},
|
||||
}),
|
||||
...(misc.featuredReviews.edges.length && {
|
||||
featuredReviews: misc.featuredReviews.edges.map(featuredReview => ({
|
||||
id: featuredReview.node.id,
|
||||
featuredReview: {
|
||||
id: misc.featuredReviews.edges[0].node.id,
|
||||
reviewer: {
|
||||
id: featuredReview.node.author.userId,
|
||||
name: featuredReview.node.author.username.text,
|
||||
id: misc.featuredReviews.edges[0].node.author.userId,
|
||||
name: misc.featuredReviews.edges[0].node.author.nickName,
|
||||
},
|
||||
rating: misc.featuredReviews.edges[0].node.authorRating,
|
||||
date: formatDate(misc.featuredReviews.edges[0].node.submissionDate),
|
||||
votes: {
|
||||
up: misc.featuredReviews.edges[0].node.helpfulness.upVotes,
|
||||
down: misc.featuredReviews.edges[0].node.helpfulness.downVotes,
|
||||
},
|
||||
rating: featuredReview.node.authorRating,
|
||||
review: {
|
||||
summary: featuredReview.node.summary.originalText,
|
||||
html: featuredReview.node.text.originalText.plaidHtml,
|
||||
summary: misc.featuredReviews.edges[0].node.summary.originalText,
|
||||
html: misc.featuredReviews.edges[0].node.text.originalText.plaidHtml,
|
||||
},
|
||||
})),
|
||||
},
|
||||
}),
|
||||
},
|
||||
details: {
|
||||
@@ -260,8 +242,8 @@ const cleanTitle = (rawData: RawTitle) => {
|
||||
},
|
||||
},
|
||||
}),
|
||||
...(misc.countriesDetails && {
|
||||
countriesOfOrigin: misc.countriesDetails.countries.map(country => ({
|
||||
...(misc.countriesOfOrigin && {
|
||||
countriesOfOrigin: misc.countriesOfOrigin.countries.map(country => ({
|
||||
id: country.id,
|
||||
text: country.text,
|
||||
})),
|
||||
@@ -371,10 +353,6 @@ const cleanTitle = (rawData: RawTitle) => {
|
||||
},
|
||||
genres: title.node.titleGenres?.genres.map(genre => genre.genre.text) ?? null,
|
||||
})),
|
||||
faqs: {
|
||||
questions: misc.faqs.edges.map(q => ({ question: q.node.question, id: q.node.id })),
|
||||
total: misc.faqs.total,
|
||||
},
|
||||
};
|
||||
|
||||
return cleanData;
|
||||
|
@@ -74,33 +74,12 @@ export const getProxiedIMDbImgUrl = (url: string) => {
|
||||
};
|
||||
|
||||
export const AppError = class extends Error {
|
||||
constructor(message: string, public statusCode: number, cause?: unknown) {
|
||||
const _cause = cause ? AppError.toError(cause) : undefined;
|
||||
super(message, { cause: _cause });
|
||||
constructor(message: string, public statusCode: number, errorOptions?: unknown) {
|
||||
const saneErrorOptions = getErrorOptions(errorOptions);
|
||||
super(message, saneErrorOptions);
|
||||
|
||||
Error.captureStackTrace(this, AppError);
|
||||
}
|
||||
|
||||
static toError(err: unknown) {
|
||||
if (err instanceof Error) return err;
|
||||
return new Error(`Unexpected: ${JSON.stringify(err)}`);
|
||||
}
|
||||
|
||||
format() {
|
||||
let str = '';
|
||||
let cur: Error | null = this;
|
||||
let depth = 0;
|
||||
|
||||
while (cur && depth <= 4) {
|
||||
if (cur.stack) str += `${cur.stack}\n`;
|
||||
else str += `${cur.name}: ${cur.message}\n`;
|
||||
|
||||
cur = cur.cause instanceof Error ? cur.cause : null;
|
||||
if (cur) str += 'Caused by:\n';
|
||||
depth++;
|
||||
}
|
||||
|
||||
return str.trimEnd();
|
||||
if (process.env.NODE_ENV === 'development') console.error(this);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -131,6 +110,19 @@ export const isLocalStorageAvailable = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const getErrorOptions = (error: unknown): ErrorOptions | undefined => {
|
||||
if (!error || typeof error !== 'object') return undefined;
|
||||
|
||||
let cause: unknown;
|
||||
// @ts-expect-error it's not an error! just that project's ts version is old, which can't be upgraded
|
||||
if ('cause' in error) cause = error.cause;
|
||||
// @ts-expect-error it's not an error! just that project's ts version is old, which can't be upgraded
|
||||
else if ('stack' in error) cause = error.stack;
|
||||
|
||||
// @ts-expect-error it's not an error! just that project's ts version is old, which can't be upgraded
|
||||
return { cause };
|
||||
};
|
||||
|
||||
export const getErrorProperties = (
|
||||
error: unknown,
|
||||
message = 'Something went very wrong',
|
||||
@@ -138,4 +130,4 @@ export const getErrorProperties = (
|
||||
) => {
|
||||
if (error instanceof AppError) return error;
|
||||
return new AppError(message, statusCode, error);
|
||||
};
|
||||
};
|
Reference in New Issue
Block a user