mirror of
https://github.com/tapframe/NuvioStreaming.git
synced 2026-04-28 03:43:02 +00:00
perfomnce optimziations
This commit is contained in:
parent
6560f5a6a7
commit
02bfd85b5a
10 changed files with 142 additions and 369 deletions
8
App.tsx
8
App.tsx
|
|
@ -40,10 +40,10 @@ Sentry.init({
|
||||||
// For more information, visit: https://docs.sentry.io/platforms/react-native/data-management/data-collected/
|
// For more information, visit: https://docs.sentry.io/platforms/react-native/data-management/data-collected/
|
||||||
sendDefaultPii: true,
|
sendDefaultPii: true,
|
||||||
|
|
||||||
// Configure Session Replay
|
// Configure Session Replay conservatively to avoid startup overhead in production
|
||||||
replaysSessionSampleRate: 0.1,
|
replaysSessionSampleRate: __DEV__ ? 0.1 : 0,
|
||||||
replaysOnErrorSampleRate: 1,
|
replaysOnErrorSampleRate: __DEV__ ? 1 : 0,
|
||||||
integrations: [Sentry.mobileReplayIntegration(), Sentry.feedbackIntegration()],
|
integrations: [Sentry.feedbackIntegration()],
|
||||||
|
|
||||||
// uncomment the line below to enable Spotlight (https://spotlightjs.com)
|
// uncomment the line below to enable Spotlight (https://spotlightjs.com)
|
||||||
// spotlight: __DEV__,
|
// spotlight: __DEV__,
|
||||||
|
|
|
||||||
312
package-lock.json
generated
312
package-lock.json
generated
|
|
@ -22,7 +22,7 @@
|
||||||
"@react-navigation/native-stack": "^7.3.10",
|
"@react-navigation/native-stack": "^7.3.10",
|
||||||
"@react-navigation/stack": "^7.2.10",
|
"@react-navigation/stack": "^7.2.10",
|
||||||
"@sentry/react-native": "~6.10.0",
|
"@sentry/react-native": "~6.10.0",
|
||||||
"@shopify/flash-list": "1.7.3",
|
"@shopify/flash-list": "2.0.3",
|
||||||
"@supabase/supabase-js": "^2.54.0",
|
"@supabase/supabase-js": "^2.54.0",
|
||||||
"@types/lodash": "^4.17.16",
|
"@types/lodash": "^4.17.16",
|
||||||
"@types/react-native-video": "^5.0.20",
|
"@types/react-native-video": "^5.0.20",
|
||||||
|
|
@ -4204,108 +4204,6 @@
|
||||||
"node": ">=10"
|
"node": ">=10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@sentry/cli-linux-arm": {
|
|
||||||
"version": "2.42.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm/-/cli-linux-arm-2.42.4.tgz",
|
|
||||||
"integrity": "sha512-lBn0oeeg62h68/4Eo6zbPq99Idz5t0VRV48rEU/WKeM4MtQCvG/iGGQ3lBFW2yNiUBzXZIK9poXLEcgbwmcRVw==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux",
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/cli-linux-arm64": {
|
|
||||||
"version": "2.42.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-arm64/-/cli-linux-arm64-2.42.4.tgz",
|
|
||||||
"integrity": "sha512-Ex8vRnryyzC/9e43daEmEqPS+9uirY/l6Hw2lAvhBblFaL7PTWNx52H+8GnYGd9Zy2H3rWNyBDYfHwnErg38zA==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux",
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/cli-linux-i686": {
|
|
||||||
"version": "2.42.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-i686/-/cli-linux-i686-2.42.4.tgz",
|
|
||||||
"integrity": "sha512-IBJg0aHjsLCL4LvcFa3cXIjA+4t5kPqBT9y+PoDu4goIFxYD8zl7mbUdGJutvJafTk8Akf4ss4JJXQBjg019zA==",
|
|
||||||
"cpu": [
|
|
||||||
"x86",
|
|
||||||
"ia32"
|
|
||||||
],
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux",
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/cli-linux-x64": {
|
|
||||||
"version": "2.42.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/cli-linux-x64/-/cli-linux-x64-2.42.4.tgz",
|
|
||||||
"integrity": "sha512-gXI5OEiOSNiAEz7VCE6AZcAgHJ47mlgal3+NmbE8XcHmFOnyDws9FNie6PJAy8KZjXi3nqoBP9JVAbnmOix3uA==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux",
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/cli-win32-i686": {
|
|
||||||
"version": "2.42.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-i686/-/cli-win32-i686-2.42.4.tgz",
|
|
||||||
"integrity": "sha512-vZuR3UPHKqOMniyrijrrsNwn9usaRysXq78F6WV0cL0ZyPLAmY+KBnTDSFk1Oig2pURnzaTm+RtcZu2fc8mlzg==",
|
|
||||||
"cpu": [
|
|
||||||
"x86",
|
|
||||||
"ia32"
|
|
||||||
],
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/cli-win32-x64": {
|
|
||||||
"version": "2.42.4",
|
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/cli-win32-x64/-/cli-win32-x64-2.42.4.tgz",
|
|
||||||
"integrity": "sha512-OIBj3uaQ6nAERSm5Dcf8UIhyElEEwMNsZEEppQpN4IKl0mrwb/57AznM23Dvpu6GR8WGbVQUSolt879YZR5E9g==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "BSD-3-Clause",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">=10"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@sentry/core": {
|
"node_modules/@sentry/core": {
|
||||||
"version": "8.54.0",
|
"version": "8.54.0",
|
||||||
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@sentry/core/-/core-8.54.0.tgz",
|
||||||
|
|
@ -4385,12 +4283,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@shopify/flash-list": {
|
"node_modules/@shopify/flash-list": {
|
||||||
"version": "1.7.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-1.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/@shopify/flash-list/-/flash-list-2.0.3.tgz",
|
||||||
"integrity": "sha512-RLhNptm02aqpqZvjj9pJPcU+EVYxOAJhPRCmDOaUbUP86+636w+plsbjpBPSYGvPZhPj56RtZ9FBlvolPeEmYA==",
|
"integrity": "sha512-jUlHuZFoPdqRCDvOqsb2YkTttRPyV8Tb/EjCx3gE2wjr4UTM+fE0Ltv9bwBg0K7yo/SxRNXaW7xu5utusRb0xA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"recyclerlistview": "4.2.1",
|
|
||||||
"tslib": "2.8.1"
|
"tslib": "2.8.1"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
|
|
@ -9903,26 +9800,6 @@
|
||||||
"lightningcss-win32-x64-msvc": "1.27.0"
|
"lightningcss-win32-x64-msvc": "1.27.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lightningcss-darwin-arm64": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-Gl/lqIXY+d+ySmMbgDf0pgaWSqrWYxVHoc88q+Vhf2YNzZ8DwoRzGt5NZDVqqIW5ScpSnmmjcgXP87Dn2ylSSQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"darwin"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-darwin-x64": {
|
"node_modules/lightningcss-darwin-x64": {
|
||||||
"version": "1.27.0",
|
"version": "1.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz",
|
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.27.0.tgz",
|
||||||
|
|
@ -9943,166 +9820,6 @@
|
||||||
"url": "https://opencollective.com/parcel"
|
"url": "https://opencollective.com/parcel"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/lightningcss-freebsd-x64": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-n1sEf85fePoU2aDN2PzYjoI8gbBqnmLGEhKq7q0DKLj0UTVmOTwDC7PtLcy/zFxzASTSBlVQYJUhwIStQMIpRA==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"freebsd"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-MUMRmtdRkOkd5z3h986HOuNBD1c2lq2BSQA1Jg88d9I7bmPGx08bwGcnB75dvr17CwxjxD6XPi3Qh8ArmKFqCA==",
|
|
||||||
"cpu": [
|
|
||||||
"arm"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-arm64-gnu": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-cPsxo1QEWq2sfKkSq2Bq5feQDHdUEwgtA9KaB27J5AX22+l4l0ptgjMZZtYtUnteBofjee+0oW1wQ1guv04a7A==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-arm64-musl": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-rCGBm2ax7kQ9pBSeITfCW9XSVF69VX+fm5DIpvDZQl4NnQoMQyRwhZQm9pd59m8leZ1IesRqWk2v/DntMo26lg==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-x64-gnu": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-Dk/jovSI7qqhJDiUibvaikNKI2x6kWPN79AQiD/E/KeQWMjdGe9kw51RAgoWFDi0coP4jinaH14Nrt/J8z3U4A==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-linux-x64-musl": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-QKjTxXm8A9s6v9Tg3Fk0gscCQA1t/HMoF7Woy1u68wCk5kS4fR+q3vXa1p3++REW784cRAtkYKrPy6JKibrEZA==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"linux"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-win32-arm64-msvc": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-/wXegPS1hnhkeG4OXQKEMQeJd48RDC3qdh+OA8pCuOPCyvnm/yEayrJdJVqzBsqpy1aJklRCVxscpFur80o6iQ==",
|
|
||||||
"cpu": [
|
|
||||||
"arm64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lightningcss-win32-x64-msvc": {
|
|
||||||
"version": "1.27.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.27.0.tgz",
|
|
||||||
"integrity": "sha512-/OJLj94Zm/waZShL8nB5jsNj3CfNATLCTyFxZyouilfTmSoLDX7VlVAmhPHoZWVFp4vdmoiEbPEYC8HID3m6yw==",
|
|
||||||
"cpu": [
|
|
||||||
"x64"
|
|
||||||
],
|
|
||||||
"license": "MPL-2.0",
|
|
||||||
"optional": true,
|
|
||||||
"os": [
|
|
||||||
"win32"
|
|
||||||
],
|
|
||||||
"engines": {
|
|
||||||
"node": ">= 12.0.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/parcel"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/lines-and-columns": {
|
"node_modules/lines-and-columns": {
|
||||||
"version": "1.2.4",
|
"version": "1.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
||||||
|
|
@ -13048,21 +12765,6 @@
|
||||||
"node": ">= 4"
|
"node": ">= 4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/recyclerlistview": {
|
|
||||||
"version": "4.2.1",
|
|
||||||
"resolved": "https://registry.npmjs.org/recyclerlistview/-/recyclerlistview-4.2.1.tgz",
|
|
||||||
"integrity": "sha512-NtVYjofwgUCt1rEsTp6jHQg/47TWjnO92TU2kTVgJ9wsc/ely4HnizHHa+f/dI7qaw4+zcSogElrLjhMltN2/g==",
|
|
||||||
"license": "Apache-2.0",
|
|
||||||
"dependencies": {
|
|
||||||
"lodash.debounce": "4.0.8",
|
|
||||||
"prop-types": "15.8.1",
|
|
||||||
"ts-object-utils": "0.0.5"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": ">= 15.2.1",
|
|
||||||
"react-native": ">= 0.30.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/regenerate": {
|
"node_modules/regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||||
|
|
@ -14746,12 +14448,6 @@
|
||||||
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
"integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==",
|
||||||
"license": "Apache-2.0"
|
"license": "Apache-2.0"
|
||||||
},
|
},
|
||||||
"node_modules/ts-object-utils": {
|
|
||||||
"version": "0.0.5",
|
|
||||||
"resolved": "https://registry.npmjs.org/ts-object-utils/-/ts-object-utils-0.0.5.tgz",
|
|
||||||
"integrity": "sha512-iV0GvHqOmilbIKJsfyfJY9/dNHCs969z3so90dQWsO1eMMozvTpnB1MEaUbb3FYtZTGjv5sIy/xmslEz0Rg2TA==",
|
|
||||||
"license": "ISC"
|
|
||||||
},
|
|
||||||
"node_modules/tslib": {
|
"node_modules/tslib": {
|
||||||
"version": "2.8.1",
|
"version": "2.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@
|
||||||
"@react-navigation/native-stack": "^7.3.10",
|
"@react-navigation/native-stack": "^7.3.10",
|
||||||
"@react-navigation/stack": "^7.2.10",
|
"@react-navigation/stack": "^7.2.10",
|
||||||
"@sentry/react-native": "~6.10.0",
|
"@sentry/react-native": "~6.10.0",
|
||||||
"@shopify/flash-list": "1.7.3",
|
"@shopify/flash-list": "2.0.3",
|
||||||
"@supabase/supabase-js": "^2.54.0",
|
"@supabase/supabase-js": "^2.54.0",
|
||||||
"@types/lodash": "^4.17.16",
|
"@types/lodash": "^4.17.16",
|
||||||
"@types/react-native-video": "^5.0.20",
|
"@types/react-native-video": "^5.0.20",
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
import React, { useMemo, useState, useEffect, useCallback, memo } from 'react';
|
import React, { useMemo, useState, useEffect, useCallback, memo } from 'react';
|
||||||
import { View, Text, StyleSheet, Dimensions, TouchableOpacity, ViewStyle, TextStyle, ImageStyle, FlatList, StyleProp } from 'react-native';
|
import { View, Text, StyleSheet, Dimensions, TouchableOpacity, ViewStyle, TextStyle, ImageStyle, FlatList, StyleProp, Platform } from 'react-native';
|
||||||
import Animated, { FadeIn, FadeOut, Easing, useSharedValue, withTiming, useAnimatedStyle, useAnimatedScrollHandler, useAnimatedReaction, runOnJS } from 'react-native-reanimated';
|
import Animated, { FadeIn, FadeOut, Easing, useSharedValue, withTiming, useAnimatedStyle, useAnimatedScrollHandler, useAnimatedReaction, runOnJS } from 'react-native-reanimated';
|
||||||
import { LinearGradient } from 'expo-linear-gradient';
|
import { LinearGradient } from 'expo-linear-gradient';
|
||||||
import { Image as ExpoImage } from 'expo-image';
|
import { Image as ExpoImage } from 'expo-image';
|
||||||
|
|
@ -157,9 +157,9 @@ const HeroCarousel: React.FC<HeroCarouselProps> = ({ items, loading = false }) =
|
||||||
source={{ uri: item.banner || item.poster }}
|
source={{ uri: item.banner || item.poster }}
|
||||||
style={styles.backgroundImage as ImageStyle}
|
style={styles.backgroundImage as ImageStyle}
|
||||||
contentFit="cover"
|
contentFit="cover"
|
||||||
blurRadius={24}
|
blurRadius={Platform.OS === 'android' ? 12 : 20}
|
||||||
cachePolicy="memory-disk"
|
cachePolicy="memory-disk"
|
||||||
transition={300}
|
transition={200}
|
||||||
priority="high"
|
priority="high"
|
||||||
/>
|
/>
|
||||||
<LinearGradient
|
<LinearGradient
|
||||||
|
|
@ -223,10 +223,11 @@ const HeroCarousel: React.FC<HeroCarouselProps> = ({ items, loading = false }) =
|
||||||
decelerationRate="fast"
|
decelerationRate="fast"
|
||||||
contentContainerStyle={contentPadding}
|
contentContainerStyle={contentPadding}
|
||||||
onScroll={scrollHandler}
|
onScroll={scrollHandler}
|
||||||
scrollEventThrottle={16}
|
scrollEventThrottle={32}
|
||||||
initialNumToRender={3}
|
disableIntervalMomentum
|
||||||
|
initialNumToRender={2}
|
||||||
windowSize={3}
|
windowSize={3}
|
||||||
maxToRenderPerBatch={3}
|
maxToRenderPerBatch={2}
|
||||||
updateCellsBatchingPeriod={50}
|
updateCellsBatchingPeriod={50}
|
||||||
removeClippedSubviews
|
removeClippedSubviews
|
||||||
getItemLayout={getItemLayout}
|
getItemLayout={getItemLayout}
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
import React, { createContext, useContext, useEffect, useMemo, useState } from 'react';
|
||||||
|
import { InteractionManager } from 'react-native';
|
||||||
import accountService, { AuthUser } from '../services/AccountService';
|
import accountService, { AuthUser } from '../services/AccountService';
|
||||||
import supabase from '../services/supabaseClient';
|
import supabase from '../services/supabaseClient';
|
||||||
import syncService from '../services/SyncService';
|
import syncService from '../services/SyncService';
|
||||||
|
|
@ -20,19 +21,29 @@ export const AccountProvider: React.FC<{ children: React.ReactNode }> = ({ child
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// Initial session (load full profile)
|
// Initial session (load full profile)
|
||||||
(async () => {
|
// Defer heavy work until after initial interactions to reduce launch CPU spike
|
||||||
const u = await accountService.getCurrentUser();
|
const task = InteractionManager.runAfterInteractions(() => {
|
||||||
setUser(u);
|
(async () => {
|
||||||
setLoading(false);
|
const u = await accountService.getCurrentUser();
|
||||||
syncService.init();
|
setUser(u);
|
||||||
if (u) {
|
setLoading(false);
|
||||||
await syncService.migrateLocalScopeToUser();
|
// Stage sync operations to avoid blocking the JS thread
|
||||||
await syncService.subscribeRealtime();
|
syncService.init();
|
||||||
// Pull first to hydrate local state, then push to avoid wiping server with empty local
|
if (u) {
|
||||||
await syncService.fullPull();
|
try {
|
||||||
await syncService.fullPush();
|
await syncService.migrateLocalScopeToUser();
|
||||||
}
|
// Small yield to event loop
|
||||||
})();
|
await new Promise(resolve => setTimeout(resolve, 50));
|
||||||
|
await syncService.subscribeRealtime();
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 50));
|
||||||
|
// Pull first to hydrate local state, then push to avoid wiping server with empty local
|
||||||
|
await syncService.fullPull();
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 50));
|
||||||
|
await syncService.fullPush();
|
||||||
|
} catch {}
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
});
|
||||||
|
|
||||||
// Auth state listener
|
// Auth state listener
|
||||||
const { data: subscription } = supabase.auth.onAuthStateChange(async (_event, session) => {
|
const { data: subscription } = supabase.auth.onAuthStateChange(async (_event, session) => {
|
||||||
|
|
@ -51,6 +62,7 @@ export const AccountProvider: React.FC<{ children: React.ReactNode }> = ({ child
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
subscription.subscription.unsubscribe();
|
subscription.subscription.unsubscribe();
|
||||||
|
task.cancel();
|
||||||
};
|
};
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1141,20 +1141,24 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
const tmdbService = TMDBService.getInstance();
|
const tmdbService = TMDBService.getInstance();
|
||||||
const fetchedTmdbId = await tmdbService.extractTMDBIdFromStremioId(id);
|
const fetchedTmdbId = await tmdbService.extractTMDBIdFromStremioId(id);
|
||||||
if (fetchedTmdbId) {
|
if (fetchedTmdbId) {
|
||||||
|
console.log('[useMetadata] extracted TMDB id from content id', { id, fetchedTmdbId });
|
||||||
setTmdbId(fetchedTmdbId);
|
setTmdbId(fetchedTmdbId);
|
||||||
// Fetch certification
|
// Fetch certification
|
||||||
const certification = await tmdbService.getCertification(type, fetchedTmdbId);
|
const certification = await tmdbService.getCertification(type, fetchedTmdbId);
|
||||||
if (certification) {
|
if (certification) {
|
||||||
|
console.log('[useMetadata] fetched certification via TMDB id (extract path)', { type, fetchedTmdbId, certification });
|
||||||
setMetadata(prev => prev ? {
|
setMetadata(prev => prev ? {
|
||||||
...prev,
|
...prev,
|
||||||
certification
|
certification
|
||||||
} : null);
|
} : null);
|
||||||
|
} else {
|
||||||
|
console.warn('[useMetadata] certification not returned from TMDB (extract path)', { type, fetchedTmdbId });
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('Could not determine TMDB ID for recommendations.');
|
console.warn('[useMetadata] Could not determine TMDB ID for recommendations / certification', { id });
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching TMDB ID:', error);
|
console.error('[useMetadata] Error fetching TMDB ID (extract path):', error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -1164,6 +1168,7 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (tmdbId) {
|
if (tmdbId) {
|
||||||
|
console.log('[useMetadata] tmdbId available; loading recommendations and enabling certification checks', { tmdbId });
|
||||||
loadRecommendations();
|
loadRecommendations();
|
||||||
// Reset recommendations when tmdbId changes
|
// Reset recommendations when tmdbId changes
|
||||||
return () => {
|
return () => {
|
||||||
|
|
@ -1173,6 +1178,37 @@ export const useMetadata = ({ id, type, addonId }: UseMetadataProps): UseMetadat
|
||||||
}
|
}
|
||||||
}, [tmdbId, loadRecommendations]);
|
}, [tmdbId, loadRecommendations]);
|
||||||
|
|
||||||
|
// Ensure certification is attached whenever a TMDB id is known and metadata lacks it
|
||||||
|
useEffect(() => {
|
||||||
|
const maybeAttachCertification = async () => {
|
||||||
|
try {
|
||||||
|
if (!metadata) {
|
||||||
|
console.warn('[useMetadata] skip certification attach: metadata not ready');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!tmdbId) {
|
||||||
|
console.warn('[useMetadata] skip certification attach: tmdbId not available yet');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if ((metadata as any).certification) {
|
||||||
|
console.log('[useMetadata] certification already present on metadata; skipping fetch');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tmdbSvc = TMDBService.getInstance();
|
||||||
|
const cert = await tmdbSvc.getCertification(type, tmdbId);
|
||||||
|
if (cert) {
|
||||||
|
console.log('[useMetadata] fetched certification (attach path)', { type, tmdbId, cert });
|
||||||
|
setMetadata(prev => prev ? { ...prev, certification: cert } : prev);
|
||||||
|
} else {
|
||||||
|
console.warn('[useMetadata] TMDB returned no certification (attach path)', { type, tmdbId });
|
||||||
|
}
|
||||||
|
} catch (err) {
|
||||||
|
console.error('[useMetadata] error attaching certification', err);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
maybeAttachCertification();
|
||||||
|
}, [tmdbId, metadata, type]);
|
||||||
|
|
||||||
// Reset tmdbId when id changes
|
// Reset tmdbId when id changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setTmdbId(null);
|
setTmdbId(null);
|
||||||
|
|
|
||||||
|
|
@ -718,7 +718,10 @@ const MainTabs = () => {
|
||||||
elevation: 0,
|
elevation: 0,
|
||||||
backgroundColor: currentTheme.colors.darkBackground,
|
backgroundColor: currentTheme.colors.darkBackground,
|
||||||
},
|
},
|
||||||
detachInactiveScreens: false,
|
// Ensure background tabs are frozen and detached
|
||||||
|
freezeOnBlur: true,
|
||||||
|
lazy: true,
|
||||||
|
detachInactiveScreens: true,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<Tab.Screen
|
<Tab.Screen
|
||||||
|
|
@ -926,6 +929,8 @@ const InnerNavigator = ({ initialRouteName }: { initialRouteName?: keyof RootSta
|
||||||
contentStyle: {
|
contentStyle: {
|
||||||
backgroundColor: currentTheme.colors.darkBackground,
|
backgroundColor: currentTheme.colors.darkBackground,
|
||||||
},
|
},
|
||||||
|
// Freeze when blurred to stop timers/network without full unmount
|
||||||
|
freezeOnBlur: true,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
|
|
@ -948,6 +953,8 @@ const InnerNavigator = ({ initialRouteName }: { initialRouteName?: keyof RootSta
|
||||||
statusBarHidden: true,
|
statusBarHidden: true,
|
||||||
statusBarAnimation: 'none',
|
statusBarAnimation: 'none',
|
||||||
}),
|
}),
|
||||||
|
// Freeze when blurred to release resources safely
|
||||||
|
freezeOnBlur: true,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<Stack.Screen
|
<Stack.Screen
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ const HomeScreen = () => {
|
||||||
let catalogIndex = 0;
|
let catalogIndex = 0;
|
||||||
|
|
||||||
// Limit concurrent catalog loading to prevent overwhelming the system
|
// Limit concurrent catalog loading to prevent overwhelming the system
|
||||||
const MAX_CONCURRENT_CATALOGS = 5;
|
const MAX_CONCURRENT_CATALOGS = 3; // Lower concurrency to reduce CPU/network spikes
|
||||||
let activeCatalogLoads = 0;
|
let activeCatalogLoads = 0;
|
||||||
const catalogQueue: (() => Promise<void>)[] = [];
|
const catalogQueue: (() => Promise<void>)[] = [];
|
||||||
|
|
||||||
|
|
@ -167,8 +167,10 @@ const HomeScreen = () => {
|
||||||
const catalogLoader = catalogQueue.shift();
|
const catalogLoader = catalogQueue.shift();
|
||||||
if (catalogLoader) {
|
if (catalogLoader) {
|
||||||
activeCatalogLoads++;
|
activeCatalogLoads++;
|
||||||
catalogLoader().finally(() => {
|
catalogLoader().finally(async () => {
|
||||||
activeCatalogLoads--;
|
activeCatalogLoads--;
|
||||||
|
// Yield to event loop to avoid JS thread starvation
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 10));
|
||||||
processCatalogQueue(); // Process next in queue
|
processCatalogQueue(); // Process next in queue
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -767,7 +769,6 @@ const HomeScreen = () => {
|
||||||
onEndReached={handleLoadMoreCatalogs}
|
onEndReached={handleLoadMoreCatalogs}
|
||||||
onEndReachedThreshold={0.6}
|
onEndReachedThreshold={0.6}
|
||||||
scrollEventThrottle={32}
|
scrollEventThrottle={32}
|
||||||
estimatedItemSize={220}
|
|
||||||
onScroll={event => {
|
onScroll={event => {
|
||||||
const y = event.nativeEvent.contentOffset.y;
|
const y = event.nativeEvent.contentOffset.y;
|
||||||
const dy = y - lastScrollYRef.current;
|
const dy = y - lastScrollYRef.current;
|
||||||
|
|
|
||||||
|
|
@ -111,14 +111,17 @@ const MetadataScreen: React.FC = () => {
|
||||||
|
|
||||||
// Extract dominant color from hero image for dynamic background
|
// Extract dominant color from hero image for dynamic background
|
||||||
const heroImageUri = useMemo(() => {
|
const heroImageUri = useMemo(() => {
|
||||||
|
if (!settings.useDominantBackgroundColor) return null;
|
||||||
if (!metadata) return null;
|
if (!metadata) return null;
|
||||||
return assetData.bannerImage || metadata.banner || metadata.poster || null;
|
return assetData.bannerImage || metadata.banner || metadata.poster || null;
|
||||||
}, [metadata, assetData.bannerImage]);
|
}, [settings.useDominantBackgroundColor, metadata, assetData.bannerImage]);
|
||||||
|
|
||||||
// Preload color extraction as soon as we have the URI
|
// Preload color extraction as soon as we have the URI
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (heroImageUri) {
|
if (heroImageUri) {
|
||||||
preloadDominantColor(heroImageUri);
|
InteractionManager.runAfterInteractions(() => {
|
||||||
|
preloadDominantColor(heroImageUri);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}, [heroImageUri]);
|
}, [heroImageUri]);
|
||||||
|
|
||||||
|
|
@ -188,7 +191,7 @@ const MetadataScreen: React.FC = () => {
|
||||||
|
|
||||||
// Debug logging for color extraction timing
|
// Debug logging for color extraction timing
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (heroImageUri && dominantColor) {
|
if (__DEV__ && heroImageUri && dominantColor) {
|
||||||
console.log('[MetadataScreen] Dynamic background color:', {
|
console.log('[MetadataScreen] Dynamic background color:', {
|
||||||
dominantColor,
|
dominantColor,
|
||||||
fallback: currentTheme.colors.darkBackground,
|
fallback: currentTheme.colors.darkBackground,
|
||||||
|
|
@ -266,7 +269,7 @@ const MetadataScreen: React.FC = () => {
|
||||||
if (relevantProgress.length === 0) return;
|
if (relevantProgress.length === 0) return;
|
||||||
|
|
||||||
// Log only essential progress information for performance
|
// Log only essential progress information for performance
|
||||||
console.log(`[MetadataScreen] Found ${relevantProgress.length} Trakt progress items for ${type}`);
|
if (__DEV__) console.log(`[MetadataScreen] Found ${relevantProgress.length} Trakt progress items for ${type}`);
|
||||||
|
|
||||||
// Find most recent progress if multiple episodes
|
// Find most recent progress if multiple episodes
|
||||||
if (type === 'series' && relevantProgress.length > 1) {
|
if (type === 'series' && relevantProgress.length > 1) {
|
||||||
|
|
@ -275,7 +278,7 @@ const MetadataScreen: React.FC = () => {
|
||||||
)[0];
|
)[0];
|
||||||
|
|
||||||
if (mostRecent.episode && mostRecent.show) {
|
if (mostRecent.episode && mostRecent.show) {
|
||||||
console.log(`[MetadataScreen] Most recent: S${mostRecent.episode.season}E${mostRecent.episode.number} - ${mostRecent.progress.toFixed(1)}%`);
|
if (__DEV__) console.log(`[MetadataScreen] Most recent: S${mostRecent.episode.season}E${mostRecent.episode.number} - ${mostRecent.progress.toFixed(1)}%`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -396,7 +399,7 @@ const MetadataScreen: React.FC = () => {
|
||||||
// DIRECT APPROACH: Just create the next episode ID directly
|
// DIRECT APPROACH: Just create the next episode ID directly
|
||||||
// This ensures we navigate to the next episode even if it's not yet in our episodes array
|
// This ensures we navigate to the next episode even if it's not yet in our episodes array
|
||||||
const nextEpisodeId = `${id}:${currentSeason}:${currentEpisode + 1}`;
|
const nextEpisodeId = `${id}:${currentSeason}:${currentEpisode + 1}`;
|
||||||
console.log(`[MetadataScreen] Created next episode ID directly: ${nextEpisodeId}`);
|
if (__DEV__) console.log(`[MetadataScreen] Created next episode ID directly: ${nextEpisodeId}`);
|
||||||
|
|
||||||
// Still try to find the episode in our list to verify it exists
|
// Still try to find the episode in our list to verify it exists
|
||||||
const nextEpisodeExists = episodes.some(ep =>
|
const nextEpisodeExists = episodes.some(ep =>
|
||||||
|
|
@ -404,9 +407,9 @@ const MetadataScreen: React.FC = () => {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (nextEpisodeExists) {
|
if (nextEpisodeExists) {
|
||||||
console.log(`[MetadataScreen] Verified next episode S${currentSeason}E${currentEpisode + 1} exists in episodes list`);
|
if (__DEV__) console.log(`[MetadataScreen] Verified next episode S${currentSeason}E${currentEpisode + 1} exists in episodes list`);
|
||||||
} else {
|
} else {
|
||||||
console.log(`[MetadataScreen] Warning: Next episode S${currentSeason}E${currentEpisode + 1} not found in episodes list, but proceeding anyway`);
|
if (__DEV__) console.log(`[MetadataScreen] Warning: Next episode S${currentSeason}E${currentEpisode + 1} not found in episodes list, but proceeding anyway`);
|
||||||
}
|
}
|
||||||
|
|
||||||
targetEpisodeId = nextEpisodeId;
|
targetEpisodeId = nextEpisodeId;
|
||||||
|
|
@ -416,7 +419,7 @@ const MetadataScreen: React.FC = () => {
|
||||||
// Fallback logic: if not finished or nextEp not found
|
// Fallback logic: if not finished or nextEp not found
|
||||||
if (!targetEpisodeId) {
|
if (!targetEpisodeId) {
|
||||||
targetEpisodeId = watchProgress?.episodeId || episodeId || (episodes.length > 0 ? buildEpisodeId(episodes[0]) : undefined);
|
targetEpisodeId = watchProgress?.episodeId || episodeId || (episodes.length > 0 ? buildEpisodeId(episodes[0]) : undefined);
|
||||||
console.log(`[MetadataScreen] Using fallback episode ID: ${targetEpisodeId}`);
|
if (__DEV__) console.log(`[MetadataScreen] Using fallback episode ID: ${targetEpisodeId}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (targetEpisodeId) {
|
if (targetEpisodeId) {
|
||||||
|
|
@ -426,7 +429,7 @@ const MetadataScreen: React.FC = () => {
|
||||||
if (epParts.length === 2) {
|
if (epParts.length === 2) {
|
||||||
normalizedEpisodeId = `${id}:${epParts[0]}:${epParts[1]}`;
|
normalizedEpisodeId = `${id}:${epParts[0]}:${epParts[1]}`;
|
||||||
}
|
}
|
||||||
console.log(`[MetadataScreen] Navigating to streams with episodeId: ${normalizedEpisodeId}`);
|
if (__DEV__) console.log(`[MetadataScreen] Navigating to streams with episodeId: ${normalizedEpisodeId}`);
|
||||||
navigation.navigate('Streams', { id, type, episodeId: normalizedEpisodeId });
|
navigation.navigate('Streams', { id, type, episodeId: normalizedEpisodeId });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -438,7 +441,7 @@ const MetadataScreen: React.FC = () => {
|
||||||
const p = episodeId.split(':');
|
const p = episodeId.split(':');
|
||||||
fallbackEpisodeId = `${id}:${p[0]}:${p[1]}`;
|
fallbackEpisodeId = `${id}:${p[0]}:${p[1]}`;
|
||||||
}
|
}
|
||||||
console.log(`[MetadataScreen] Navigating with fallback episodeId: ${fallbackEpisodeId}`);
|
if (__DEV__) console.log(`[MetadataScreen] Navigating with fallback episodeId: ${fallbackEpisodeId}`);
|
||||||
navigation.navigate('Streams', { id, type, episodeId: fallbackEpisodeId });
|
navigation.navigate('Streams', { id, type, episodeId: fallbackEpisodeId });
|
||||||
}, [navigation, id, type, episodes, episodeId, watchProgressData.watchProgress]);
|
}, [navigation, id, type, episodes, episodeId, watchProgressData.watchProgress]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -816,30 +816,47 @@ export class TMDBService {
|
||||||
*/
|
*/
|
||||||
async getCertification(type: string, id: number): Promise<string | null> {
|
async getCertification(type: string, id: number): Promise<string | null> {
|
||||||
try {
|
try {
|
||||||
// Different endpoints for movies and TV shows
|
if (type === 'movie') {
|
||||||
const endpoint = type === 'movie' ? 'movie' : 'tv';
|
const response = await axios.get(`${BASE_URL}/movie/${id}/release_dates`, {
|
||||||
const response = await axios.get(`${BASE_URL}/${endpoint}/${id}/release_dates`, {
|
headers: await this.getHeaders(),
|
||||||
headers: await this.getHeaders(),
|
params: await this.getParams()
|
||||||
params: await this.getParams()
|
});
|
||||||
});
|
|
||||||
|
|
||||||
if (response.data && response.data.results) {
|
if (response.data && response.data.results) {
|
||||||
// Try to find US certification first
|
// Prefer US, then GB, then any
|
||||||
const usRelease = response.data.results.find((r: any) => r.iso_3166_1 === 'US');
|
const countryPriority = ['US', 'GB'];
|
||||||
if (usRelease && usRelease.release_dates && usRelease.release_dates.length > 0) {
|
for (const code of countryPriority) {
|
||||||
const certification = usRelease.release_dates.find((rd: any) => rd.certification)?.certification;
|
const rel = response.data.results.find((r: any) => r.iso_3166_1 === code);
|
||||||
if (certification) return certification;
|
if (rel?.release_dates?.length) {
|
||||||
}
|
const cert = rel.release_dates.find((rd: any) => rd.certification)?.certification;
|
||||||
|
if (cert) return cert;
|
||||||
// Fallback to any certification if US is not available
|
}
|
||||||
for (const country of response.data.results) {
|
}
|
||||||
if (country.release_dates && country.release_dates.length > 0) {
|
for (const country of response.data.results) {
|
||||||
const certification = country.release_dates.find((rd: any) => rd.certification)?.certification;
|
const cert = country.release_dates?.find((rd: any) => rd.certification)?.certification;
|
||||||
if (certification) return certification;
|
if (cert) return cert;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return null;
|
||||||
|
} else {
|
||||||
|
// TV uses content ratings endpoint, not release_dates
|
||||||
|
const response = await axios.get(`${BASE_URL}/tv/${id}/content_ratings`, {
|
||||||
|
headers: await this.getHeaders(),
|
||||||
|
params: await this.getParams()
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.data && response.data.results) {
|
||||||
|
// Prefer US, then GB, then any
|
||||||
|
const countryPriority = ['US', 'GB'];
|
||||||
|
for (const code of countryPriority) {
|
||||||
|
const rating = response.data.results.find((r: any) => r.iso_3166_1 === code);
|
||||||
|
if (rating?.rating) return rating.rating;
|
||||||
|
}
|
||||||
|
const any = response.data.results.find((r: any) => !!r.rating);
|
||||||
|
if (any?.rating) return any.rating;
|
||||||
|
}
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
return null;
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue