1661 Commits

Author SHA1 Message Date
11c300ecf7 Add status api to get scanner's status (#1195) 2025-12-01 20:18:21 +01:00
1e975ce238 Set null not distinct in scanner request constraint 2025-12-01 20:15:57 +01:00
b39fa4262d Add status api to get scanner's status 2025-12-01 20:04:16 +01:00
d7699389bc Fix missing kid in apikeys jwt 2025-12-01 20:04:16 +01:00
renovate[bot]
1036e9f3f3 chore(deps): update dependency @biomejs/biome to v2.3.7 (#1189)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 10:36:11 +01:00
renovate[bot]
b4749f3ed3 fix(deps): update aws-sdk-go-v2 monorepo (#1191)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 10:34:25 +01:00
renovate[bot]
a20c61206f fix(deps): update module github.com/labstack/echo-jwt/v4 to v4.4.0 (#1192)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 10:34:14 +01:00
renovate[bot]
0644a43cb1 chore(deps): update actions/checkout action to v6 (#1193)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-12-01 10:34:05 +01:00
af4742ae0b Fix sqlarr of api (#1188) 2025-11-30 19:29:46 +00:00
acelinkio
e401ca98c0 downgrade cloudpirates postgres 0.12.0 (#1187) 2025-11-28 13:15:55 -08:00
Arlan Lloyd
a756c875fd 0.12.1 has a bug with rendering nested values 2025-11-28 21:13:10 +00:00
acelinkio
2ef26e5d02 add devspace (#1173) 2025-11-28 20:52:10 +01:00
acelinkio
e7d9002156 kyoo_api logs redact password & other sensitive fields (#1182) 2025-11-28 16:42:27 +00:00
acelinkio
28d2e193aa kyoo_api extension install specify schema (#1183) 2025-11-28 16:39:47 +00:00
ce5bee11c0 Use unnest in insertion methods (#1185) 2025-11-28 17:28:11 +01:00
60d59d7f7b Wrap every insert with a trace 2025-11-28 17:25:29 +01:00
464d720ef9 Fix unnest issues 2025-11-28 17:11:43 +01:00
8fc279d2ed Use unnest everywhere 2025-11-28 17:11:43 +01:00
a45e992339 Properly type unnestValues return 2025-11-28 17:11:43 +01:00
5f8ddd435a Use unnest for entries 2025-11-28 17:11:43 +01:00
d822463fe0 Add a trace for api migrations 2025-11-28 17:11:43 +01:00
acelinkio
3a0cbf786d fix(deps): update aws-sdk-go-v2 monorepo (#1159) 2025-11-24 13:12:25 -08:00
renovate[bot]
dfb4777a5d fix(deps): update aws-sdk-go-v2 monorepo 2025-11-24 20:29:44 +00:00
acelinkio
eea32c47e9 chore(deps): update postgres docker tag to v0.12.1 (#1181) 2025-11-24 09:49:58 -08:00
renovate[bot]
6bcd03b18e chore(deps): update postgres docker tag to v0.12.1 2025-11-24 13:46:46 +00:00
acelinkio
87a3df6897 chore(deps): update dependency @biomejs/biome to v2.3.6 (#1179) 2025-11-23 18:38:41 -08:00
acelinkio
7f7a16e9b5 chore(deps): update postgres docker tag to v0.12.0 (#1180) 2025-11-23 18:38:17 -08:00
renovate[bot]
b95dd9056b chore(deps): update postgres docker tag to v0.12.0 2025-11-24 02:22:25 +00:00
renovate[bot]
5044f941b1 chore(deps): update dependency @biomejs/biome to v2.3.6 2025-11-24 02:08:06 +00:00
c56f9ea791 Remove identify traces (#1178) 2025-11-23 23:55:23 +01:00
eb56dd70d6 Batch images task insertion and add priority (#1177) 2025-11-23 23:22:01 +01:00
a4f5ef33ff Fix deadlock on image downloading 2025-11-23 23:20:40 +01:00
20ab1dae6c Force tests to run on kyoo_test database 2025-11-23 23:16:58 +01:00
7ebc0fe504 Fix type issues 2025-11-23 22:44:59 +01:00
019aceb8d9 Batch images task insertion and add priority 2025-11-23 22:44:59 +01:00
f59cb5d671 Properly handle spans of image downloading (#1176) 2025-11-23 19:00:54 +01:00
d4deafe1dc Forward X-Forward-Host & proto headers in traefik 2025-11-23 18:58:19 +01:00
7b2f1c7a82 Fix image test in github 2025-11-23 18:06:55 +01:00
c5fa3ecb01 Cleanup scanner processing span 2025-11-23 17:49:23 +01:00
3602905e86 Properly handle spans of image downloading 2025-11-23 17:49:23 +01:00
1f7844b8a5 Fix api images path (#1175) 2025-11-23 14:57:07 +01:00
Jory Irving
3b76fb2647 Allow manual helm chart publishing for specific tags (#1174) 2025-11-23 13:24:14 +01:00
acelinkio
9a00d5036f Bump golang.org/x/crypto from 0.44.0 to 0.45.0 in /transcoder (#1171) 2025-11-21 09:34:30 -08:00
dependabot[bot]
7c315602cd Bump golang.org/x/crypto from 0.44.0 to 0.45.0 in /transcoder
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.44.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.44.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-21 17:03:04 +00:00
acelinkio
19e0e402da Bump golang.org/x/crypto from 0.43.0 to 0.45.0 in /auth (#1168) 2025-11-21 09:02:35 -08:00
acelinkio
ef38468178 chore(deps): update dependency @biomejs/biome to v2.3.5 (#1157) 2025-11-21 09:02:17 -08:00
2cbbb450c2 Lock scanner processing to a single runner (#1170) 2025-11-20 12:13:34 +01:00
9f466ff702 Update elysia otel plugin 2025-11-20 12:12:01 +01:00
05f7fabb3c Lock scanner processing to a single runner 2025-11-20 12:12:01 +01:00
5bc6a06b91 Chunk identify scans (#1169) 2025-11-20 09:46:49 +01:00
f7e801e574 Chunk identify scans 2025-11-20 09:44:00 +01:00
dependabot[bot]
c663189df1 Bump golang.org/x/crypto from 0.43.0 to 0.45.0 in /auth
Bumps [golang.org/x/crypto](https://github.com/golang/crypto) from 0.43.0 to 0.45.0.
- [Commits](https://github.com/golang/crypto/compare/v0.43.0...v0.45.0)

---
updated-dependencies:
- dependency-name: golang.org/x/crypto
  dependency-version: 0.45.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-11-20 02:45:53 +00:00
37ec32b52d Name migrate span of scanner 2025-11-20 00:03:24 +01:00
188ce3f67d Log to stdout & otel for scanner 2025-11-19 23:59:08 +01:00
18b2ae2c5f Remove name prefix in apikeys (#1167) 2025-11-19 23:29:31 +01:00
a115c83cba Make scanner ready check a noop (#1166) 2025-11-19 20:49:42 +01:00
27d25f4829 Fix transcoder service name in otel (#1165) 2025-11-19 19:27:50 +00:00
acelinkio
d1d6fa9556 docs: change logo to use google source (#1164) 2025-11-19 10:09:03 -08:00
Arlan Lloyd
7878673d8d change logo to use google source 2025-11-19 18:07:09 +00:00
34761b43ae Fix need rendering compute on videos slug (#1163) 2025-11-19 16:28:47 +00:00
acelinkio
536b03b1ef chart: update docs (#1162) 2025-11-18 14:22:53 -08:00
acelinkio
6f37c128ef Merge branch 'master' into chart/update_notes 2025-11-18 14:21:51 -08:00
Arlan Lloyd
8e3a582f75 update docs 2025-11-18 22:20:32 +00:00
acelinkio
b5720dca06 update diagrams for v5 (#1156) 2025-11-18 10:11:51 -08:00
Arlan Lloyd
df26dbca63 update SSR notes + api downloads media images 2025-11-18 18:10:13 +00:00
acelinkio
851ae9eb9d Merge branch 'master' into update_diagrams 2025-11-18 09:37:45 -08:00
Arlan Lloyd
8aaf786400 update metadata storage + scanner docs 2025-11-18 16:04:18 +00:00
3e40842c84 Setup otel & export traces for all services (#1161) 2025-11-17 23:38:30 +01:00
8ab4146241 Fix format 2025-11-17 23:20:09 +01:00
0fa25eaeca Use my work of drizzle-otel to properly instrument db errors 2025-11-17 23:07:59 +01:00
2194831d86 Manually instrument scanner 2025-11-17 23:07:59 +01:00
7124a3d3c6 Instrument scanner 2025-11-17 23:07:59 +01:00
55a22f1c9e Instrument pgx 2025-11-17 23:07:54 +01:00
6d58164a6d Instrument auth's echo 2025-11-17 23:03:49 +01:00
fea9c16515 Instrument drizzle 2025-11-17 23:03:49 +01:00
01883d08cc Instrument elyzia 2025-11-17 23:03:49 +01:00
acelinkio
03792487c3 chore(deps): update postgres docker tag to v0.11.6 (#1158) 2025-11-17 07:50:27 -08:00
renovate[bot]
87a0fa39f7 chore(deps): update postgres docker tag to v0.11.6 2025-11-17 15:03:19 +00:00
renovate[bot]
64dae6ddce chore(deps): update dependency @biomejs/biome to v2.3.5 2025-11-17 01:48:59 +00:00
Arlan Lloyd
efec489c96 update diagrams for v5 2025-11-15 20:11:24 +00:00
Arlan Lloyd
5837b9875d update project structure 2025-11-14 16:46:51 +00:00
1e1a6a1159 chart: v5 update (#884) 2025-11-14 09:41:09 +01:00
5e63b57440 Fix pagination URLs when behind SSL-terminating reverse proxy 2025-11-13 14:04:05 +01:00
Arlan Lloyd
befc0fc84f update sslmode default for kyoo_api 2025-11-12 23:41:40 +00:00
Arlan Lloyd
9bbdb3d7f0 add way to specify shared database 2025-11-12 06:50:52 +00:00
Arlan Lloyd
58690eb428 copy default claims from .env 2025-11-11 15:29:32 +00:00
Arlan Lloyd
7d47b7642c add sslmode to api/scanner & fix default for transcoder 2025-11-10 19:11:33 +00:00
Arlan Lloyd
2f3682c226 remove unneeded comment 2025-11-10 18:49:32 +00:00
Arlan Lloyd
d952444919 fix scanner claims 2025-11-10 17:13:45 +00:00
Arlan Lloyd
86cb391425 add interpolation to handle apikey concatination 2025-11-10 16:01:08 +00:00
Arlan Lloyd
ed6623293b fix probe locations 2025-11-10 15:27:58 +00:00
Arlan Lloyd
7a756dd67c remove test manifest 2025-11-10 14:28:16 +00:00
Arlan Lloyd
e71640a636 remove test values 2025-11-10 14:26:47 +00:00
renovate[bot]
f4b1ab5fa0 Update dependency @biomejs/biome to v2.3.4 (#1152)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 11:11:34 +01:00
renovate[bot]
90475e47b1 Update aws-sdk-go-v2 monorepo (#1137)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 09:49:56 +00:00
renovate[bot]
c32b58e974 Update dependency @biomejs/biome to v2.3.3 (#1148)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 10:38:15 +01:00
renovate[bot]
211f75f71a Update dependency go to v1.25.4 (#1149)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 10:38:07 +01:00
renovate[bot]
f0b9f3afdc Update module github.com/asticode/go-astisub to v0.38.0 (#1124)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 10:37:51 +01:00
renovate[bot]
6bc041723e Update module golang.org/x/sync to v0.18.0 (#1151)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-10 10:37:39 +01:00
Arlan Lloyd
82ea4fbe0b move oidc vars 2025-11-10 04:44:19 +00:00
Arlan Lloyd
1749dc814b add postgres extension + config 2025-11-10 04:35:50 +00:00
Arlan Lloyd
dfc886127a update schema configs 2025-11-10 04:30:12 +00:00
Arlan Lloyd
4943c94182 remove swagger middleware 2025-11-10 04:21:09 +00:00
Arlan Lloyd
238702f81c add probes 2025-11-10 03:59:53 +00:00
Antoine Labarussias
c60abb26f9 fix(chart): send cookie header to middleware 2025-11-09 20:13:20 +01:00
Antoine Labarussias
2fb393bb45 fix(chart): update transcoder pg env vars 2025-11-09 20:13:20 +01:00
Antoine Labarussias
6bab124331 fix(chart): set existingSecret to null 2025-11-09 20:13:20 +01:00
Antoine Labarussias
9c57e01426 feat(chart): add auth private key 2025-11-09 20:13:20 +01:00
Arlan Lloyd
66dedaee29 update apikey format to $name-$key 2025-11-09 20:13:20 +01:00
Arlan Lloyd
eb31c0d8e6 add in scanner & extra apikey support 2025-11-09 20:13:20 +01:00
Arlan Lloyd
cd65632527 allow for specifying middleware proxy root url 2025-11-09 20:13:20 +01:00
Arlan Lloyd
a563d8f8ba update docs 2025-11-09 20:13:20 +01:00
Arlan Lloyd
60082ee799 remove apikey reference 2025-11-09 20:13:20 +01:00
Arlan Lloyd
6065b73d13 fix port metadata 2025-11-09 20:13:20 +01:00
Arlan Lloyd
32a9dfc11c fix middleware 2025-11-09 20:13:20 +01:00
Arlan Lloyd
57c135c86b set traefik args via extraArgs 2025-11-09 20:13:20 +01:00
Arlan Lloyd
5064111a93 update traefik configs 2025-11-09 20:13:20 +01:00
Arlan Lloyd
de718b6a46 update scanner settings 2025-11-09 20:13:20 +01:00
Arlan Lloyd
d7748eb83e remove specifying auth schema and rsa 2025-11-09 20:13:20 +01:00
Arlan Lloyd
d730b5f3f4 specify traefik repo/version 2025-11-09 20:13:20 +01:00
Arlan Lloyd
5d17f8f0f9 fix subchart settings/notes 2025-11-09 20:13:20 +01:00
Arlan Lloyd
864ee3efa2 add explicit namespace 2025-11-09 20:13:20 +01:00
Arlan Lloyd
a14a0145a9 update transcoder env 2025-11-09 20:13:20 +01:00
Arlan Lloyd
a86c361825 fix api port 2025-11-09 20:13:20 +01:00
Arlan Lloyd
e17e969bfe fix scanner envs 2025-11-09 20:13:20 +01:00
Arlan Lloyd
4708186f5c update api env vars 2025-11-09 20:13:20 +01:00
Arlan Lloyd
6238c8d9a0 fix default address 2025-11-09 20:13:20 +01:00
Arlan Lloyd
7a34bbedae fix readme 2025-11-09 20:13:20 +01:00
Arlan Lloyd
e59477eddd finish renaming kyoo_back to kyoo_api 2025-11-09 20:13:20 +01:00
Arlan Lloyd
7368af7266 rename back to api 2025-11-09 20:13:20 +01:00
Arlan Lloyd
9c03f99524 move to cloudpirates postgres 2025-11-09 20:13:19 +01:00
Arlan Lloyd
54d4965a9a purge old infra var 2025-11-09 20:13:18 +01:00
Arlan Lloyd
dc7d6919da purge kyoo_migrations, no longer needed 2025-11-09 20:13:18 +01:00
Arlan Lloyd
aa180bfcea purge autosync! 2025-11-09 20:13:18 +01:00
Arlan Lloyd
5ab28622d9 purge rabbitmq 2025-11-09 20:13:17 +01:00
Arlan Lloyd
7f97ea6e90 purge meilisearch from chart 2025-11-09 20:13:14 +01:00
Arlan Lloyd
869b0206b8 purge matcher specific settings 2025-11-09 20:13:14 +01:00
Arlan Lloyd
159a4cc77a prepare ingress to traefikproxy 2025-11-09 20:13:14 +01:00
Arlan Lloyd
571590a40d update variables 2025-11-09 20:13:13 +01:00
Arlan Lloyd
0943401d03 initial add of auth 2025-11-09 20:13:13 +01:00
Arlan Lloyd
ababb67b1a update traefik configs 2025-11-09 20:13:13 +01:00
Arlan Lloyd
5bf4d70623 traefik update services configs 2025-11-09 20:13:13 +01:00
Arlan Lloyd
c495589927 use short names 2025-11-09 20:13:13 +01:00
Arlan Lloyd
5e20257202 fix middleware name 2025-11-09 20:13:13 +01:00
Arlan Lloyd
e8154c31ce update ForwardAuth docs 2025-11-09 20:13:13 +01:00
Arlan Lloyd
b1d8d00a9b update 2025-11-09 20:13:13 +01:00
Arlan Lloyd
c5c0de5493 configure defaultConfigmap 2025-11-09 20:13:13 +01:00
Arlan Lloyd
cfafe12c82 add conditional enable 2025-11-09 20:13:13 +01:00
Arlan Lloyd
594e0233ca fix template 2025-11-09 20:13:13 +01:00
Arlan Lloyd
63c5b40123 initial add Traefik
Signed-off-by: Arlan Lloyd <arlanlloyd@gmail.com>
2025-11-09 20:13:13 +01:00
1caff13adc Add /health & /ready for every service (#1147) 2025-11-09 20:12:36 +01:00
b4c85f3f28 Add /health and /ready for scanner 2025-11-09 19:58:41 +01:00
a95bbcb6eb Fix last_seen update on auth 2025-11-09 19:58:41 +01:00
61b38d5b03 Add /ready for api 2025-11-09 19:25:08 +01:00
563ae85db1 Add /health and /ready for transcoder 2025-11-09 19:21:29 +01:00
8f0fb42b47 Add /ready api to auth 2025-11-09 19:21:29 +01:00
40c13e7ddf Cleanup casing in api extension setup 2025-11-09 19:21:29 +01:00
0a862c3782 Remove phantom token middleware for swagger 2025-11-09 19:21:29 +01:00
b1723c2f2c Transcoder misc fixes (#1144)
Co-authored-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-11-09 18:07:20 +00:00
Weblate (bot)
84fcbbbb42 Translations update from Hosted Weblate (#1146) 2025-11-09 18:53:50 +01:00
Weblate (bot)
93b5b50ba1 Translations update from Hosted Weblate (#1145) 2025-11-09 18:52:22 +01:00
4f9d340ef4 Add settings page (#1143) 2025-11-09 18:49:42 +01:00
5142e2bc25 Fix expo build 2025-11-09 18:27:03 +01:00
8f7f388403 Fix claim edit always editing permissions 2025-11-09 18:27:03 +01:00
5a37327e63 Fix change password api 2025-11-09 18:27:03 +01:00
d42062679a Handle logout and account deletion 2025-11-09 16:38:10 +01:00
6bb905b388 Rework settings page 2025-11-09 16:38:10 +01:00
39cfd501ac Add automatic language detection and language setting 2025-11-09 16:38:10 +01:00
079cc6b4f9 Fix translations keys 2025-11-09 16:38:10 +01:00
951ae955ed Use a postinstall script to generate translation list 2025-11-09 16:38:10 +01:00
61708857af Rework useMutation optimistic updates & start settings page 2025-11-09 16:38:10 +01:00
d3c69876d4 Add back search logic (#1142) 2025-11-08 15:03:14 +01:00
ebaf6d2177 Delete old front routing 2025-11-08 14:40:45 +01:00
9bc30ab62d Add back search logic 2025-11-08 14:40:45 +01:00
Antoine
f71a65d134 feat(auth): update forward auth endpoint (#1141) 2025-11-06 01:25:33 +01:00
renovate[bot]
ca0722b55c chore(deps): update helm release postgresql to v18.1.3 (#1118)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 09:42:27 +01:00
renovate[bot]
22cf24fd8c fix(deps): update module github.com/lestrrat-go/jwx/v3 to v3.0.12 (#1088)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-11-05 09:42:15 +01:00
Antoine
19e3619a42 docs(transcoder): update env examples (#1140) 2025-11-05 09:26:20 +01:00
1db4dea56f Handle cookies in keibi + fix database/env stuff (#1135) 2025-11-04 10:09:39 +01:00
03bb51661a Format stuff 2025-11-04 09:48:21 +01:00
01177c2489 Proprely remove cookies on logout 2025-11-04 09:48:21 +01:00
a86cd969a3 Properly handle rate limits in the scanner 2025-11-04 09:48:21 +01:00
bc6c93c9c7 Fix bearer cookie being base64ed 2025-11-04 09:48:21 +01:00
572ddc69ad Fix video controller permissions 2025-11-04 09:48:21 +01:00
c1b243df9c Fix image downloading error handling 2025-11-04 09:48:21 +01:00
31500dc3c5 Use an api key for the scanner 2025-11-04 09:48:21 +01:00
509e7c08cd Switch transcoder to pgx 2025-11-04 09:48:21 +01:00
165d9e8f31 Update .env.example 2025-11-04 09:48:21 +01:00
04171af3e3 Require core.play to play videos in gocoder 2025-11-04 09:48:21 +01:00
f1ddc7e7b9 Hardcode gocoder db schema 2025-11-04 09:48:21 +01:00
5827cc32e8 Hard code keibi postgres schema 2025-11-04 09:48:21 +01:00
4dc34641ec Handle cookies in keibi 2025-11-04 09:48:21 +01:00
Antoine
14c8f25499 fix(front): small fixes (#1134) 2025-11-03 18:37:18 +00:00
Antoine
d98ac3b452 fix(api): don't crash if not superuser (#1133) 2025-11-03 12:34:30 +01:00
3e7b27342c chore(deps): update actions/upload-artifact action to v5 (#1138) 2025-11-03 09:32:57 +01:00
dd9e611bef chore(deps): update dependency node to v24 (#1139) 2025-11-03 09:32:48 +01:00
renovate[bot]
0905e4424e chore(deps): update dependency node to v24 2025-11-03 01:54:30 +00:00
renovate[bot]
64c43a7833 chore(deps): update actions/upload-artifact action to v5 2025-11-03 01:54:26 +00:00
648a03e3ea Translations update from Hosted Weblate (#1136) 2025-11-02 22:40:29 +01:00
Максим Горпиніч
eb6887d189 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (211 of 211 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/uk/
2025-11-02 18:51:11 +00:00
acelinkio
c6133d85ff fix: auth's publish location (#1131) 2025-11-02 12:22:07 +01:00
Antoine
8a1b90f035 fix(front): update initial state api url (#1132) 2025-11-02 12:21:44 +01:00
renovate[bot]
8348e185fc chore(deps): update dependency @biomejs/biome to v2.3.2 (#1128)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-29 14:06:12 +01:00
renovate[bot]
1d78b26a37 fix(deps): update aws-sdk-go-v2 monorepo (#1129)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-28 09:20:39 +01:00
a8b2e575d5 Ignore front in renovate (#1127) 2025-10-27 10:57:03 +01:00
c132afe163 Delete v4 backend + docker fixes (#1116) 2025-10-26 22:55:56 +01:00
ebad8f32a4 Fix details page query 2025-10-26 22:32:40 +01:00
fb74ed30f8 Fix dockerfile of api 2025-10-26 22:31:40 +01:00
a0be0555e0 Update api packages 2025-10-26 22:31:40 +01:00
002b9e4b35 Add front dockerfile 2025-10-26 22:31:40 +01:00
996ad52159 Update docker compose 2025-10-26 11:20:51 +01:00
3b8c21c20f Misc cleanups 2025-10-26 11:20:51 +01:00
b3b58f7a1e Delete old back 2025-10-26 11:20:51 +01:00
7739908a19 Add back info page (#1115) 2025-10-26 09:48:38 +00:00
a3f29c73ec Player rewrite (#1020) 2025-10-24 16:33:49 +02:00
5fdc96db64 Format stuff 2025-10-24 16:18:35 +02:00
9206a30182 Fix player on mobile 2025-10-24 12:33:31 +02:00
1d81981c3f Fix expo install with bun 1.3 2025-10-22 13:41:37 +02:00
a15f28e541 Update bun-types in api 2025-10-22 09:18:44 +02:00
23832929e9 Add libass support 2025-10-22 09:17:56 +02:00
3590963206 Add subtitle conversion (from srt to vtt for example) 2025-10-22 09:17:54 +02:00
5ca1ae938f wip: Add subtitles handling 2025-10-22 09:16:45 +02:00
dfdeca35f3 Add keyboard bindings for player 2025-10-22 09:16:45 +02:00
70ff2285d5 Add video & quality selector 2025-10-22 09:16:45 +02:00
c5f237771c Add audio track selector 2025-10-22 09:16:45 +02:00
8fea8b1fe7 Add player error handling and hls fallback 2025-10-22 09:16:45 +02:00
816ee8de14 Web player fixes & fullscreen 2025-10-22 09:16:45 +02:00
a7d5f94dfb Allow clientId to be specified in query params 2025-10-22 09:16:45 +02:00
b7c6ba1e85 Fix subtitle extraction race condition 2025-10-22 09:16:45 +02:00
e348464261 Use my build of rnv to fix events 2025-10-22 09:16:45 +02:00
5031cc7163 Fix package versions 2025-10-22 09:16:45 +02:00
ebfb486363 Fix select for web 2025-10-22 09:16:44 +02:00
6cb1ae5fa1 Use on-failure instead of unless-stopped in dev docker compose 2025-10-22 09:16:44 +02:00
ad41c09055 Fix some typescript issues 2025-10-22 09:16:44 +02:00
5b320974df Update packages 2025-10-22 09:16:44 +02:00
e01c67b1ef Fix player controls style 2025-10-22 09:16:44 +02:00
da5823deb2 Fix /videos/:id?with=show date formatting 2025-10-22 09:16:44 +02:00
7085a68733 fixup! Add mime_codec to subtitles in the transcoder 2025-10-22 09:16:44 +02:00
84a855602e Implement middle controls 2025-10-22 09:16:44 +02:00
57779f02b1 Keep controls open in menues or hover 2025-10-22 09:16:44 +02:00
becc550add Implement bottom controls 2025-10-22 09:16:44 +02:00
9343bb524c Remake touch controls 2025-10-22 09:16:44 +02:00
fc9695a2dc Rewrite player's controls compenents 2025-10-22 09:16:44 +02:00
a310ceaed5 Implement player's enEnd & loading indicator 2025-10-22 09:16:44 +02:00
4d8806fc7f Make history's time non nullable (it was never null anyways) 2025-10-22 09:16:44 +02:00
d70b45d1fd Add external subtitles handling 2025-10-22 09:16:44 +02:00
5eb067639b Add mime_codec to subtitles in the transcoder 2025-10-22 09:16:44 +02:00
c364d3a67e Fix rnv startup 2025-10-22 09:16:44 +02:00
666ad9279f Fix dockerignore of auth & transcoder 2025-10-22 09:16:44 +02:00
02c77d2f32 Use rnv v7 for the rework 2025-10-22 09:16:44 +02:00
ebbed77650 Add /videos/:id/direct & /videos/:id/master.m3u8 routes 2025-10-22 09:16:44 +02:00
578dc4bbc9 Delete old models package 2025-10-22 09:16:44 +02:00
e3ae961b68 Add progress to /videos/:id 2025-10-22 09:16:44 +02:00
c33ba01e54 Add with=show to /videos/:id 2025-10-22 09:16:44 +02:00
787bfc1151 Type video in the front 2025-10-22 09:16:44 +02:00
f12718d67f Cleanup video info type 2025-10-22 09:16:43 +02:00
df3e0d1ed7 Remove some transcoder's deprecated fields 2025-10-22 09:16:43 +02:00
8ffed25580 Add /api/videos/:id/info route to redirect to the transcoder 2025-10-22 09:16:43 +02:00
a0739e57f2 Init player rework 2025-10-22 09:16:43 +02:00
renovate[bot]
da79d235be fix(deps): update aws-sdk-go-v2 monorepo (#1105)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-21 20:36:43 +00:00
renovate[bot]
ae20682c92 chore(deps): update aws-sdk-net monorepo (#1110)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-20 09:42:34 +02:00
renovate[bot]
99d4a21c12 chore(deps): update dependency system.componentmodel.composition to 9.0.10 (#1111)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-20 09:42:28 +02:00
renovate[bot]
17040e9775 chore(deps): update dotnet monorepo to 8.0.21 (#1112)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-20 09:42:22 +02:00
renovate[bot]
f92f93f960 chore(deps): update helm release postgresql to v18.0.15 (#1113)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-20 09:42:15 +02:00
renovate[bot]
1eb832f00d chore(deps): update actions/setup-node action to v6 (#1114)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-20 09:42:09 +02:00
renovate[bot]
b14ada8f48 chore(deps): update dependency @biomejs/biome to v2.2.6 (#1103)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-19 17:04:13 +02:00
renovate[bot]
f5f7a187c4 chore(deps): update dependency go to v1.25.3 (#1104)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-18 11:32:20 +02:00
renovate[bot]
938f7ca047 fix(deps): update module golang.org/x/text to v0.30.0 (#1109)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 22:53:09 +02:00
renovate[bot]
b0c1df2827 fix(deps): update module github.com/go-playground/validator/v10 to v10.28.0 (#1106)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 09:29:16 +02:00
renovate[bot]
be0b5d1523 chore(deps): update helm release postgresql to v18 (#1107)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-13 09:29:09 +02:00
renovate[bot]
fbee956876 chore(deps): update aws-sdk-net monorepo (#1102)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-07 09:30:43 +02:00
renovate[bot]
db1c1a5e92 chore(deps): update aws-sdk-net monorepo (#1099)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-06 09:32:48 +02:00
renovate[bot]
b4f9552048 chore(deps): update dependency nswag.aspnetcore to 14.6.1 (#1100)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-06 09:32:42 +02:00
renovate[bot]
1a5b93e5aa fix(deps): update aws-sdk-go-v2 monorepo (#1101)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-10-06 09:32:34 +02:00
acelinkio
216a58af24 Add runtime class in transcoder chart (#1093) 2025-09-30 07:24:41 -07:00
renovate[bot]
eff7a32b09 chore(deps): update aws-sdk-net monorepo (#1094)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 10:03:15 +02:00
renovate[bot]
bd041c1a4e chore(deps): update dependency meilisearch to 0.17.1 (#1095)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 09:37:47 +02:00
renovate[bot]
48876494f7 chore(deps): update skiasharp monorepo to 3.119.1 (#1096)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 09:37:36 +02:00
renovate[bot]
e4d92ff364 fix(deps): update aws-sdk-go-v2 monorepo (#1097)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 09:37:28 +02:00
renovate[bot]
d35ab8c894 chore(deps): update dependency nswag.aspnetcore to 14.6.0 (#1098)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-29 09:37:21 +02:00
64f38517e2 Add runtime class in transcoder chart 2025-09-22 21:06:28 +02:00
renovate[bot]
6b82053aec chore(deps): update aws-sdk-net monorepo (#1087)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-22 09:27:18 +02:00
renovate[bot]
5e91766d15 chore(deps): update golang docker tag to v1.25 (#1089)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-22 09:25:53 +02:00
renovate[bot]
65dc31c88a fix(deps): update module golang.org/x/text to v0.29.0 (#1084)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 13:22:40 +00:00
renovate[bot]
7ad78bd759 fix(deps): update module github.com/golang-migrate/migrate/v4 to v4.19.0 (#1077)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 13:10:01 +00:00
renovate[bot]
0befab278e chore(deps): update dependency @biomejs/biome to v2.2.4 (#1071)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:52:46 +02:00
renovate[bot]
8ea88f4301 chore(deps): update actions/setup-go action to v6 (#1085)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:52:27 +02:00
renovate[bot]
07fdf5e0b9 fix(deps): update module github.com/jackc/pgx/v5 to v5.7.6 (#1083)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:52:13 +02:00
renovate[bot]
de9559d1a2 chore(deps): update dotnet monorepo to 8.0.20 (#1082)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:52:07 +02:00
renovate[bot]
640bcad39f chore(deps): update dependency system.componentmodel.composition to 9.0.9 (#1081)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:51:58 +02:00
renovate[bot]
19edd54e37 fix(deps): update github.com/jackc/pgerrcode digest to afb5586 (#1080)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:51:48 +02:00
renovate[bot]
e9a9ecb157 chore(deps): update helm release meilisearch to v0.17.1 (#1076)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:51:41 +02:00
renovate[bot]
36605a9b85 chore(deps): update aws-sdk-net monorepo (#1070)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:51:34 +02:00
renovate[bot]
432b6681c7 chore(deps): update actions/setup-node action to v5 (#1079)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:51:26 +02:00
renovate[bot]
34525168bb fix(deps): update module golang.org/x/sync to v0.17.0 (#1078)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:51:14 +02:00
renovate[bot]
336a925591 chore(deps): update helm release rabbitmq to v16.0.14 (#1074)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:50:59 +02:00
renovate[bot]
2f6b946e71 chore(deps): update helm release postgresql to v16.7.27 (#1073)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:50:53 +02:00
renovate[bot]
47218e289b chore(deps): update dependency go to v1.25.1 (#1072)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:50:42 +02:00
renovate[bot]
8f1813168b fix(deps): update aws-sdk-go-v2 monorepo (#1075)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-09-17 14:50:14 +02:00
renovate[bot]
7ececfaf6a fix(deps): update module github.com/aws/aws-sdk-go-v2/config to v1.31.1 (#1067)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-26 12:06:12 +02:00
renovate[bot]
3f994ddd6f chore(deps): update dependency awssdk.s3 to 4.0.6.7 (#1062)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-25 10:08:19 +02:00
renovate[bot]
4e051e7ead chore(deps): update helm release postgresql to v16.7.26 (#1063)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-25 10:08:13 +02:00
renovate[bot]
b48a0fc0e0 fix(deps): update module github.com/lestrrat-go/httprc/v3 to v3.0.1 (#1064)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-25 10:08:08 +02:00
renovate[bot]
3fbfc3c289 chore(deps): update dependency @biomejs/biome to v2.2.0 (#1065)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-25 10:08:02 +02:00
Weblate (bot)
0baaed5973 Translations update from Hosted Weblate (#1061)
Co-authored-by: Максим Горпиніч <gorpinicmaksim0@gmail.com>
2025-08-24 16:13:24 +02:00
renovate[bot]
7f2c1fa5af chore(deps): update dependency awssdk.s3 to 4.0.6.5 (#1060)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-19 09:18:35 +02:00
Alice
89d44078f3 Add Traefik Port Hints (#1051) 2025-08-19 00:24:05 +02:00
renovate[bot]
ba0311ca29 chore(deps): update dependency meilisearch to 0.17.0 (#1056)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 10:43:20 +02:00
renovate[bot]
c249397b23 fix(deps): update module golang.org/x/text to v0.28.0 (#1058)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 10:43:06 +02:00
renovate[bot]
52022c1660 chore(deps): update actions/checkout action to v5 (#1059)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 10:42:48 +02:00
renovate[bot]
df2b5a0b1d fix(deps): update aws-sdk-go-v2 monorepo (#1057)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 10:42:33 +02:00
renovate[bot]
b062222238 chore(deps): update dependency go to v1.25.0 (#1055)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 10:42:24 +02:00
renovate[bot]
0432fb59d4 chore(deps): update helm release rabbitmq to v16.0.13 (#1054)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 10:42:19 +02:00
renovate[bot]
7da6b7c488 chore(deps): update helm release postgresql to v16.7.24 (#1053)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 10:42:14 +02:00
renovate[bot]
f7701986bd chore(deps): update dependency @biomejs/biome to v2.1.4 (#1052)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-18 10:42:08 +02:00
renovate[bot]
9af26df40e chore(deps): update dependency awssdk.s3 to 4.0.6.4 (#1049)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 22:53:01 +02:00
renovate[bot]
a4ee343101 chore(deps): update traefik docker tag to v3.5 (#1048)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:46:12 +02:00
renovate[bot]
a11eae6094 chore(deps): update helm release meilisearch to v0.15.0 (#1047)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:45:22 +02:00
renovate[bot]
84941ceb63 chore(deps): update dependency nswag.aspnetcore to 14.5.0 (#1046)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:45:04 +02:00
renovate[bot]
4a889890e3 fix(deps): update module github.com/lestrrat-go/jwx/v3 to v3.0.10 (#1045)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:44:34 +02:00
renovate[bot]
794c10e590 fix(deps): update aws-sdk-go-v2 monorepo (#1044)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:44:05 +02:00
renovate[bot]
897564337c chore(deps): update helm release rabbitmq to v16.0.12 (#1043)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:42:21 +02:00
renovate[bot]
e49e202677 chore(deps): update dotnet monorepo to 8.0.19 (#1042)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:42:10 +02:00
renovate[bot]
b85febeaa4 chore(deps): update dependency system.componentmodel.composition to 9.0.8 (#1041)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:41:58 +02:00
renovate[bot]
c0bbb973c4 chore(deps): update dependency go to v1.24.6 (#1040)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:41:48 +02:00
renovate[bot]
a57b2696de chore(deps): update dependency awssdk.s3 to 4.0.6.3 (#1039)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:41:38 +02:00
renovate[bot]
952a0dbc2f chore(deps): update dependency system.linq.async to 6.0.3 (#1001)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-11 19:41:19 +02:00
Weblate (bot)
6919a310b8 Translations update from Hosted Weblate (#1037)
Co-authored-by: ssantos <ssantos@web.de>
2025-08-09 00:50:06 +02:00
renovate[bot]
76ea0ce2ce fix(deps): update aws-sdk-go-v2 monorepo (#1036)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 23:43:38 +02:00
renovate[bot]
611490e786 fix(deps): update module github.com/golang-jwt/jwt/v5 to v5.3.0 (#1035)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 18:53:17 +02:00
renovate[bot]
725c1dc2e6 fix(deps): update module github.com/go-playground/validator/v10 to v10.27.0 (#1007)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 10:55:58 +02:00
renovate[bot]
d77156e5d0 fix(deps): update aws-sdk-go-v2 monorepo (#1034)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 10:55:53 +02:00
renovate[bot]
8f9190c176 fix(deps): update module github.com/swaggo/swag to v1.16.6 (#1033)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 10:55:45 +02:00
renovate[bot]
90780eae4b chore(deps): update dependency awssdk.extensions.netcore.setup to 4.0.2.1 (#1032)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 10:55:38 +02:00
renovate[bot]
691d63e15f chore(deps): update dependency @biomejs/biome to v2.1.3 (#1031)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-04 10:55:31 +02:00
renovate[bot]
6054e8cb18 fix(deps): update module github.com/lestrrat-go/jwx/v3 to v3.0.8 (#1004)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-08-02 22:19:09 +02:00
renovate[bot]
385130aa05 Update module github.com/labstack/echo/v4 to v4.13.4 - abandoned (#972)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: acelinkio <31336038+acelinkio@users.noreply.github.com>
2025-08-02 10:39:32 +00:00
renovate[bot]
b0daddca17 chore(deps): update dependency awssdk.s3 to 4.0.6.2 (#1030)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-29 09:28:09 +02:00
renovate[bot]
fb049d4c05 fix(deps): update module github.com/swaggo/swag to v1.16.5 (#1024)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 09:28:48 +02:00
renovate[bot]
774ff21b6b fix(deps): update aws-sdk-go-v2 monorepo (#1029)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 09:28:24 +02:00
renovate[bot]
f899445e13 chore(deps): update helm release postgresql to v16.7.21 (#1028)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 09:28:17 +02:00
renovate[bot]
ecb4dae801 chore(deps): update dependency awssdk.s3 to 4.0.6.1 (#1027)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 09:28:09 +02:00
renovate[bot]
03d3a1b386 chore(deps): update dependency @biomejs/biome to v2.1.2 (#1026)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-28 09:27:59 +02:00
Arthur Jamet
bfff409142 Transcoder: If empty JWKS env var, do not enable JWKS (#1025) 2025-07-23 12:49:52 +00:00
renovate[bot]
e9a34967f1 fix(deps): update module github.com/golang-jwt/jwt/v5 to v5.2.3 (#1023)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-21 09:44:46 +02:00
renovate[bot]
fc726f96fe chore(deps): update helm release postgresql to v16.7.19 (#1022)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-21 09:44:35 +02:00
renovate[bot]
dcb551afbe chore(deps): update dependency awssdk.s3 to 4.0.5 (#1021)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-21 09:44:16 +02:00
renovate[bot]
1cdf765fec chore(deps): update helm release rabbitmq to v16.0.11 (#1003)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-20 20:11:15 +02:00
d5a747f40d Add /videos/:id?with=next,previous route (#1019) 2025-07-19 18:05:11 +02:00
335b003b7c Test multi entry video with /videos/:id 2025-07-19 18:03:05 +02:00
e0d5754519 Test multi-versions in /videos/:id 2025-07-19 17:57:19 +02:00
28702b9cdb Test /videos/id with multi-part episodes 2025-07-19 17:55:13 +02:00
f99a144bc4 Add tests for /videos/:id 2025-07-19 17:40:33 +02:00
dc0c412eda fixup! Add helper function for entries' translations 2025-07-19 16:40:31 +02:00
fcac650322 Fix swagger's href 2025-07-19 15:54:07 +02:00
5379536db2 Add /videos/:id?with=next,previous route 2025-07-19 15:53:01 +02:00
8c8a974054 Add helper function for entries' translations 2025-07-19 15:46:10 +02:00
616c7140d3 Fix firstEntry type in api response 2025-07-19 15:46:10 +02:00
7939cc1c79 Fix api tests 2025-07-19 00:39:49 +02:00
ec204d04e1 Add jwt check with jwks in transcoder 2025-07-19 00:39:49 +02:00
460e4596f7 Generate swagger for transcoder 2025-07-19 00:39:49 +02:00
c340a9b559 Move metadata routes to it's own router 2025-07-19 00:39:49 +02:00
5d414bea16 Move stream routes utils to stream.go 2025-07-19 00:39:49 +02:00
46f313d735 Add swagger for transcoder & move routes to router module 2025-07-19 00:39:49 +02:00
30dd1e0b96 Update auth swagger 2025-07-19 00:39:49 +02:00
61b6eb0c6e wip: Validate jwt in transcoder 2025-07-19 00:39:49 +02:00
8caff21114 Expose transcoder to traefik 2025-07-19 00:39:49 +02:00
c90d0e7ffc Hardcode transcoder prefix to /video 2025-07-19 00:39:49 +02:00
4188e7bcd3 Hardcode /api prefix for the api 2025-07-19 00:39:49 +02:00
renovate[bot]
fbfe9dda8a fix(deps): update module golang.org/x/text to v0.27.0 (#1017)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 22:36:15 +00:00
renovate[bot]
2ef8f07a72 chore(deps): update aws-sdk-net monorepo (#1000)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-15 00:31:10 +02:00
8a9cf9fa1a Use poster for movies in entry line 2025-07-15 00:11:28 +02:00
ff4155de5e Fix entries list container 2025-07-15 00:11:28 +02:00
5ed43c85de Add next up in series detail page 2025-07-15 00:11:28 +02:00
666e4e2e6b Fix createdAt & updatedAt date formats for series's first & next
entries
2025-07-15 00:11:28 +02:00
8513cc057b Fix seasons entriesCount computation 2025-07-15 00:11:28 +02:00
42cce837e4 Make series page 2025-07-15 00:11:28 +02:00
d5c7ee40bc Rework entry box/line 2025-07-15 00:11:28 +02:00
dbf63e1b22 Add entry & extra types in front 2025-07-15 00:11:28 +02:00
4b6f56a293 Merge remote-tracking branch 'weblate/master' 2025-07-14 23:41:35 +02:00
renovate[bot]
f5cc3e0717 chore(deps): update helm release postgresql to v16.7.16 (#1002)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 12:50:05 +02:00
renovate[bot]
5c05531449 fix(deps): update aws-sdk-go-v2 monorepo (#999)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 12:36:06 +02:00
renovate[bot]
74a2f50012 chore(deps): update dotnet monorepo to 8.0.18 (#1012)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 01:34:55 +00:00
f6a41fdd63 fix(deps): update module golang.org/x/sync to v0.16.0 (#1015) 2025-07-14 03:34:25 +02:00
renovate[bot]
46736b9100 chore(deps): update dependency go to v1.24.5 (#1010)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 03:28:03 +02:00
renovate[bot]
cb16a51b38 chore(deps): update dependency system.componentmodel.composition to 9.0.7 (#1011)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-07-14 03:27:50 +02:00
aea2535cc6 Add entriesCount & availableCount to seasons 2025-07-14 03:27:46 +02:00
287b5350ff chore(deps): update dependency @biomejs/biome to v2.1.1 (#1013) 2025-07-14 03:27:29 +02:00
015b909a91 chore(deps): update dependency interpolatedsql.dapper to 2.4.0 (#1014) 2025-07-14 03:27:21 +02:00
renovate[bot]
d5197f563c fix(deps): update module golang.org/x/sync to v0.16.0 2025-07-14 01:13:04 +00:00
renovate[bot]
b82ebc90e8 chore(deps): update dependency interpolatedsql.dapper to 2.4.0 2025-07-14 01:12:38 +00:00
renovate[bot]
c924e330b8 chore(deps): update dependency @biomejs/biome to v2.1.1 2025-07-14 01:12:33 +00:00
1ea83848f3 Migrate to expo only (no next) PART 1 (#763) 2025-07-14 03:10:41 +02:00
4c1ad4da5b Fix progress date format 2025-07-14 03:05:50 +02:00
7b3f3cc1c1 Update code for biome v2 2025-07-14 02:56:51 +02:00
bbe1ad4ef1 Use bun dev in prod dockerfile until we have better 2025-07-14 00:58:50 +02:00
4a98b5ff27 Merge remote-tracking branch 'origin' into feat/two 2025-07-14 00:56:01 +02:00
8f80d6c96d wip: Series details 2025-07-14 00:33:40 +02:00
e1059aceed Fix safe area in movies details page 2025-07-14 00:11:14 +02:00
9d8e2e25e2 Cleanup studios display in details page 2025-07-13 23:57:10 +02:00
69838493bc Add loader for movie details page 2025-07-13 23:53:31 +02:00
512b378702 Cleanup movie details page 2025-07-13 22:18:15 +02:00
Weblate (bot)
6986b54d98 Translations update from Hosted Weblate (#1008)
Co-authored-by: 7stain <7stain@web.de>
Co-authored-by: Akhil Raj <akhilakae07@gmail.com>
2025-07-13 18:21:51 +02:00
Akhil Raj
c8b3c0d806 Translated using Weblate (Malayalam)
Currently translated at 5.2% (11 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ml/
2025-07-13 18:01:52 +02:00
Akhil Raj
5f94bd144d Translated using Weblate (Malayalam)
Currently translated at 5.2% (11 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ml/
2025-07-13 18:01:50 +02:00
7stain
2aadfb1319 Translated using Weblate (German)
Currently translated at 100.0% (209 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/de/
2025-07-13 18:01:49 +02:00
3f1c027019 Make header transparent in details page 2025-07-08 00:20:47 +02:00
0d4e8d5a62 Move app router to src directory 2025-07-08 00:13:38 +02:00
bf1997facd Some fix for details page 2025-07-08 00:09:58 +02:00
977398c851 Fix invalid images url 2025-07-07 23:46:11 +02:00
a697ffb524 Fix ?with=studios invalid date formats 2025-07-07 23:30:44 +02:00
aa342cfbd3 Fix base uri handling 2025-07-07 23:13:52 +02:00
c7103410dc Remake details page for movies 2025-07-07 22:40:21 +02:00
Weblate (bot)
549b44ad89 Translations update from Hosted Weblate (#1006)
Co-authored-by: tata <naft.dev@proton.me>
2025-07-06 12:36:23 +02:00
26410734fc Ensure stable sort when no lang is specified 2025-06-23 01:49:10 +02:00
985a13c1e4 Fix date handling (force iso on drizzle side) 2025-06-23 01:36:18 +02:00
dfe0d52b1e Add back login/register (& server url picker on mobile) 2025-06-23 00:34:43 +02:00
552926d2cb Fix browse layout switch 2025-06-22 21:22:37 +02:00
0ad9c86756 Fix translation keys for browse settings 2025-06-22 19:43:30 +02:00
1673da0004 Fix browse settings & infinite list 2025-06-22 19:31:21 +02:00
4d96ab5451 Fix scanner's invalid expected response 2025-06-22 19:29:16 +02:00
aa5ba7f2a9 Allow /api/shows to be filtered by kind 2025-06-22 19:28:26 +02:00
16f6399c4f Fix image's api from 500ing when image is not available + optimize etag 2025-06-22 19:27:53 +02:00
4ff0a1fe09 Update biome 2025-06-22 19:27:44 +02:00
e63e3605c6 Rework images & skeletons 2025-06-22 17:39:19 +02:00
886b33d5a7 Fix dropped typo in translations 2025-06-22 13:36:37 +02:00
2f0e077fa1 Allow shows to be sorted by names 2025-06-21 16:03:23 +02:00
713f3ca96f Make front's dev dockerfile 2025-06-21 15:48:58 +02:00
69c4e4e6d8 Rework browse settings 2025-06-21 13:57:17 +02:00
9498dea3fd Add show type 2025-06-20 17:30:10 +02:00
6823642e33 Rework collection & movie type 2025-06-20 17:27:12 +02:00
6c243b8961 Adapt models (serie & co) for new api 2025-06-19 23:48:22 +02:00
43cf343841 wip 2025-06-19 09:17:33 +02:00
3a9cb262f8 Create useMigration helper 2025-06-18 22:30:33 +02:00
36abadc2cc Rework browse page 2025-06-18 12:04:52 +02:00
renovate[bot]
5d7cdfdad8 Update Helm release postgresql to v16.7.11 (#997)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-17 09:21:09 +02:00
renovate[bot]
ecfb063bc7 Update dependency AWSSDK.S3 to 4.0.1.5 (#996)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-17 09:21:03 +02:00
renovate[bot]
d100018291 Update aws-sdk-go-v2 monorepo (#986)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 07:37:19 +00:00
renovate[bot]
405fbb49a0 Update dependency AWSSDK.S3 to 4.0.1.4 (#987)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:31:59 +02:00
renovate[bot]
9b015da29c Update dependency go to v1.24.4 (#988)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:31:49 +02:00
renovate[bot]
4d57278062 Update dependency System.ComponentModel.Composition to 9.0.6 (#989)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:31:39 +02:00
renovate[bot]
2b832ab05c Update dotnet monorepo to 8.0.17 (#990)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:31:26 +02:00
renovate[bot]
5454665337 Update Helm release postgresql to v16.7.10 (#991)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:28:53 +02:00
renovate[bot]
76564736bd Update Helm release rabbitmq to v16.0.7 (#992)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:28:45 +02:00
renovate[bot]
f8adc3cf0c Update module github.com/lestrrat-go/jwx/v3 to v3.0.5 (#993)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:28:33 +02:00
renovate[bot]
3317f6a3b8 Update Helm release meilisearch to v0.14.0 (#994)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:28:23 +02:00
renovate[bot]
a83ea2f370 Update module golang.org/x/text to v0.26.0 (#995)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-16 09:28:05 +02:00
8de7f20ac9 wip: Add browse page 2025-06-15 15:48:26 +02:00
9fbddd7b58 Fix navbar on android 2025-06-15 13:29:27 +02:00
651475876b Add back navbar 2025-06-15 13:22:33 +02:00
9d2edc8d06 Fix android build 2025-06-14 17:31:15 +02:00
50b6af78f4 Make the web run 2025-06-14 17:05:53 +02:00
d6c5e5281d Add .env.example to release (#984) 2025-06-10 14:05:25 +02:00
renovate[bot]
4029f4bb43 Update dependency AWSSDK.S3 to 4.0.1.3 (#983)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-10 02:17:19 +02:00
renovate[bot]
64f7e7c8be Update module github.com/golang-migrate/migrate/v4 to v4.18.3 (#827)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 10:42:08 +02:00
renovate[bot]
f37f95e6f4 Update module github.com/aws/aws-sdk-go-v2/service/s3 to v1.80.0 (#980)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 09:06:59 +02:00
renovate[bot]
ab49263b0c Update module github.com/lestrrat-go/jwx/v3 to v3.0.2 (#979)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 09:06:50 +02:00
renovate[bot]
01002f2975 Update dependency AWSSDK.S3 to 4.0.1.2 (#976)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-09 09:06:40 +02:00
acelinkio
df9622f57b Update Helm release postgresql to v16.7.9 (#977) 2025-06-08 18:16:03 -07:00
acelinkio
09ec19626e Update Helm release rabbitmq to v16.0.5 (#978) 2025-06-08 18:15:33 -07:00
renovate[bot]
c56192244e Update Helm release rabbitmq to v16.0.5 2025-06-09 01:05:49 +00:00
renovate[bot]
e78c4cbf5f Update Helm release postgresql to v16.7.9 2025-06-09 01:05:45 +00:00
5e37a946ac Expo switch cleanups 2025-06-09 01:53:10 +02:00
f0a0b40b3e Remove one 2025-06-09 01:09:11 +02:00
1fdabaa63a Update npm pacakges 2025-06-08 22:06:13 +02:00
f8aae2f701 Try to fix bun run build 2025-06-07 19:32:57 +02:00
bb62a2844f Fix react-query devtools error on mobile 2025-06-07 19:32:57 +02:00
317e795d6f Make translations work on web & native 2025-06-07 19:32:57 +02:00
3f82f04f65 Load resources at compile time 2025-06-07 19:32:57 +02:00
829497300e Use expo-fs as a backend 2025-06-07 19:32:57 +02:00
14cf634815 Custom translation backend 2025-06-07 19:32:57 +02:00
96a38e0c65 wip: Make translation provider for native 2025-06-07 19:32:57 +02:00
1685800ce8 Fix one patch version 2025-06-07 19:32:57 +02:00
9ba853f52c Add sed in project.json, what could go wrong 2025-06-07 19:32:57 +02:00
c172767843 Disable react native directory check 2025-06-07 19:32:57 +02:00
f41be77632 Update packages 2025-06-07 19:32:57 +02:00
16d6c65eba wip: Disable async improt of translations for mobile 2025-06-07 19:32:57 +02:00
b1f6fdc30f Add back eas config 2025-06-07 19:32:57 +02:00
474a0a546b Fix circular imports of error provider 2025-06-07 19:32:57 +02:00
e3bde0cd57 Fix circular import of account context 2025-06-07 19:32:57 +02:00
11712d3e4e Move login page 2025-06-07 19:32:55 +02:00
be54eb11fe Auto switch between ssr and browser mode of translations 2025-06-07 19:32:05 +02:00
31c183ecf1 Add translation provider with http & fs backend 2025-06-07 19:32:03 +02:00
23f42f247d Use my fork of react native svg to fix web 2025-06-07 19:30:06 +02:00
8c40e2230d Fix react native svg 2025-06-07 19:30:05 +02:00
6584983535 Update stuff 2025-06-07 19:30:05 +02:00
071b365a9b Patch dependencies 2025-06-07 19:30:05 +02:00
4b239db229 Handle svg 2025-06-07 19:30:05 +02:00
f2bc916483 Rework links for one 2025-06-07 19:30:05 +02:00
6cfeba6c62 Add error consumer for unauthorized 2025-06-07 19:30:05 +02:00
b4144e61d3 Fix yoshiki providers + add vite proxy 2025-06-07 19:30:05 +02:00
b4f303e0fb Fixup ssr fetch 2025-06-07 19:30:05 +02:00
176d76b246 Fix prefetch 2025-06-07 19:30:05 +02:00
7ee6c2e666 Finish account provider cleanup 2025-06-07 19:30:05 +02:00
ea7cb8b4d1 Rework account internals storage 2025-06-07 19:30:05 +02:00
0a8553653c Settings/mmkv setup 2025-06-07 19:30:05 +02:00
f76b2732a1 wip: Account/login rework 2025-06-07 19:30:05 +02:00
7211699e87 Rework error provider 2025-06-07 19:30:05 +02:00
5d6bb63ba2 Rework query function 2025-06-07 19:30:05 +02:00
c1e3a67a4e Move primitives 2025-06-07 19:30:05 +02:00
4a3d033562 Rework Fetch component 2025-06-07 19:30:05 +02:00
cbc00729cc Move resources to ~/models 2025-06-07 19:30:05 +02:00
7a4e203cdd Query rework part1 2025-06-07 19:30:05 +02:00
32ecf25321 Start to remove workspace & move theme to root package 2025-06-07 19:30:05 +02:00
d53d4a26e9 Cleanup inline-style-prefixer fix 2025-06-07 19:30:05 +02:00
c84985766e Fix react query in ssr 2025-06-07 19:30:05 +02:00
6a229a090a Fix runtime errors in browser 2025-06-07 19:30:05 +02:00
25e9cec3c3 Finally fix style renderer 2025-06-07 19:30:05 +02:00
b9354537e1 Inline style prefixer debug tests 2025-06-07 19:30:05 +02:00
0e01b7c564 wip 2025-06-07 19:30:05 +02:00
9b89b00b9f Start providers setup 2025-06-07 19:30:05 +02:00
32c826e65d Migrate to app.config.ts 2025-06-07 19:30:05 +02:00
b22e89423a Delete yarn, setup one 2025-06-07 19:30:04 +02:00
b602185237 Scanner rework for v5 (#923) 2025-06-07 19:25:46 +02:00
2f6943cd6f Fix lots of stuff 2025-06-07 19:02:06 +02:00
489336c77a Add tests for video linking 2025-06-07 17:48:10 +02:00
6e2743a4be Add link video route 2025-06-07 17:45:39 +02:00
3e69ea9c8b Implement link videos on the scanner 2025-06-07 17:45:39 +02:00
d9d411b377 Rename unmatched route (from unknowns) 2025-06-07 17:45:39 +02:00
be4b4f016b Add isAvailable filter for both entries & shows 2025-06-07 17:45:39 +02:00
107e581801 Fix entries fetching when first ep of season is not 1 2025-06-07 17:45:39 +02:00
9b68110cf6 Fix json post of series & movies 2025-06-07 17:45:39 +02:00
505427f0ff Fix missing absolute group handling 2025-06-07 17:45:39 +02:00
9e3a9af0ef Properly handle image cache 2025-06-07 17:45:39 +02:00
af97c52e48 Fix auth tests 2025-06-07 17:45:39 +02:00
953ac5ffa8 Use trailer instead of trailerUrl on seed, allow seasonNumber = 0 2025-06-07 17:45:39 +02:00
791bbf275a Fix order starting at 0 instead of 1 2025-06-07 17:45:39 +02:00
d1bf1f3339 Fix scanner's create requests 2025-06-07 17:45:39 +02:00
62e0a123aa Update api's packages 2025-06-07 17:45:39 +02:00
55d1551cd3 Fix uv's shell.nix (& add python-slugify) 2025-06-07 17:45:39 +02:00
a22edc11ce Handle crew & fix some themoviedb bugs 2025-06-07 17:45:39 +02:00
af566150f5 Use watch mode for transcoder 2025-06-07 17:45:39 +02:00
4828fa08cf Use docker-compose watch mode for auth 2025-06-07 17:45:39 +02:00
e5b1842432 Add format workflow for auth 2025-06-07 17:45:39 +02:00
7857b14a14 Hardcode keibi's prefix to /auth 2025-06-07 17:45:39 +02:00
12d9ad3183 wip: Reconnect to database on connection failure 2025-06-07 17:45:39 +02:00
df23cf54d7 Fix listener 2025-06-07 17:45:39 +02:00
9c451a865e Cleanup task handling/cancellation of background tasks 2025-06-07 17:45:39 +02:00
5b2ccba175 Fix watch of docker-compose 2025-06-07 17:45:39 +02:00
ae0f55ae9b Clear failed requests before scanning 2025-06-07 17:45:39 +02:00
c9fcbc8e8f Implement proper shutdown of scan/monitor tasks 2025-06-07 17:45:39 +02:00
1747454845 Fix dockerfiles 2025-06-07 17:45:39 +02:00
095d309bb6 Use docker compose watch for api 2025-06-07 17:45:39 +02:00
10e200ea5a Remove docker.dev for docker watch for scanner 2025-06-07 17:45:38 +02:00
af75985a14 Switch to uv 2025-06-07 17:45:38 +02:00
34c891128e Provider cleanup 2025-06-07 17:45:38 +02:00
cafc40d5f2 Fix tmdb stuff 2025-06-07 17:45:38 +02:00
d13fa1bdf1 Fix example .env & postgres vars for v5 2025-06-07 17:45:38 +02:00
90b6e2264d Create request in db 2025-06-07 17:45:38 +02:00
a9b7d18a6e Fix request creation 2025-06-07 17:45:38 +02:00
2fc696dde9 Add database migration script 2025-06-07 17:45:38 +02:00
f3310e23f3 Stop trying to use the non-working DI of fastapi 2025-06-07 17:45:38 +02:00
ebda81db97 Fix identify 2025-06-07 17:45:38 +02:00
d6d71421fd Fix scanner's teardown 2025-06-07 17:45:38 +02:00
d873c74545 Fix scanner/api communications 2025-06-07 17:45:38 +02:00
07972b0773 Cleanup missing auth header error 2025-06-07 17:45:38 +02:00
e2f02a279d fastapi's di is utter garbage 2025-06-07 17:45:38 +02:00
444249dfc4 Singleton try 2025-06-07 17:45:38 +02:00
6d70870ef3 Proper app cleanup 2025-06-07 17:45:38 +02:00
0839f5afb7 Small fixes & error handling 2025-06-07 17:45:38 +02:00
9eae11d3b5 Use fastapi router 2025-06-07 17:45:38 +02:00
cd874e382f Handle database connection vars 2025-06-07 17:45:38 +02:00
0cafe1ef40 Cleanup startup events 2025-06-07 17:45:38 +02:00
d666cda744 Fix jwks validation in scanner 2025-06-07 17:45:38 +02:00
19f346ffb6 Add kid in jwks & jwts 2025-06-07 17:45:38 +02:00
a29dff1014 Validate jwts in the scanner 2025-06-07 17:45:38 +02:00
45a1198f30 Add put /scan to trigger a scan 2025-06-07 17:45:38 +02:00
1e65053c37 Map Language for pydantic 2025-06-07 17:45:38 +02:00
b0dad090ae Start scan & monitor on master instance of scanner 2025-06-07 17:45:38 +02:00
53867792f3 Switch to asyncpg & create initial listener 2025-06-07 17:45:38 +02:00
21435da93f wip: Link videos found after request started 2025-06-07 17:45:38 +02:00
2bf9464c18 Implement request processor (listen for requests) 2025-06-07 17:45:38 +02:00
f5f4ad439c Create a psycopg pool 2025-06-07 17:45:38 +02:00
d1e38c9e1c Create request migration 2025-06-07 17:45:38 +02:00
249019d6f5 Move old stuff to one dir 2025-06-07 17:45:38 +02:00
608e0cf12e Move stuff around 2025-06-07 17:45:38 +02:00
f1f7dde507 Match guessed's entries to tmdb's entries 2025-06-07 17:45:38 +02:00
058f7a67a1 Switch to tmdb's API Read Access Token 2025-06-07 17:45:38 +02:00
38d4b20092 Cleanup composite provider 2025-06-07 17:45:38 +02:00
37271cc855 Remove specials override (tmdb absolute ordering) 2025-06-07 17:45:38 +02:00
481af6bfd3 Rewrite absolute order computation for tmdb 2025-06-07 17:45:38 +02:00
e4e7caf738 Add entry & seasons parsing from tmdb 2025-06-07 17:45:38 +02:00
fa8f43c9bb Add serie search 2025-06-07 17:45:38 +02:00
3537722d44 Add movie search 2025-06-07 17:45:38 +02:00
d8906cfe06 Parse staff & collections 2025-06-07 17:45:38 +02:00
d32711845b Rework get movie for tmdb 2025-06-07 17:45:37 +02:00
cb7edde64c Move tmdb 2025-06-07 17:45:37 +02:00
4353b5e911 Fix api tests 2025-06-07 17:45:37 +02:00
b6ed8f0684 Type series & all related types 2025-06-07 17:45:37 +02:00
b28f00aa22 Type movie & all related types 2025-06-07 17:45:37 +02:00
70be095131 Create composite provider that uses both tvdb & tmdb 2025-06-07 17:45:37 +02:00
fb2a9cf9f1 Remake provider interface 2025-06-07 17:45:37 +02:00
7beff1eeaf Fix lsp warnings 2025-06-07 17:45:37 +02:00
f8612fed96 wip: Start scan request processor 2025-06-07 17:45:37 +02:00
9c98e284f0 Cleanup scan + monitor with a class 2025-06-07 17:45:37 +02:00
b3a13882c1 Rework fs monitor 2025-06-07 17:45:37 +02:00
e3a04c0e0f Write enqueue logic for identify requests 2025-06-07 17:45:37 +02:00
4eed03a566 Match new videos with known metadata 2025-06-07 17:45:37 +02:00
ed7e9cd159 Match 2025-06-07 17:45:37 +02:00
11d0461d55 Filter videos & push them to the api 2025-06-07 17:45:37 +02:00
8dd43653cc Proper rendering computation (god that was a pain) 2025-06-07 17:45:37 +02:00
2d7ff3bc58 Try stuff with rendering & guessit rules 2025-06-07 17:45:37 +02:00
f740448229 Fix pydantic printing 2025-06-07 17:45:37 +02:00
d92482d0b7 Create identify pipeline 2025-06-07 17:45:37 +02:00
ab5d2ad4e8 Update elysia & fix type issues 2025-06-07 17:45:37 +02:00
7ff794742d Write identify function 2025-06-07 17:45:37 +02:00
4480757df5 Type Video in the scanner 2025-06-07 17:45:37 +02:00
87fa87298e Init new KyooClient & setup pydantic 2025-06-07 17:45:37 +02:00
51f583965a Move models to new scanner module 2025-06-07 17:45:37 +02:00
60d1105280 Move fs scanner 2025-06-07 17:45:37 +02:00
aba86601cd Add scanner's openapi to scalar 2025-06-07 17:45:37 +02:00
9f330f6683 Init fastapi 2025-06-07 17:45:37 +02:00
eb2b2a95a0 Fix api listen url print 2025-06-07 17:45:37 +02:00
943d2ac10b Split shell.nix into project specific ones 2025-06-07 17:45:37 +02:00
6324901d3b Enable v5 by default in docker-compose.dev.yaml 2025-06-07 17:45:37 +02:00
b3d8ffc89d Init scanner with fastapi 2025-06-07 17:45:37 +02:00
ae9bfcfd41 Move stuff to old_scanner 2025-06-07 17:45:37 +02:00
acelinkio
37e0fc3f0e Update Helm release postgresql to v16.7.5 (#969) 2025-06-02 07:08:49 -07:00
acelinkio
533ca0aed0 Update Helm release rabbitmq to v16.0.3 (#970) 2025-06-02 07:08:34 -07:00
acelinkio
5897899d71 Merge branch 'master' into renovate/postgresql-16.x 2025-06-02 07:06:52 -07:00
renovate[bot]
3f96da2c7c Update module github.com/aws/aws-sdk-go-v2/service/s3 to v1.79.4 (#971)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-06-02 12:10:26 +02:00
renovate[bot]
c31c82a3e4 Update Helm release rabbitmq to v16.0.3 2025-06-02 02:20:13 +00:00
renovate[bot]
1c3314d8a5 Update Helm release postgresql to v16.7.5 2025-06-02 02:20:05 +00:00
solidDoWant
63df1baead Add support for QSV with newer Intel iGPUs (#931) 2025-05-30 12:32:18 +02:00
renovate[bot]
4f63f09566 Update dependency AWSSDK.S3 to 4.0.0.7 (#966)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 10:46:50 +02:00
renovate[bot]
bd9f51d260 Update aws-sdk-net monorepo (#963)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 10:28:45 +02:00
renovate[bot]
17181cec0e Update dependency Serilog to 4.3.0 (#965)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 10:28:10 +02:00
renovate[bot]
7455e79f61 Update module github.com/jackc/pgx/v5 to v5.7.5 (#964)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-26 10:25:12 +02:00
renovate[bot]
67cd8bea9c Update dependency Dapper to 2.1.66 (#959)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-20 09:21:40 +02:00
renovate[bot]
05c2118f1f Update Helm release meilisearch to v0.13.0 (#960)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-20 09:20:38 +02:00
renovate[bot]
21b7a5cec6 Update dotnet monorepo to 8.0.16 (#955)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 09:23:12 +02:00
renovate[bot]
6e5b9852c7 Update dependency System.ComponentModel.Composition to 9.0.5 (#954)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 09:22:56 +02:00
renovate[bot]
1d70864e89 Update Helm release meilisearch to v0.12.2 (#956)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 09:22:45 +02:00
renovate[bot]
dfce460153 Update Helm release postgresql to v16.7.4 (#958)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-19 09:22:33 +02:00
renovate[bot]
7d31de50c3 Update dependency AWSSDK.S3 to 4.0.0.3 (#953)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-12 22:26:28 +02:00
renovate[bot]
77ffc2e061 Update module golang.org/x/text to v0.25.0 (#952)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-12 09:34:10 +02:00
renovate[bot]
1b3f6d41ba Update dependency go to v1.24.3 (#949)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-12 09:33:59 +02:00
renovate[bot]
fa0bb985a7 Update Helm release postgresql to v16.6.7 (#950)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-12 09:33:48 +02:00
renovate[bot]
d9a6d052bc Update Helm release rabbitmq to v16.0.2 (#951)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-12 09:33:36 +02:00
renovate[bot]
18b0c34165 Update dependency AWSSDK.S3 to 4.0.0.2 (#948)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-05-12 09:33:18 +02:00
solidDoWant
1f573a2553 Added support for disabling password login and registration (#947)
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
Signed-off-by: solidDoWant <fred.heinecke@yahoo.com>
2025-05-09 14:07:32 +02:00
solidDoWant
ce63da1448 Added support for considering DTS audio streams when determing player codec support (#942) 2025-05-08 02:08:59 +02:00
solidDoWant
f6a67341b6 Reduce playback start time by 100x (#945) 2025-05-08 00:33:36 +02:00
solidDoWant
4a0e1aa72c Cleanly handle unsupported subtitles (#944) 2025-05-07 22:51:43 +02:00
renovate[bot]
27a4fc328e Update traefik Docker tag to v3.4 2025-05-06 01:22:17 +02:00
renovate[bot]
e45883230b Update dependency AWSSDK.S3 to 4.0.0.1 2025-05-06 00:46:17 +02:00
renovate[bot]
8f121d20e3 Update module golang.org/x/sync to v0.14.0 2025-05-05 19:28:35 +02:00
renovate[bot]
665d614921 Update aws-sdk-net monorepo to v4 2025-05-05 04:33:52 +02:00
renovate[bot]
aa42d807b2 Update Helm release rabbitmq to v16 2025-05-05 04:28:18 +02:00
renovate[bot]
4c0f20a33e Update skiasharp monorepo to 3.119.0 2025-05-05 04:25:07 +02:00
renovate[bot]
f729ef06a7 Update dependency NSwag.AspNetCore to 14.4.0 2025-05-05 04:24:42 +02:00
renovate[bot]
ebec864187 Update module github.com/lestrrat-go/jwx/v3 to v3.0.1 2025-05-05 04:24:25 +02:00
renovate[bot]
d9e0ca1edd Update Helm release postgresql to v16.6.6 2025-05-05 04:23:33 +02:00
renovate[bot]
d23a24943e Update dependency AWSSDK.S3 to 3.7.416.18 2025-05-05 04:23:18 +02:00
ebd95c7b0c Apis for the scanner (#885) 2025-05-04 16:03:35 +02:00
a96813fe30 Return deleted paths in DELETE /videos 2025-05-04 15:35:59 +02:00
4df171386b Test deletions 2025-05-04 15:35:37 +02:00
46d98e038d Update availableSince of entries on POST /videos 2025-05-04 15:35:37 +02:00
205dda652a Update available count of shows when inserting videos 2025-05-04 15:35:37 +02:00
e26bc931f5 Fix & test GET /videos 2025-05-04 15:35:37 +02:00
45e769828b Add unique constraint on [rendering, version, part] 2025-05-04 15:35:37 +02:00
466b67afe5 Put POST /videos in a transaction, handle dups 2025-05-04 15:35:37 +02:00
379765b28f Fix typechecking 2025-05-04 15:35:37 +02:00
71b3ee61af Add support for externalId in POST /videos 2025-05-04 15:35:37 +02:00
7203155747 Use .Composite for models (better swagger) 2025-05-04 15:35:37 +02:00
9cb9301a35 Update packages (drizzle included) 2025-05-04 15:35:37 +02:00
6a5862ddd2 Fix & test movie, episodes & slug linking 2025-05-04 15:35:37 +02:00
060c4d74b4 Type value lists 2025-05-04 15:35:37 +02:00
07a41bb175 Fix POST /videos 2025-05-04 15:35:37 +02:00
d2bb37b3a7 Add more tests 2025-05-04 15:35:37 +02:00
ce66dba0c8 Add unmatched paths in GET /videos (for scanner) 2025-05-04 15:35:37 +02:00
6194d806cc Delete unknown entries, rework them as part of unmatched videos 2025-05-04 15:35:37 +02:00
1fca8957a2 Fix auth default PGHOST 2025-05-04 15:35:37 +02:00
39dcfb4418 Test POST /videos 2025-05-04 15:35:37 +02:00
1369da1845 Rework POST /videos 2025-05-04 15:35:37 +02:00
621c9cec82 Add GET /videos/ that also list guesses 2025-05-04 15:35:37 +02:00
c504cbbff5 Type videos's for to map to entries 2025-05-04 15:35:37 +02:00
0aa2c9c086 Cleanup scanner workflow 2025-05-04 15:35:37 +02:00
Fred Heinecke
099032c165 Fix scanner message storm caused by #916
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-05-04 14:55:43 +02:00
Fred Heinecke
a16d09d692 Fix transcoder S3 deadlock when writer does not respect context cancellation
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-05-04 14:55:16 +02:00
Fred Heinecke
949a367d0d Fix S3 client being disposed after first use
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-05-04 14:54:02 +02:00
Fred Heinecke
0b3d46cc67 Fix inverted if/else check for thumbnail requests
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-05-04 14:53:26 +02:00
solidDoWant
7d04da2eae Backend: Fix pooling configuration always overriding connection string parameters 2025-05-04 14:13:40 +02:00
Fred Heinecke
454855b299 Add CA Certificates to transcoder image
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-05-04 14:12:56 +02:00
solidDoWant
265386f289 Added support for storing transcoder metadata in S3
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-05-02 11:38:28 +02:00
Fred Heinecke
cf7bc456e8 Fix Scanner service crash when RabbitMQ queues are predeclared
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-05-02 11:25:36 +02:00
Fred Heinecke
0493265b1d Added Go pprof handlers
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-05-02 09:35:48 +02:00
renovate[bot]
58cc688a02 chore(deps): update helm release postgresql to v16.6.4 2025-04-29 00:52:56 +02:00
Fred Heinecke
1a61b18b2d Fix Backend service crash when RabbitMQ queues are predeclared
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-04-28 12:22:25 +02:00
solidDoWant
0fe423869a Address PR comments
Signed-off-by: solidDoWant <fred.heinecke@yahoo.com>
2025-04-28 12:21:01 +02:00
solidDoWant
7193b5a2a2 Add support for loading multiple root CAs from the specified CA file
Signed-off-by: solidDoWant <fred.heinecke@yahoo.com>
2025-04-28 12:21:01 +02:00
Fred Heincke
79ee70a1a2 Add support for RabbitMQ connection string to Backend service
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-04-28 12:21:01 +02:00
Fred Heincke
73e2eaaf70 Add support for RabbitMQ connection string to the Scanner service
Signed-off-by: Fred Heincke <fred.heinecke@yahoo.com>
2025-04-28 09:50:26 +02:00
Fred Heincke
02c2a2db52 Add support for RabbitMQ connection string to the Autosync service
Signed-off-by: Fred Heincke <fred.heinecke@yahoo.com>
2025-04-28 09:50:08 +02:00
solidDoWant
a39baa1b50 Fix null dereference when file does not exist
Signed-off-by: solidDoWant <fred.heinecke@yahoo.com>
2025-04-28 09:49:04 +02:00
Fred Heinecke
5ebbd2b565 [v4] Added support for storing images in S3-compatible object storage
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-04-28 09:49:04 +02:00
Fred Heinecke
35437500ed Update workflows to work on forks
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-04-28 09:31:36 +02:00
Fred Heinecke
94fe79bcd1 Support standard libpq environment variables for the Backend service
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-04-24 09:40:09 +02:00
solidDoWant
5ced62aab3 Support standard libpq environment variables for Auth service (#901) 2025-04-24 09:38:20 +02:00
f2294ac97e Support POSTGRES_URL environment variable for the Transcoder service (#903) 2025-04-24 09:28:54 +02:00
Fred Heinecke
1c8cbab989 Support POSTGRES_URL environment variable for the Transcoder service
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-04-24 05:31:40 +00:00
renovate[bot]
f2caf1a975 fix(deps): update module github.com/lestrrat-go/jwx to v3 (#880)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Zoe Roux <zoe.roux@zoriya.dev>
2025-04-23 21:50:26 +00:00
b1509f4001 chore(deps): update helm release rabbitmq to v15.5.3 (#897) 2025-04-23 23:15:49 +02:00
renovate[bot]
4475964eb2 chore(deps): update helm release rabbitmq to v15.5.3 2025-04-23 21:12:47 +00:00
092128add1 Support standard libpq environment variables for the API (#899) 2025-04-23 23:10:13 +02:00
e68217dbce Add api keys support (#900) 2025-04-23 23:09:09 +02:00
solidDoWant
9945d49be9 comment out env vars
Signed-off-by: solidDoWant <fred.heinecke@yahoo.com>
2025-04-23 21:08:18 +00:00
fb908c95ef Fix hurl test 2025-04-23 23:04:28 +02:00
667249bc81 Add CreatedBy value in apikeys 2025-04-23 22:45:39 +02:00
dcbbb6352a Add hurl tests for apikeys 2025-04-23 22:35:52 +02:00
Fred Heinecke
d0a1ee848f bug fixes, PR feedback, remove some vars
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-04-23 19:54:55 +00:00
e8acb31834 Allow env to specify apikeys 2025-04-23 19:41:42 +02:00
a72ecdb21b Add apikey support to /jwt 2025-04-23 19:41:42 +02:00
85186a74c8 Add apikeys routes 2025-04-23 19:41:42 +02:00
822a7029ef wip: Add api keys apis 2025-04-23 19:41:42 +02:00
Fred Heinecke
634c8808a1 [v5] Added support for storing images in S3
Signed-off-by: Fred Heinecke <fred.heinecke@yahoo.com>
2025-04-22 22:58:50 +00:00
solidDoWant
099d893da9 Add support for storing images in S3 (#896) 2025-04-20 16:47:49 +00:00
1d1ea295c0 chore(deps): bump golang.org/x/net from 0.36.0 to 0.38.0 in /transcoder (#895) 2025-04-17 10:22:56 +02:00
dependabot[bot]
b38adc558d chore(deps): bump golang.org/x/net from 0.36.0 to 0.38.0 in /transcoder
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.36.0 to 0.38.0.
- [Commits](https://github.com/golang/net/compare/v0.36.0...v0.38.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-version: 0.38.0
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-04-16 23:20:38 +00:00
acelinkio
893d2b7081 chore(deps): update helm release rabbitmq to v15.5.1 (#894) 2025-04-14 18:04:19 -07:00
acelinkio
e962887569 Merge branch 'master' into renovate/rabbitmq-15.x 2025-04-14 18:03:30 -07:00
acelinkio
5af6078e67 chore(deps): update helm release postgresql to v16.6.3 (#893) 2025-04-14 18:03:18 -07:00
renovate[bot]
5e3c8c5f6f chore(deps): update helm release rabbitmq to v15.5.1 2025-04-14 23:04:49 +00:00
renovate[bot]
91e08dd5a9 chore(deps): update helm release postgresql to v16.6.3 2025-04-14 23:04:45 +00:00
cf8814a5fd chore(deps): update dotnet monorepo to 8.0.15 (#887) 2025-04-14 09:36:23 +02:00
renovate[bot]
a7760f4e41 chore(deps): update dotnet monorepo to 8.0.15 2025-04-14 07:32:16 +00:00
8785d5af4d fix(deps): update dependency sharp to ^0.34.0 (#890) 2025-04-14 09:31:25 +02:00
renovate[bot]
0d6219aca7 fix(deps): update dependency sharp to ^0.34.0 2025-04-14 07:29:59 +00:00
cad5dee882 chore(deps): update helm release rabbitmq to v15.5.0 (#889) 2025-04-14 09:28:02 +02:00
renovate[bot]
cb831888ee chore(deps): update helm release rabbitmq to v15.5.0 2025-04-14 07:27:03 +00:00
c6ad4266ec chore(deps): update helm release postgresql to v16.6.2 (#888) 2025-04-14 09:25:13 +02:00
renovate[bot]
1b1e49f089 chore(deps): update helm release postgresql to v16.6.2 2025-04-14 07:23:54 +00:00
b6fafa6d68 chore(deps): update dependency system.componentmodel.composition to 9.0.4 (#886) 2025-04-14 09:21:03 +02:00
renovate[bot]
111d216dcd chore(deps): update dependency system.componentmodel.composition to 9.0.4 2025-04-14 07:20:58 +00:00
3b9d9f592e fix(deps): update module golang.org/x/text to v0.24.0 (#891) 2025-04-14 09:20:02 +02:00
renovate[bot]
4b79ec7fae fix(deps): update module golang.org/x/text to v0.24.0 2025-04-14 03:08:39 +00:00
d7388d3504 Document scanner's v5 workflow (#678) 2025-04-09 00:34:12 +02:00
3c681fca65 Document scanner's v5 workflow 2025-04-09 00:30:42 +02:00
29f38e42ae Fix localized images selection (#677) 2025-04-09 00:21:25 +02:00
c0596eb3ab Format stuff 2025-04-09 00:18:31 +02:00
Felipe Marinho
5941fc3ee7 chg: fix: key_error when original_language is unavailable 2025-04-09 00:14:21 +02:00
Felipe Marinho
f121b718a9 chg: feat: add localization to collections as well 2025-04-09 00:14:20 +02:00
Felipe Marinho
eaa09aba3b chg: fix: lint issues 2025-04-09 00:14:20 +02:00
Felipe Marinho
31a38d0861 chg: fix: original_language param 2025-04-09 00:14:20 +02:00
Felipe Marinho
9416c06a0d chg: fix: apply MR suggestions 2025-04-09 00:14:20 +02:00
Felipe Marinho
60410481c1 chg: lint: format code 2025-04-09 00:14:20 +02:00
Felipe Marinho
4be2812780 chg: fix: add null as default original language 2025-04-09 00:14:20 +02:00
Felipe Marinho
26b839fc4a chg: fix: make the extra parameter optional 2025-04-09 00:14:20 +02:00
Felipe Marinho
bc7920fad3 chg: fix: add media type 2025-04-09 00:14:20 +02:00
Felipe Marinho
50e18ee99d chg: refactor: remove repetitive code 2025-04-09 00:14:20 +02:00
Felipe Marinho
6b751e11f3 chg: fix: add fallback 2025-04-09 00:14:20 +02:00
Felipe Marinho
28fe8bd9bc chg: refactor: use langcodes instead of string for language representation 2025-04-09 00:14:20 +02:00
Felipe Marinho
7c0424fcda chg: feat: better ignore regex 2025-04-09 00:14:20 +02:00
Felipe Marinho
b96ce5d46f chg: docs: add setting to the envfile 2025-04-09 00:14:20 +02:00
Felipe Marinho
e73aa83c83 chg: fix: only use 3 languages 2025-04-09 00:14:20 +02:00
Felipe Marinho
e403c35741 chg: fix: join bug 2025-04-09 00:14:20 +02:00
Felipe Marinho
a23293c0b7 chg: fix: scanner errors 2025-04-09 00:14:20 +02:00
Felipe Marinho
6fa4bd889f chg: fix: prioritize language 2025-04-09 00:14:20 +02:00
Felipe Marinho
81cc6d752b chg: fix: add all images in response 2025-04-09 00:14:20 +02:00
Felipe Marinho
88fff8ff24 chg: fix: do not prioritize original language 2025-04-09 00:14:20 +02:00
Felipe Marinho
8f2b487fb4 chg: fix: modify tmdb request 2025-04-09 00:14:20 +02:00
Felipe Marinho
196f5678df chg: add debug log 2025-04-09 00:14:20 +02:00
Felipe Marinho
db15a5649a chg: fix: always use iso639-1 when calling function 2025-04-09 00:14:20 +02:00
Felipe Marinho
beb0946802 debug 2025-04-09 00:14:20 +02:00
Felipe Marinho
a1cd3ba752 chg: docs: add missing parameter docs 2025-04-09 00:14:20 +02:00
Felipe Marinho
7de11919ad chg: feat: add localized image priorization 2025-04-09 00:14:20 +02:00
60764f6c06 Add nextup/continue watching routes (#883) 2025-04-09 00:01:52 +02:00
7bd1de3df6 Fix nextEntry query in history (alias mismatch) 2025-04-09 00:00:16 +02:00
20f8640790 Test nextup 2025-04-08 23:47:55 +02:00
e1b428e8ce Fix nextEntry calculation when adding to watchlist 2025-04-08 23:39:50 +02:00
144e08a99c Fix with=nextEntry 2025-04-08 23:39:50 +02:00
d6d3540b16 Fix history percent calculation 2025-04-08 23:39:50 +02:00
09dd78b272 Fix nextEntry & lastPlayedAt calculations on history/watchlist 2025-04-08 23:39:50 +02:00
67d7643261 Add lastPlayedAt in watchlists & sort nextup with it 2025-04-08 23:39:50 +02:00
d8566355bb Add nextup routes 2025-04-08 23:39:50 +02:00
68270c1343 Read `preferOriginal from jwt settings (#882) 2025-04-08 09:36:14 +02:00
c8742605ff Read `preferOriginal from jwt settings 2025-04-08 09:34:52 +02:00
9991da4fe1 Create history APIs (#881) 2025-04-08 00:23:34 +02:00
4cf67c3247 Sql cleanups 2025-04-08 00:22:23 +02:00
69006478cb Update watchlist when inserting into history 2025-04-07 22:53:07 +02:00
c0e00c0fd4 Handle duplicated entries in the history 2025-04-07 21:40:41 +02:00
e32fc229f8 Fix history population (drizzle patch) 2025-04-07 21:24:04 +02:00
c48815a71a Add history tests 2025-04-07 19:34:10 +02:00
e2fa3af1e8 Add route to batch populate the history 2025-04-07 19:07:05 +02:00
fef9e844a1 Add /profile/:id/history api 2025-04-07 18:27:13 +02:00
4ba7750012 Create history api 2025-04-07 18:27:13 +02:00
df7d109c34 Cleanup default watchlist sort 2025-04-07 18:27:13 +02:00
880a85ff8d Move watchlist controller to profile dir 2025-04-07 18:27:13 +02:00
572e763a61 Add watchStatus apis (#874) 2025-04-07 16:08:25 +02:00
080da9bc27 Fix tests & misc errors 2025-04-07 15:40:32 +02:00
db0b244286 Handle profiles creation in kyoo db schema 2025-04-07 12:41:41 +02:00
59533e5f0c Handle 404 for user accounts 2025-04-07 12:40:11 +02:00
b3edf31afc Create simple watchlist tests 2025-04-07 12:40:11 +02:00
bf361a79d1 Better movie/serie watchlist types 2025-04-07 12:40:11 +02:00
83d8462003 Add watchstatus create/edit apis 2025-04-07 12:40:11 +02:00
3f5af4b7fa Fix FIRST_USER_CLAIMS 2025-04-07 12:40:11 +02:00
18eb1b02a3 Add /users/:username in keibi 2025-04-07 12:40:11 +02:00
4b0100c52d Create watchlist read api 2025-04-07 12:40:11 +02:00
a7f355531d Add function to fetch user info from api 2025-04-07 12:40:11 +02:00
aa9476680c Allow filter & sort by watchStatus 2025-04-07 12:40:11 +02:00
b4e8fbdd26 chore(deps): update dependency go to v1.24.2 (#875) 2025-04-07 11:15:19 +02:00
renovate[bot]
d7dc92a8ca chore(deps): update dependency go to v1.24.2 2025-04-07 08:46:48 +00:00
148fd6b2e5 chore(deps): update helm release rabbitmq to v15.4.1 (#876) 2025-04-07 10:44:52 +02:00
renovate[bot]
c9f93c5ab3 chore(deps): update helm release rabbitmq to v15.4.1 2025-04-07 08:44:00 +00:00
a83fa90482 chore(deps): update dependency nswag.aspnetcore to 14.3.0 (#877) 2025-04-07 10:42:59 +02:00
renovate[bot]
427376524f chore(deps): update dependency nswag.aspnetcore to 14.3.0 2025-04-07 02:29:19 +00:00
acelinkio
d38d2b7006 chore(deps): update helm release postgresql to v16.6.0 (#878) 2025-04-06 19:27:53 -07:00
renovate[bot]
008dcc6e64 chore(deps): update helm release postgresql to v16.6.0 2025-04-07 02:15:32 +00:00
341322d625 Add watch status in entries, movies & series (#843) 2025-04-06 22:07:59 +02:00
5994b8bc02 Fix aliases issues in jsonBuildObject 2025-04-06 22:02:24 +02:00
5a6e29e57a Fix guess's sub/sid format 2025-04-06 19:52:54 +02:00
74ee45244b Support nextEntry in /series/{id} 2025-04-06 19:32:48 +02:00
c3abd7c61b Handle watch status on entries 2025-04-06 18:25:41 +02:00
11e1c59698 Handle watchstatus on movies/series 2025-04-06 18:25:28 +02:00
22754442ad Create migration for watchlist/history/profiles 2025-04-06 18:24:49 +02:00
54131b6762 wip: nextEntry 2025-04-06 14:54:50 +02:00
1943eca52b Use the same subquery (videos/progress) for entries & firstEntry 2025-04-06 14:54:50 +02:00
be35a4f0d9 Add percent in movie's watchlist 2025-04-06 14:54:50 +02:00
32cc6e7910 Add watch status type in movies/series 2025-04-06 14:54:50 +02:00
e489d0c445 Add watchlist table 2025-04-06 14:54:50 +02:00
31a749b5ed Add progress in /series/:id?width=firstEntry 2025-04-06 14:54:50 +02:00
be2e5e5ccf Fix drizzle patch for lateral join 2025-04-06 14:54:50 +02:00
6ecaec2dee Add progress status in every entry 2025-04-06 14:54:50 +02:00
781a6a8196 Add history table 2025-04-06 14:54:49 +02:00
e9db7b6285 Add edit user/settings route + check for permissions (#873) 2025-04-06 14:41:01 +02:00
29704e2f26 Fix edit settings test 2025-04-06 14:36:03 +02:00
026ad817bc Format stuff 2025-04-06 14:24:43 +02:00
dcbe817d60 Use additionalProperties (elysiajs/elysia#1159) 2025-04-06 14:24:03 +02:00
0aab4cd84c Forge jwt for tests 2025-04-06 14:24:03 +02:00
49f700ca6e Check for permissions on each routes 2025-04-06 14:24:03 +02:00
8110f7de66 Add tests for edit settings & password 2025-04-06 14:24:03 +02:00
31d545530b Add edit password 2025-04-05 23:49:53 +02:00
dbe8e319c8 Add edit user/settings route 2025-04-05 23:49:53 +02:00
a903d88a66 Auth cleanups (#872) 2025-04-05 01:25:30 +02:00
d4fbba8aeb Revert labstack/echo-jwt#13 2025-04-05 00:46:30 +02:00
d88160218b Fix tests 2025-04-05 00:46:22 +02:00
6d8697cd9d Convert robot tests to hurl 2025-04-05 00:28:24 +02:00
c5a676b2a5 Add guest handling 2025-04-05 00:28:24 +02:00
431055ec49 Add custom claims for first user 2025-04-05 00:28:24 +02:00
8ef4fe5e55 Remove db conf handling and read private key from storage 2025-04-04 22:44:44 +02:00
92753b72d3 Add a middleware in keibi to convert session token to jwt 2025-04-04 22:44:44 +02:00
411f6dcfba Use pages for users paginations 2025-04-04 22:44:44 +02:00
076d5a0dbd Use KError instead of problem details (like the api) 2025-04-04 22:44:44 +02:00
b81c94f2da Cleanup doc of users routes 2025-04-04 22:44:44 +02:00
f53e71afff Add doc for session routes 2025-04-04 22:44:44 +02:00
8fe50ad00b Add examples for jwt routes of keibi 2025-04-04 22:44:44 +02:00
65a7f62fd1 Validate issuer & allow unlogged routes 2025-04-04 22:44:44 +02:00
d0d12cc5f6 Add common swagger that combine auth & api 2025-04-04 22:44:44 +02:00
4dbb41f008 Translations update from Hosted Weblate (#870) 2025-04-02 09:32:40 +02:00
LucaNori
a84ecfcae0 Translated using Weblate (Italian)
Currently translated at 67.9% (142 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/it/
2025-04-01 19:58:45 +02:00
2f85253ae4 Update Helm release postgresql to v16.5.6 (#866) 2025-03-31 16:46:10 +02:00
renovate[bot]
f522ee6481 Update Helm release postgresql to v16.5.6 2025-03-31 03:31:17 +00:00
f14301f9ac Translations update from Hosted Weblate (#865) 2025-03-30 22:30:48 +02:00
loïc poisot
10e5700904 Translated using Weblate (French)
Currently translated at 100.0% (209 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/fr/
2025-03-30 21:26:43 +02:00
6d09c3354c Integerate the auth service to the api (#857) 2025-03-25 11:22:12 +01:00
0e81c11f75 Use echo-jwt 4.2 to prevent breaking change 2025-03-25 10:53:27 +01:00
1f8652e06c Validate jwt claims 2025-03-25 10:27:03 +01:00
bcded031e2 Use jwks in elysia 2025-03-25 10:27:03 +01:00
161e4943a1 Add openid-configuration just for jwks_uri (for jwt.io) 2025-03-25 10:27:03 +01:00
9dc1087273 Use 30s interval healthchecks 2025-03-25 10:27:03 +01:00
6391a99bb9 Switch to jwks instead of custom /info 2025-03-25 10:27:03 +01:00
068b19c936 Create auth middleware in elysia 2025-03-25 10:27:03 +01:00
50549f20de Rename base file 2025-03-25 10:27:03 +01:00
825619b11d Make /jwt return an Authorization header for traefik 2025-03-25 10:27:03 +01:00
e6e2f8ce91 Add /health route in the api 2025-03-25 10:27:03 +01:00
61151478e4 Fix phantom token middleware 2025-03-25 10:27:03 +01:00
4cf5adda9a Fix api's traefik rule 2025-03-25 10:27:03 +01:00
204344955e Add KYOO_PREFIX handling in api's redirect 2025-03-25 10:27:03 +01:00
92b0076bef Run go mod download in transcoder's Dockerfile.dev 2025-03-25 10:27:03 +01:00
7ec940a8dc Add healthchecks for auth 2025-03-25 10:27:03 +01:00
b94a6a652e Push generated files in auth to make tools happy 2025-03-25 10:27:03 +01:00
23adc6033e Update go modules 2025-03-25 10:27:03 +01:00
631967567f Add traefik middleware for phantom-tokens 2025-03-25 10:27:03 +01:00
808ee3a8c2 Translations update from Hosted Weblate (#860) 2025-03-25 00:31:59 +01:00
Eloi Barcon Piñeiro
aec2b0d9bf Translated using Weblate (Galician)
Currently translated at 24.8% (52 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/gl/
2025-03-24 18:15:18 +00:00
Eloi Barcon Piñeiro
c08e233bfd Added translation using Weblate (Galician) 2025-03-24 18:15:18 +00:00
Eloi Barcon Piñeiro
b8986d17e4 Translated using Weblate (Spanish)
Currently translated at 100.0% (209 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/
2025-03-24 18:15:17 +00:00
02ad247468 Update Helm release rabbitmq to v15.4.0 (#861) 2025-03-24 19:15:12 +01:00
renovate[bot]
8214deaeb2 Update Helm release rabbitmq to v15.4.0 2025-03-24 16:37:13 +00:00
ecee7255ed Update Helm release postgresql to v16.5.2 (#858) 2025-03-24 09:22:49 +01:00
renovate[bot]
0ce178595e Update Helm release postgresql to v16.5.2 2025-03-24 02:02:05 +00:00
792e8d5974 Translations update from Hosted Weblate (#855) 2025-03-22 12:10:58 +01:00
Abdullah
c61ca4021c Translated using Weblate (Arabic)
Currently translated at 100.0% (209 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ar/
2025-03-21 20:27:39 +01:00
15019152d3 Translations update from Hosted Weblate (#854) 2025-03-20 23:15:53 +01:00
Abdullah
7cd53ca867 Translated using Weblate (Arabic)
Currently translated at 69.8% (146 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ar/
2025-03-20 22:45:50 +01:00
Abdullah
b3bfc97469 Translated using Weblate (Arabic)
Currently translated at 68.8% (144 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ar/
2025-03-20 22:44:40 +01:00
d34ab4f0f0 Translations update from Hosted Weblate (#853) 2025-03-20 09:32:14 +01:00
Abdullah
3777908d57 Translated using Weblate (Arabic)
Currently translated at 66.5% (139 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ar/
2025-03-20 07:56:58 +01:00
Abdullah
1e0618e4be Translated using Weblate (Arabic)
Currently translated at 20.0% (42 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ar/
2025-03-20 00:07:02 +01:00
Amir
f0cabb4f5d Translated using Weblate (Amharic)
Currently translated at 18.6% (39 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/am/
2025-03-20 00:07:01 +01:00
b77aa39770 Add routes to access images (#852) 2025-03-19 18:21:17 +01:00
4ce8ce7f6d Add /studios/:id/logo & /staff/:id/image 2025-03-19 18:19:23 +01:00
27c5b34c5a Cleanup shows route & handle random 2025-03-19 18:19:23 +01:00
6ff00a1133 Add all movies image routes 2025-03-19 18:19:23 +01:00
7d3413a3d5 Extract get image logic to a function 2025-03-19 18:19:23 +01:00
9905587c83 Add first /poster route 2025-03-19 18:19:23 +01:00
47554590a9 Add image handler by id with quality control 2025-03-19 18:19:23 +01:00
c114af0856 Properly handle image download failures 2025-03-19 18:19:23 +01:00
5da13f8f41 Add image downloading + blurhash (#846) 2025-03-18 22:09:08 +01:00
51558db1b2 Add image downloading test 2025-03-18 22:07:37 +01:00
0a729ccf75 Migrate mqueue 2025-03-18 22:05:45 +01:00
f11e1b56db Fix tests
Also fix sharp on nixos
2025-03-18 22:05:45 +01:00
71b57c50e7 Handle image in jsonb 2025-03-18 22:05:45 +01:00
6e642db7db Cleanup original images handling 2025-03-18 22:05:45 +01:00
9ef114b91a Use reworked image queue in every insert 2025-03-18 22:05:45 +01:00
71b8cbca4a Create task runner to download images 2025-03-18 22:05:45 +01:00
67511a3aa8 Add function to download images, resize them & blurhash 2025-03-18 22:05:45 +01:00
1a11bc3492 wip: Add image downloading 2025-03-18 22:05:45 +01:00
82d8a00eb4 Update dependency System.ComponentModel.Composition to 9.0.3 (#847) 2025-03-17 09:46:59 +01:00
renovate[bot]
7deb31aea5 Update dependency System.ComponentModel.Composition to 9.0.3 2025-03-17 08:42:38 +00:00
e75321879c Update dotnet monorepo to 8.0.14 (#848) 2025-03-17 09:41:50 +01:00
renovate[bot]
8f98e75534 Update dotnet monorepo to 8.0.14 2025-03-17 08:37:53 +00:00
8ecb036ec3 Update Helm release postgresql to v16.5.0 (#849) 2025-03-17 09:37:04 +01:00
renovate[bot]
5431d50005 Update Helm release postgresql to v16.5.0 2025-03-17 08:35:51 +00:00
7fcae39567 Update dependency node to v22 (#851) 2025-03-17 09:34:08 +01:00
renovate[bot]
f2e05e21eb Update dependency node to v22 2025-03-17 03:07:11 +00:00
acelinkio
998cdcb80a Update Helm release postgresql to v16.4.16 (#836) 2025-03-13 16:28:24 -07:00
acelinkio
58951b1a20 Merge branch 'master' into renovate/postgresql-16.x 2025-03-13 16:27:18 -07:00
acelinkio
f7ee8a0a15 Update Helm release rabbitmq to v15.3.3 (#837) 2025-03-13 16:27:07 -07:00
renovate[bot]
f894a5db21 Update Helm release rabbitmq to v15.3.3 2025-03-13 16:34:41 +00:00
renovate[bot]
26c3b093b3 Update Helm release postgresql to v16.4.16 2025-03-13 16:34:38 +00:00
31bfd58160 Translations update from Hosted Weblate (#845) 2025-03-13 17:33:40 +01:00
Akhil Raj
53ecb31470 Translated using Weblate (Malayalam)
Currently translated at 2.3% (5 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ml/
2025-03-13 17:02:10 +01:00
d08febf803 Bump golang.org/x/net from 0.33.0 to 0.36.0 in /transcoder (#844) 2025-03-13 09:38:33 +01:00
dependabot[bot]
aface8f326 Bump golang.org/x/net from 0.33.0 to 0.36.0 in /transcoder
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.33.0 to 0.36.0.
- [Commits](https://github.com/golang/net/compare/v0.33.0...v0.36.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2025-03-13 01:33:40 +00:00
Bryan J.
9983f0c48a Update README.md 2025-03-11 09:27:28 +01:00
27aff3cf8f Add with=firstEntry (#841) 2025-03-10 19:34:39 +01:00
renovate[bot]
6b4bab7905 Update module golang.org/x/text to v0.23.0 2025-03-10 19:34:10 +01:00
5ae04c6dac Add with=firstEntry 2025-03-10 19:32:47 +01:00
458eb2c387 Create /news (#839) 2025-03-10 18:58:13 +01:00
f6b10738da Migrate & test 2025-03-10 18:56:52 +01:00
2cebdcd63e Add /news route 2025-03-10 18:56:52 +01:00
6dec212a2c Add DELETE /videos 2025-03-10 18:56:52 +01:00
621d4752ba Add availableSince field on entries (will be used for /news) 2025-03-10 18:56:52 +01:00
878d72f3a4 Cleanup availableCount & episodeCount update transaction 2025-03-10 18:56:52 +01:00
8687cf8de0 Add staff & role APIs (#835) 2025-03-10 14:11:59 +01:00
dfaf5480ad Add tests & fix roles/staff 2025-03-10 14:10:28 +01:00
e3a537896a Add staff migrations & basic tests 2025-03-10 11:29:12 +01:00
25f042fbd7 Add staff examples 2025-03-10 10:22:31 +01:00
43a128ebe8 Add staff seeding 2025-03-10 01:31:51 +01:00
46833ac06f Rework sort to handle multiples tables 2025-03-10 00:22:32 +01:00
039880d812 Add /series/:id/staff 2025-03-10 00:22:32 +01:00
18532b80b1 Add /movies/:id/staff 2025-03-10 00:22:32 +01:00
cba47ca346 Add /staff/:id/roles 2025-03-10 00:22:32 +01:00
7e6592fa2e Implement routes in /shows 2025-03-10 00:22:32 +01:00
8d7d5f3e7e Add /staff routes 2025-03-10 00:22:32 +01:00
bcec4c31d1 Add staff types & db schema 2025-03-10 00:22:32 +01:00
06458adc31 Add with=videos support for movies (#834) 2025-03-09 18:45:47 +01:00
b093df96ec Add with=videos support for movies 2025-03-09 18:44:12 +01:00
e0ad458d73 Add original name & latinName in series/movie (#833) 2025-03-09 18:17:36 +01:00
4b46963eff Rework /studios/:id to use relational query 2025-03-09 18:16:04 +01:00
34926dab51 Fix entries's video retrieval 2025-03-09 18:16:04 +01:00
d61573668b Use original with collections too 2025-03-09 18:16:04 +01:00
aab38f6a89 Rework & type relations 2025-03-09 18:16:04 +01:00
f9ff6c00d7 Add studios in new with= handling 2025-03-09 18:16:04 +01:00
fc60fcc7c4 Cleanup video join in entries 2025-03-09 18:16:04 +01:00
c161d680e3 Add with=translations in the sql builder logic 2025-03-09 18:16:04 +01:00
3f77a1bda5 Fix tests 2025-03-09 18:16:04 +01:00
fd57f506c1 Proper error handling for missing original 2025-03-09 18:16:04 +01:00
cca0da4bf6 Use sql builder instead of orm for /movie 2025-03-09 18:16:04 +01:00
16fb638231 Make guess field of video mandatory 2025-03-09 18:16:04 +01:00
ac7b589d76 Fix preferOriginal 2025-03-09 18:16:03 +01:00
3f188e27a1 Only specify kind in movie/serie/collection in /shows 2025-03-09 18:16:03 +01:00
74f2229dcd Migrate original handling 2025-03-09 18:16:03 +01:00
67dc251489 Rework original handling in seeding 2025-03-09 18:16:03 +01:00
b69cb05088 Type guess info in db schema 2025-03-09 18:16:03 +01:00
6b0e3e7577 Add original name & latinName in series/movie 2025-03-09 18:16:03 +01:00
74a509ec03 Add entriesCount, availableCount & isAvailable (#831) 2025-03-08 14:56:54 +01:00
0e4f678e2c Fix test 2025-03-08 14:55:40 +01:00
269003c25d Add back isAvailable for movies 2025-03-08 14:51:14 +01:00
bbbf7b32e0 Exclude extras & test availableCount/entryCount 2025-03-08 14:51:14 +01:00
54ee704ab9 Create migration & fix update statment 2025-03-08 14:51:14 +01:00
c58cb3ef78 Cleanup preferOriginal handling 2025-03-08 14:51:14 +01:00
194428ecfe Compute the number of entries available for a show 2025-03-08 14:51:14 +01:00
dcf26b94cd Add entries count in series 2025-03-08 14:51:14 +01:00
d9e3b3a94b Add available videos in /entries response (#830) 2025-03-06 22:24:13 +01:00
e8ffe31330 Fix docker build 2025-03-06 22:22:35 +01:00
fd2f3be663 Dont send videos with extras 2025-03-06 14:28:19 +01:00
e86ab9c081 Fix entries test with videos 2025-03-06 14:28:18 +01:00
66fadb2b20 Remove schema from validation errors 2025-03-06 14:28:18 +01:00
70d0d480f6 Test & fix entry video join 2025-03-06 14:28:18 +01:00
477fb24036 Patch drizzle to add leftJoinLateral 2025-03-06 14:26:24 +01:00
0558222150 Add videos in /shows/:id/entries 2025-03-06 14:26:24 +01:00
acelinkio
a430819d22 Update Helm release postgresql to v16.4.14 (#825) 2025-03-03 12:46:36 -08:00
renovate[bot]
4e24d01b3f Update Helm release postgresql to v16.4.14 2025-03-03 20:45:25 +00:00
acelinkio
85a5fd0846 Update Helm release rabbitmq to v15.3.2 (#826) 2025-03-03 12:44:28 -08:00
renovate[bot]
6781428791 Update Helm release rabbitmq to v15.3.2 2025-03-03 17:14:31 +00:00
250c9c8ff9 Add studios (#824) 2025-03-03 18:13:17 +01:00
cdf4ab4941 Test ?with= 2025-03-03 18:11:39 +01:00
750434465d Add ?with=studios in movies & series 2025-03-03 17:54:35 +01:00
6cf8947c80 Fix swagger response of /studios/:id 2025-03-03 12:09:50 +01:00
2aada33a6a Fix swagger examples for externalId 2025-03-03 11:45:41 +01:00
bf16231350 Add /studios & /studios/random 2025-03-03 11:45:18 +01:00
44658ce6b0 Add /studios/:id 2025-03-03 10:01:41 +01:00
03d071acb4 Add /studios/:id/{movies,series} 2025-03-03 09:41:24 +01:00
7492bff7c8 Use guards instead of adding type info multiples times 2025-03-03 09:39:13 +01:00
ff5fc69d41 Add get by studio tests 2025-03-03 09:36:38 +01:00
4d9547952e Cleanup history in mermaid schema 2025-03-03 00:09:37 +01:00
6d2c9958f9 Fix api mermaid indentation 2025-03-03 00:01:37 +01:00
97a9a406bb Format stuff 2025-03-02 23:50:15 +01:00
adaa892a26 Add GET /studios/:id/shows 2025-03-02 23:47:02 +01:00
2301e48321 Use db metadata on entries 2025-03-02 23:47:02 +01:00
710675180c Add studio insert method 2025-03-02 23:47:02 +01:00
1cc26c5985 Fix typescript compilation 2025-03-02 23:47:02 +01:00
31d95d7fd7 Add studio migration 2025-03-02 23:47:02 +01:00
12faca5fb5 Add db-metadata type helper 2025-03-02 23:47:01 +01:00
e32c83180e Add studio type 2025-03-02 23:46:24 +01:00
73250f2bba Add mixed /shows route (that return movies, series & collections) (#823) 2025-03-02 19:47:59 +01:00
648fb6825a Fix test 2025-03-02 19:46:28 +01:00
4f73e76a34 Add /collections/:id/shows 2025-03-02 19:44:45 +01:00
68d4958e3a Add /shows & /shows/random routes 2025-03-02 19:44:45 +01:00
9ff62ef050 Add /series & /collections routes (#822) 2025-03-02 19:13:04 +01:00
9f974de245 Add /collections/:id/series & /collections/:id/movies 2025-03-02 19:09:28 +01:00
d53947265f Add basic collection routes 2025-03-02 19:09:28 +01:00
662400da13 Add GET /series/{id} (based on movie's get) 2025-03-02 18:53:31 +01:00
f143511e14 Add /series/random 2025-03-02 18:12:29 +01:00
cc221c560d Add GET /series (using the same logic as /movies) 2025-03-02 18:09:25 +01:00
24f44de7c0 Move movie controller to shows subdir 2025-03-02 17:39:49 +01:00
9b1bd69eae Add collections in v5 (#821) 2025-03-02 17:32:26 +01:00
019be569dd Format stuff 2025-03-02 17:31:16 +01:00
98c6263036 Add basic collection test 2025-03-02 17:31:16 +01:00
4538d9ce98 Add collection example 2025-03-02 17:28:38 +01:00
e8c9dfce56 Create insert method 2025-03-02 17:28:38 +01:00
fc9afa5ede Allow collections to be created with movies or series 2025-03-02 17:28:38 +01:00
dbfe836ce3 Add collection type in database 2025-03-02 17:28:38 +01:00
5535507469 Rework collection relation on db schema 2025-03-02 17:28:38 +01:00
01183df4e9 Define collection type 2025-03-02 00:19:32 +01:00
43465834c3 Specify languages when needed 2025-03-01 23:48:21 +01:00
0a1ca61dfb Fix typescript compilation 2025-03-01 23:48:21 +01:00
6402b3cae6 Add unknown video example 2025-03-01 23:48:21 +01:00
c96365fe0a Fix race condition with movies test 2025-03-01 23:48:21 +01:00
84d9ccb8bb Test extras 2025-03-01 23:48:21 +01:00
655f677e91 Format stuff 2025-03-01 23:48:21 +01:00
5483e34c5e Fix season get 2025-03-01 23:48:21 +01:00
b5460682c9 Test get seasons 2025-03-01 23:48:21 +01:00
6a30173628 Fix poster creation of movie entries 2025-03-01 23:48:21 +01:00
9aa7815f57 Use integer instead of numbers where it make sense 2025-03-01 23:48:21 +01:00
4ee6493eb8 Fix 404 handling for entries 2025-03-01 23:48:21 +01:00
fb7635ef56 Cleanup swagger & add examples for entries 2025-03-01 23:48:21 +01:00
5e0ba7f630 Fix path params making items not appear in swagger 2025-03-01 23:48:21 +01:00
caeef0417c Use baseline's elysia/swagger instead of fork now that it works 2025-03-01 23:48:21 +01:00
b70f66960d wip 2025-03-01 23:48:21 +01:00
89914f6c95 Format stuff 2025-03-01 23:48:21 +01:00
1476505262 Add /unknowns route 2025-03-01 23:48:21 +01:00
29696c378a Add /series/:id/extras route 2025-03-01 23:48:21 +01:00
a5483b4ca1 Fix typing & extra handling when fetching entries from db 2025-03-01 23:48:21 +01:00
c70e11d36a Prettify entry types 2025-03-01 23:48:21 +01:00
c730d47cd9 Add entries controller 2025-03-01 23:48:21 +01:00
renovate[bot]
200ea580f0 chore(deps): update helm release meilisearch to v0.12.0 2025-02-24 09:40:23 +01:00
renovate[bot]
a90af3be49 chore(deps): update helm release postgresql to v16.4.9 2025-02-24 09:38:24 +01:00
renovate[bot]
bcdf99576c chore(deps): update golang docker tag to v1.24 2025-02-24 09:25:33 +01:00
9b526461c6 Fix pg_trgm word similarly threshold even for the first session 2025-02-22 19:30:19 +01:00
1bca9f47dd Update elysia again (fix regression) 2025-02-22 19:30:19 +01:00
3f09ca93a3 Pin drizzle to 0.39.0 due to https://github.com/drizzle-team/drizzle-orm/issues/4060 2025-02-22 19:30:19 +01:00
a370048a12 Update elysia and remove workaround 2025-02-22 19:30:19 +01:00
b18ab07e3e Fix create extension place (move out of migration) 2025-02-22 19:30:19 +01:00
7fb23bb490 Add ci to run bun test 2025-02-22 19:30:19 +01:00
renovate[bot]
1c8571e406 fix(deps): update module golang.org/x/text to v0.22.0 2025-02-17 10:49:09 +01:00
renovate[bot]
40949e1edb chore(deps): update dotnet monorepo to 8.0.13 2025-02-17 10:31:08 +01:00
renovate[bot]
0f0fac26db chore(deps): update dependency system.componentmodel.composition to 9.0.2 2025-02-17 10:27:16 +01:00
renovate[bot]
d6e2d34710 chore(deps): update helm release postgresql to v16.4.7 2025-02-17 10:23:27 +01:00
renovate[bot]
c9f854c562 chore(deps): update helm release rabbitmq to v15.3.1 2025-02-17 10:20:48 +01:00
acelinkio
f5edea5c30 chore(deps): update helm release rabbitmq to v15.2.5 (#805) 2025-02-09 17:28:51 -08:00
renovate[bot]
0a137e06f9 chore(deps): update helm release rabbitmq to v15.2.5 2025-02-10 01:27:33 +00:00
acelinkio
1398b3112c chore(deps): update helm release postgresql to v16.4.6 (#804) 2025-02-09 17:26:56 -08:00
renovate[bot]
17c4aee408 chore(deps): update helm release postgresql to v16.4.6 2025-02-10 01:23:26 +00:00
renovate[bot]
0874c019a2 chore(deps): update helm release rabbitmq to v15.2.4 2025-02-03 14:22:59 +01:00
acelinkio
208149963c chart: forgot to add ingress to readme (#800) 2025-01-31 08:19:37 -08:00
Arlan Lloyd
3fec5a1a71 fix spelling mistake 2025-01-31 16:14:16 +00:00
acelinkio
e5ccfba4f1 Merge branch 'master' into chart/update-ingress 2025-01-31 08:13:08 -08:00
Arlan Lloyd
fd1e841150 small wording change 2025-01-31 09:45:58 +01:00
Arlan Lloyd
bc98bb2d60 readme update 2025-01-31 09:45:58 +01:00
Arlan Lloyd
284db713b3 forgot to add ingress to readme 2025-01-31 04:37:33 +00:00
acelinkio
319c65a859 chart: doc update + small qol (#799) 2025-01-30 20:31:11 -08:00
Arlan Lloyd
d374108b37 keep using pvc for example 2025-01-31 04:27:51 +00:00
Arlan Lloyd
bd89f4ac32 update chart notes & small edits 2025-01-31 04:11:43 +00:00
1b94d783d9 Add POST /series that handle seasons & entries (#797) 2025-01-30 20:10:43 +01:00
b6dff90ccd Disable biome lint 2025-01-30 20:09:21 +01:00
b16c2374c4 Format stuff 2025-01-30 20:03:42 +01:00
30bf2d9207 Test entries seeding 2025-01-30 20:03:42 +01:00
4424e9b40a Handle extra seeding 2025-01-30 20:03:42 +01:00
32a1e89b27 Add insert seasons 2025-01-30 20:03:42 +01:00
5d8d5721af Split helpers in multiples files 2025-01-30 20:03:42 +01:00
f9554bd128 Define seasons relations 2025-01-30 20:03:42 +01:00
b1df97f767 Type extra & allow movie entries to specify a slug on seed 2025-01-30 20:03:42 +01:00
cf59695e09 Fix need-rendering test 2025-01-30 20:03:42 +01:00
1a2ab48c73 Start the smart video controller 2025-01-30 20:03:42 +01:00
015f58226a Update drizzle + migration 2025-01-30 20:03:42 +01:00
740bf7adaa Remove tests afterAll 2025-01-30 20:03:42 +01:00
7906374553 Add history & from in the guess type 2025-01-30 20:03:42 +01:00
e9c7cfe832 Fix entries insertion (special numbers not saved) 2025-01-30 20:03:42 +01:00
b0637aeb6a Type guess from videos 2025-01-30 20:03:42 +01:00
b262aeed5d Better need rendering calculation when inserting entries 2025-01-30 20:03:42 +01:00
f2c1982afa Test videos creation of slugs 2025-01-30 20:03:42 +01:00
e5bb462e36 Update test helpers 2025-01-30 20:03:42 +01:00
fabf6b6863 Define relations on evj 2025-01-30 20:03:42 +01:00
2588eef23b Create values helper & fix video join insertion 2025-01-30 20:03:42 +01:00
a216fd0d67 Add migration for entries 2025-01-30 20:03:42 +01:00
8d6121d8b0 Handle video joint creation with entries 2025-01-30 20:03:42 +01:00
2510420cea Fix seed entries type 2025-01-30 20:03:42 +01:00
0939289e2c Add seed entry capabilities 2025-01-30 20:03:42 +01:00
5ca0ef08d4 Make processImages synchronous 2025-01-30 20:03:42 +01:00
962672e4ed Start series insert 2025-01-30 20:03:42 +01:00
470a8deae9 Start entry insert 2025-01-30 20:03:42 +01:00
ec3d48ac79 Extract movie insert to a show insert method 2025-01-30 20:03:42 +01:00
b9c022f614 Add seed entry types 2025-01-30 20:03:42 +01:00
d4257c1d02 Properly register examples for seasons 2025-01-30 20:03:42 +01:00
acelinkio
b3b9ec17a7 chore(deps): update helm release postgresql to v16.4.5 (#798) 2025-01-29 08:28:42 -08:00
renovate[bot]
b9ab977253 chore(deps): update helm release postgresql to v16.4.5 2025-01-27 01:47:06 +00:00
404855b637 Revert "Add path filters for robot ci"
This reverts commit 0e9281fb73.
2025-01-25 15:12:22 +01:00
e2d34a993b Format stuff 2025-01-25 15:12:22 +01:00
7868731922 Add seasons index and fix nullability 2025-01-25 15:12:22 +01:00
bb2630431a Add seasons controller 2025-01-25 15:12:22 +01:00
a6ac5dfb75 Cleanup translation schema for series + example 2025-01-25 15:12:22 +01:00
9f929eeb7a Move description to common types 2025-01-25 15:12:22 +01:00
9f06353f60 Add path filters for robot ci 2025-01-25 15:12:22 +01:00
9abe7f191a Test & fix search 2025-01-24 22:48:03 +01:00
5bf30af564 Format stuff + update packages 2025-01-24 22:48:03 +01:00
1634624701 Fix search sort 2025-01-24 22:48:03 +01:00
1e2fd919ff Add index migration 2025-01-24 22:48:03 +01:00
ce81caaf14 Allow filter on tags 2025-01-24 22:48:03 +01:00
426665c9d9 Allow filter string to match without quotes 2025-01-24 22:48:03 +01:00
1c0fdf6f89 wip 2025-01-24 22:48:03 +01:00
eaec881594 wip: Replace tsvector with trigram search 2025-01-24 22:48:03 +01:00
59aca6d520 Generate search vectors 2025-01-24 22:48:03 +01:00
988b705a30 Fix schema utils to make drizzle-kit work 2025-01-24 22:48:03 +01:00
a51de86c95 Stupid implementation of search, lots to fix 2025-01-24 22:48:03 +01:00
23dc0a2f88 Add search vector & index 2025-01-24 22:48:03 +01:00
26470136af Add indexes on the movie type 2025-01-24 22:48:03 +01:00
f756c001e5 Update meilisearch (#794) 2025-01-23 23:48:24 +01:00
e80440d413 Translations update from Hosted Weblate (#792) 2025-01-23 23:35:57 +01:00
6800c90ebf Added translation using Weblate (Icelandic) 2025-01-23 23:20:33 +01:00
f522a42560 Fix no resize transcode of 10bits items with hwaccel (#793) 2025-01-23 22:20:29 +00:00
401f1b5bc4 Translations update from Hosted Weblate (#791) 2025-01-21 09:09:41 +01:00
Evgeniy
346264f49a Translated using Weblate (Russian)
Currently translated at 100.0% (209 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ru/
2025-01-21 03:08:50 +01:00
Bruno “Brubo” Nimer
c721e2918f Translated using Weblate (Italian)
Currently translated at 49.7% (104 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/it/
2025-01-21 03:08:50 +01:00
renovate[bot]
8ed850469d chore(deps): update dotnet monorepo 2025-01-20 23:37:47 +01:00
renovate[bot]
451642c107 chore(deps): update dependency system.componentmodel.composition to 9.0.1 2025-01-20 23:33:43 +01:00
renovate[bot]
e937f44ba6 chore(deps): update traefik docker tag to v3.3 2025-01-20 23:30:26 +01:00
acelinkio
5c00c2b0c8 chore(deps): update helm release rabbitmq to v15.2.3 (#789) 2025-01-20 10:25:49 -08:00
renovate[bot]
7d468eb64d chore(deps): update helm release rabbitmq to v15.2.3 2025-01-20 18:23:44 +00:00
acelinkio
ce03f39c25 chore(deps): update helm release postgresql to v16.4.3 (#788) 2025-01-20 10:22:44 -08:00
renovate[bot]
11d0601ae7 chore(deps): update helm release postgresql to v16.4.3 2025-01-20 14:42:13 +00:00
acelinkio
1e44112444 chore(deps): update helm release postgresql to v16.4.2 (#786) 2025-01-19 20:15:49 -08:00
acelinkio
fb36a62104 Merge branch 'master' into renovate/postgresql-16.x 2025-01-19 19:45:17 -08:00
acelinkio
66f2c523cf chore(deps): update helm release rabbitmq to v15.2.2 (#785) 2025-01-19 19:45:04 -08:00
renovate[bot]
36877596ed chore(deps): update helm release postgresql to v16.4.2 2025-01-20 00:37:22 +00:00
renovate[bot]
360ee3e5a2 chore(deps): update helm release rabbitmq to v15.2.2 2025-01-20 00:37:19 +00:00
87314a0e96 Use bun build in the dockerfile 2025-01-18 16:39:40 +01:00
ce242bf1b4 Add dockerfile 2025-01-18 16:39:40 +01:00
a8fb84daf0 Format code 2025-01-18 16:39:40 +01:00
02d1197f6b Add ci for api 2025-01-18 16:39:40 +01:00
956ab51e1b Add a flag to retrieve all translations 2025-01-17 23:16:31 +01:00
02ddd1401b Add isAvailable 2025-01-17 23:16:31 +01:00
a734a40668 Add tests for preferOriginal in /movies 2025-01-17 18:49:24 +01:00
a558f47558 Test & Fix prefer original for /movies/{id} 2025-01-17 18:49:24 +01:00
7047304ae5 Handle 404 error better 2025-01-17 18:49:24 +01:00
9fc5f8a706 Fix /movies select distinct 2025-01-17 18:49:24 +01:00
7fcaf6490d Add original translation support on the /movies/{id} route 2025-01-17 18:49:24 +01:00
f3f69a0def Rewrite /movies/{id} to use the relational api 2025-01-17 18:49:24 +01:00
5ca1b19148 Add preferOriginal query param for /movies 2025-01-17 18:49:24 +01:00
7cc6e7e2d4 Handle fallback when creating new translations 2025-01-17 18:49:24 +01:00
4d0a6e5223 feat(api): random sort (#771) 2025-01-13 14:17:58 +01:00
d1609ddfbf Fix & test random slug reservation 2025-01-13 14:16:43 +01:00
1cdb372079 Fix & test /movies/random 2025-01-13 14:16:43 +01:00
b6f996139f Reserve the random slug 2025-01-13 14:16:43 +01:00
46570410ea Add seed in response if it was not specified 2025-01-13 14:16:43 +01:00
b9da57fd88 Cleanups 2025-01-13 14:16:43 +01:00
9a54266967 Add /movies/random route 2025-01-13 14:16:43 +01:00
8b7e109be3 Cleanup sort parsing 2025-01-13 14:16:43 +01:00
86d37514dc Fix after handling 2025-01-13 14:16:43 +01:00
Arthur Jamet
f490faa796 v5 api: Handle random in keyset paginate 2025-01-13 14:16:43 +01:00
Arthur Jamet
67ea86a955 v5 api: Random sort query parameter cannot be reversed 2025-01-13 14:16:43 +01:00
Arthur Jamet
2afccaa813 v5 api: Random query parameter becomes sort value 2025-01-13 14:16:43 +01:00
Arthur Jamet
0e230114a7 v5 api: Sort Movies Randomly, passing seed as query parameter 2025-01-13 14:16:42 +01:00
renovate[bot]
57ae120d4d Update dependency Serilog.AspNetCore to v9 (#777)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-13 09:46:08 +01:00
acelinkio
420d5238b2 Update Helm release postgresql to v16.3.5 (#773) 2025-01-12 16:49:00 -08:00
renovate[bot]
8f60a97043 Update Helm release postgresql to v16.3.5 2025-01-13 00:28:12 +00:00
3aee4bd3e2 v5 api: initial schemas, types & basic routes (#680) 2025-01-10 12:17:47 +01:00
fe6f4fd43b Fix null sorting 2025-01-10 12:16:33 +01:00
3547799079 Sort nulls at the end even in desc order 2025-01-10 12:16:33 +01:00
c71650d386 Test sort order with null values 2025-01-10 12:16:33 +01:00
e78f28ea71 Add test helpers 2025-01-10 12:16:32 +01:00
0555fcb9a5 Handle forced fallback on /movies 2025-01-10 12:16:32 +01:00
81958f6c3b Fix after when sorting with remmapped keys 2025-01-10 12:16:32 +01:00
6e293efc2b Remove page's prev & weird reverse handling 2025-01-10 12:16:32 +01:00
371d9148f4 wip 2025-01-10 12:16:32 +01:00
1389abb946 Fix prev/next generation 2025-01-10 12:16:32 +01:00
641ce4237e Use an array as a backing store for after 2025-01-10 12:16:32 +01:00
879d2959d5 Create page with next/prev url 2025-01-10 12:16:32 +01:00
50002907e3 Create keyset pagination function 2025-01-10 12:16:32 +01:00
482ad0dda2 Move sort parsing to typebox 2025-01-10 12:16:32 +01:00
0499be4194 Fix comment newline handling 2025-01-10 12:16:32 +01:00
3d6912b60d Handle filter parsing with typebox 2025-01-10 12:16:32 +01:00
efbec85b67 Update dependencies & switch to text lockfile 2025-01-10 12:16:32 +01:00
c14d4e0911 Add filter to drizzle converter 2025-01-10 12:16:32 +01:00
c71da66bb6 Add more complex tests 2025-01-10 12:16:32 +01:00
8531049716 Add tests for the filter parser 2025-01-10 12:16:32 +01:00
e960307172 Write filter grammar & fix priorities 2025-01-10 12:16:32 +01:00
e20e327286 Filter fixes 2025-01-10 12:16:32 +01:00
81b7d5558e Finish filter parser 2025-01-10 12:16:32 +01:00
df41694811 Start a filter parser 2025-01-10 12:16:32 +01:00
05d5ac5a75 Allow \n in doc comments 2025-01-10 12:16:32 +01:00
2fd6b85d7e Fix validation errors 2025-01-10 12:16:32 +01:00
587dc4f970 Add get /movies & sort api 2025-01-10 12:16:32 +01:00
a4853cb186 Test missing accept-language endpoint 2025-01-10 12:16:32 +01:00
3a7a12bfd3 Cleanup swagger examples 2025-01-10 12:16:32 +01:00
43ae26679a Fix type issues on get /movies 2025-01-10 12:16:32 +01:00
eea0f688a0 Make movie get work 2025-01-10 12:16:32 +01:00
9e1afca9ec Fix existing get movie & add test 2025-01-10 12:16:32 +01:00
c263dd770e Ensure image ids are human readable 2025-01-10 12:16:32 +01:00
0b77072b04 Small cleanups 2025-01-10 12:16:32 +01:00
0c0628529c Validate language tags 2025-01-10 12:16:32 +01:00
cdceb1a734 Add proper error type & error handling 2025-01-10 12:16:32 +01:00
c8c6cccf6a Handle and test slug reconciliation & conflicts 2025-01-10 12:16:32 +01:00
caa394e0da Create tests & cleanup for movies seeding 2025-01-10 12:16:32 +01:00
5e1e2fb6e2 Add tests setup for post /movies 2025-01-10 12:16:32 +01:00
24035c15bf Add 200/201 handling on post /movies + doc 2025-01-10 12:16:32 +01:00
5d24dcafd5 Handle conflicts as updates 2025-01-10 12:16:32 +01:00
cfe2cabfa4 wip: push movies could update items 2025-01-10 12:16:32 +01:00
55b3f1cc8c wip: upsert things 2025-01-10 12:16:32 +01:00
3d20f063e9 Create post /videos route 2025-01-10 12:16:32 +01:00
c20aa862a9 Move video slug to jointure 2025-01-10 12:16:32 +01:00
92ee0b2e7f wip: Allow videos to be joined on a post /movies 2025-01-10 12:16:32 +01:00
8253554304 Add many-to-many jointure between entries & videos 2025-01-10 12:16:32 +01:00
31b7c0e035 Move seed function to separate file 2025-01-10 12:16:32 +01:00
30d5d65755 Create movie seed route handler 2025-01-10 12:16:32 +01:00
1309749e46 Remove the option to create videos from post /movies 2025-01-10 12:16:32 +01:00
b63391d744 Cleanup schemas 2025-01-10 12:16:32 +01:00
b47c38ca76 Cleanup movie example in swagger 2025-01-10 12:16:32 +01:00
361c07ce53 Seed movie schema 2025-01-10 12:16:32 +01:00
b8b536632d Swagger setup 2025-01-10 12:16:32 +01:00
0edf216618 Splt translations for seasons & series + seed setup 2025-01-10 12:16:32 +01:00
887431a335 Update movie example (still need seed image update) 2025-01-10 12:16:32 +01:00
7ca441aaae Disable ts truncations 2025-01-10 12:16:32 +01:00
c5972bd15f Split translations for movies 2025-01-10 12:16:32 +01:00
b0dac24eea Use kind guards in registerExamples 2025-01-10 12:16:32 +01:00
cfe6ce9c7e Split entries & add translations types 2025-01-10 12:16:32 +01:00
97d9abca62 Add utils for validating slugs & languages 2025-01-10 12:16:32 +01:00
02ebb6b3f6 Add guesses in video db schema 2025-01-10 12:16:32 +01:00
d6cae5ace1 Small cleanups 2025-01-10 12:16:32 +01:00
47729d8373 Set order type to float 2025-01-10 12:16:32 +01:00
2a9ea5ecbf Add examples for series 2025-01-10 12:16:32 +01:00
4a9a768488 Add demmy season controller 2025-01-10 12:16:32 +01:00
0b0ae9abd3 Add season model 2025-01-10 12:16:32 +01:00
ed19413576 Remove serieId & seasonId from entry response 2025-01-10 12:16:32 +01:00
34e145ab23 Add seasons in db 2025-01-10 12:16:31 +01:00
ffa42de4f3 Cleanup external id types in db 2025-01-10 12:16:31 +01:00
84ce544f4d Add extra types (from #463). No backing store for now 2025-01-10 12:16:31 +01:00
29d11720a5 Add entries dummy controller & fix entries types 2025-01-10 12:16:31 +01:00
7071e07ef4 Define schema for all entries type 2025-01-10 12:16:31 +01:00
eb2d2009f7 Movie utils models to directory 2025-01-10 12:16:31 +01:00
c5a502ec32 Add serie model, dummy controller & example 2025-01-10 12:16:31 +01:00
89952185a9 Cleanup video schema & add descrpitions of api fields 2025-01-10 12:16:31 +01:00
039c19f61c Create dummy video controller 2025-01-10 12:16:31 +01:00
372c1f6875 Cleanup example registration & add descriptions 2025-01-10 12:16:31 +01:00
3f97ba729d Fix entries fk and manually fix migrations 2025-01-10 12:16:31 +01:00
143ac6c721 Regenerate migrations 2025-01-10 12:16:31 +01:00
0759d6c2c4 Update schema for new drizzle version and fix some config issue 2025-01-10 12:16:31 +01:00
e2e04b88f4 Upgrade packages 2025-01-10 12:16:31 +01:00
d3fc3894bc Manually fix migrations and startup 2025-01-10 12:16:31 +01:00
8d01a87b6c wip: Add movie/video example 2025-01-10 12:16:31 +01:00
a37c4fe723 Fix subquery handling of translations 2025-01-10 12:16:31 +01:00
78e84cf960 Use string for date & datetime 2025-01-10 12:16:31 +01:00
4f74ffc5ce Add video migration & runtime field on shows 2025-01-10 12:16:31 +01:00
f53e8e3611 Store image id instead of low/middle/high uri 2025-01-10 12:16:31 +01:00
00774230af Add video model 2025-01-10 12:16:31 +01:00
6f71b98209 Add video schema 2025-01-10 12:16:31 +01:00
e7ed36caff Add jwt verification on the api 2025-01-10 12:16:31 +01:00
6d13f0610b Use select with named fields for movies 2025-01-10 12:16:31 +01:00
6327e911ad Add first drizzle query with multi-language 2025-01-10 12:16:31 +01:00
4c7a02b443 Add api biome.json 2025-01-10 12:16:31 +01:00
ed5d677ae1 Type json in drizzle schemas 2025-01-10 12:16:31 +01:00
908e06c88f Create elysia schemas for movies 2025-01-10 12:16:31 +01:00
4c91462b05 Generate migration 2025-01-10 12:16:31 +01:00
c40f086244 Define show schema and split schema 2025-01-10 12:16:31 +01:00
da3a5181df Fix connection things 2025-01-10 12:16:31 +01:00
8acb1750b6 Add inital migration 2025-01-10 12:16:31 +01:00
96a8ae3de7 Fix schema and add pgSchema 2025-01-10 12:16:31 +01:00
e0704458ee Adding migrations boilerplate 2025-01-10 12:16:31 +01:00
bbc52e58b4 Add entries sql setup 2025-01-10 12:16:31 +01:00
7eaf1e1729 Setup drizzle 2025-01-10 12:16:31 +01:00
ad8673a46f Setup elysia swagger 2025-01-10 12:16:31 +01:00
9e4076e1ea Elysia init 2025-01-10 12:16:31 +01:00
f59dd37825 Use a subdir in cache to ensure no user data is ever deleted (#770) 2025-01-09 20:33:51 +00:00
dcd7e8fad8 Translations update from Hosted Weblate (#769) 2025-01-08 18:42:20 +01:00
72f821f9f2 Add missing languages 2025-01-08 18:27:38 +01:00
தமிழ்நேரம்
eef868d407 Translated using Weblate (Tamil)
Currently translated at 100.0% (209 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ta/
2025-01-08 14:36:27 +01:00
303178b220 Translations update from Hosted Weblate (#768) 2025-01-07 10:12:25 +01:00
தமிழ்நேரம்
3fddc0eae5 Added translation using Weblate (Tamil) 2025-01-06 23:58:05 +01:00
PUFF1N
b88e40802e Translated using Weblate (Turkish)
Currently translated at 100.0% (209 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/tr/
2025-01-06 23:57:38 +01:00
renovate[bot]
e26c830b35 chore(deps): update dependency meilisearch to 0.15.5 (#766)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-06 09:39:54 +01:00
b1ebbfe7af Translations update from Hosted Weblate (#764) 2025-01-05 23:14:17 +01:00
Bezruchenko Simon
92b0cc3ef1 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (209 of 209 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/uk/
2025-01-05 21:49:29 +00:00
Antoine
f918a3bc4b fix(chart): fix transcoder volumeMount (#765) 2025-01-05 22:49:23 +01:00
147e0eef36 Fix chart name to push to oci 2025-01-05 22:00:53 +01:00
45698e1d18 Fix helm release ci 2025-01-05 21:55:58 +01:00
acelinkio
727f548a80 chart/sslmode templating (#762) 2025-01-04 12:04:18 -08:00
Arlan Lloyd
8b4a4f6dde add icon 2025-01-04 19:56:17 +00:00
Arlan Lloyd
874c825706 templating related to #750 ssl 2025-01-04 19:56:10 +00:00
dd24b4258e Cleanup docker compose restart values (#761) 2025-01-04 18:06:42 +01:00
3182cc8d07 Add POSTGRES_SSLMODE for gocoder (#760) 2025-01-04 15:57:30 +00:00
9be48de1fd Translations update from Hosted Weblate (#756) 2025-01-04 02:37:25 +01:00
jannis
1c3519730b Translated using Weblate (German)
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/de/
2025-01-04 01:26:55 +01:00
Felipe Marinho
2ee313d5f6 Add earing Impaired suptitle flag support (#754) 2025-01-04 00:26:51 +00:00
cd89e757c1 Handle non resize transcode (#755) 2025-01-03 23:09:04 +01:00
acelinkio
aadf300e5e path update for helm charts (#749) 2025-01-03 10:22:31 -08:00
acelinkio
2d982b7539 Merge branch 'master' into chart/updateprefix 2025-01-03 09:39:28 -08:00
c427d080c7 Add prefix to back/auth/transcoder (#747) 2025-01-03 18:37:48 +01:00
c86c838b93 Revert "Update dependency MeiliSearch to 0.15.5 (#700)"
This reverts commit 9034d60565.
2025-01-03 18:32:41 +01:00
778f9fd9eb Add prefix for v4 back 2025-01-03 18:32:41 +01:00
257ef354c6 Add prefix for auth 2025-01-03 18:32:41 +01:00
0e12ccd6bb Use transcoder's RoutePrefix to listen
This is probably a breaking change for downstream transcoder users
2025-01-03 18:32:41 +01:00
Felipe Marinho
b2255651af Fix external subtitles extraction (null dereference) 2025-01-03 16:42:20 +01:00
Arlan Lloyd
7cd0f07432 generic verision--populated on release workflow 2025-01-02 22:01:18 +00:00
Arlan Lloyd
fbe15f413f path update for helm charts 2025-01-02 21:44:21 +00:00
f27e2344e5 Translations update from Hosted Weblate (#736) 2025-01-02 22:29:49 +01:00
ahhhh...secret
b140e091bc Added translation using Weblate (Arabic) 2025-01-02 21:28:33 +00:00
renovate[bot]
d075610195 chore(deps): update python docker tag to v3.13 (#656)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2025-01-02 22:28:28 +01:00
f8b587a7b1 Migrate dockerfile to gpu spec for docker v27 (#748) 2025-01-02 21:19:47 +00:00
e4f7c1215b Update go modules (#745) 2025-01-01 21:47:00 +00:00
4db01dd910 Add .ignore support in the scanner (#679) 2025-01-01 21:25:12 +01:00
46543d1f74 fix: reorder delete/register 2025-01-01 21:23:46 +01:00
Felipe Marinho
6992de5e2f refactor: use sets to avoid costly loops 2025-01-01 21:23:46 +01:00
Felipe Marinho
8f4aecb236 docs: add docs about ignoring dirs 2025-01-01 21:23:46 +01:00
Felipe Marinho
d39694ae24 feat: add support for ".ignore" file 2025-01-01 21:23:46 +01:00
acelinkio
04a628e195 chore(deps): update helm release meilisearch to v0.11.0 (#742) 2024-12-29 17:45:36 -08:00
renovate[bot]
35a78264b8 chore(deps): update helm release meilisearch to v0.11.0 2024-12-30 01:43:59 +00:00
acelinkio
352013c260 chore(deps): update helm release postgresql to v16.3.4 (#741) 2024-12-29 17:42:44 -08:00
renovate[bot]
c93aa2438b chore(deps): update helm release postgresql to v16.3.4 2024-12-30 00:11:30 +00:00
Miroslav Šedivý
b4e22538fc fix fmt sprintf in thumbnails.go (#740) 2024-12-24 22:55:42 +00:00
acelinkio
34255444bf update helm docs & media path (#739) 2024-12-23 08:33:35 -08:00
acelinkio
3bb3a508f0 Merge branch 'master' into updateDocs 2024-12-23 08:30:22 -08:00
Arlan Lloyd
b1fb2a0038 update media path 2024-12-23 16:24:31 +00:00
acelinkio
6151a61c68 Create PVCs for back & transcoder (#734) 2024-12-23 07:52:44 -08:00
acelinkio
d142189be2 Merge branch 'master' into addPVCs 2024-12-23 07:02:15 -08:00
renovate[bot]
8655c2c0a5 chore(deps): update helm release postgresql to v16.3.2 (#737)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 08:40:19 +00:00
renovate[bot]
b8faaaf4eb chore(deps): update helm release rabbitmq to v15.2.1 (#738)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-23 09:38:07 +01:00
Arlan Lloyd
d90f4f3526 cleanup 2024-12-23 01:39:34 +00:00
Arlan Lloyd
d418e0ffb3 update docs 2024-12-23 01:37:24 +00:00
acelinkio
ae5c41c35b Merge branch 'master' into addPVCs 2024-12-22 15:47:01 -08:00
acelinkio
52f5989b5a Allow specifying strategy for deployments (#735) 2024-12-22 14:13:25 -08:00
Arlan Lloyd
1a2b922c16 applying fix to other deployments 2024-12-22 22:06:23 +00:00
Arlan Lloyd
fbb0d7b581 fix strategy spec 2024-12-22 22:02:31 +00:00
Arlan Lloyd
9b00782e10 Allow specifying strategy for deployments 2024-12-22 10:17:38 +00:00
Arlan Lloyd
64f67e7ef7 create pvcs needed for back/transcoder 2024-12-22 09:24:24 +00:00
Scott Merchant
296305f8f6 Fix http:// support on android app (#733) 2024-12-19 17:06:29 +00:00
Scott Merchant
cf728739b3 Remove autocomplete and autocapitalisation on server url and username fields (#731) 2024-12-19 16:06:34 +00:00
renovate[bot]
8dcd4df750 chore(deps): update helm release rabbitmq to v15.2.0 (#727)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-18 16:38:43 +01:00
renovate[bot]
124e45261a chore(deps): update helm release postgresql to v16.3.1 (#726)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-18 16:09:51 +01:00
renovate[bot]
d22a1ad5f0 chore(deps): update dependency serilog to 4.2.0 (#720)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:09:33 +00:00
renovate[bot]
81ef228c7f chore(deps): update dependency skiasharp.nativeassets.linux.nodependencies to 3.116.1 (#718)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:04:07 +00:00
renovate[bot]
32e71c14b1 chore(deps): update dependency skiasharp to 3.116.1 (#717)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-16 10:59:39 +01:00
acelinkio
694dff0f97 chore: remove empty annotation field from being rendered (#716) 2024-12-15 07:09:21 -08:00
Arlan Lloyd
0b95ca2173 prevent empty field from being rendered 2024-12-15 04:04:27 +00:00
acelinkio
58c6b71e33 fix: extraContainers (#715) 2024-12-14 11:16:01 -08:00
Arlan Lloyd
98e3c111b6 fix extraContainers 2024-12-14 19:12:05 +00:00
acelinkio
03992e1b2b fix: Helm Chart: map resources, livenessProbe and readinessProbe properties correctly in deployments (#714) 2024-12-14 09:38:13 -08:00
scme0
6ee047695a fix other occurances 2024-12-13 19:56:16 +01:00
scme0
c4ed84f52a Fix resources section 2024-12-13 19:52:22 +01:00
6e3086097b Add @acelinkio as official maintainer of the chart (#711) 2024-12-13 16:21:15 +01:00
c54be64769 Translations update from Hosted Weblate (#709) 2024-12-13 15:44:59 +01:00
김인수
0e0f77ccbf Translated using Weblate (Korean)
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ko/
2024-12-13 04:01:03 +00:00
Jory Irving
750b7d294d Add helm chart test and release workflows (#705)
* feat(gha): add chart release workflow

* feat(gha): add chart test

* fix: remove env

* fix: tag version based on release

* fix: remove working dir

* fix: run on change

* chore: workflow dispatch all the things
2024-12-09 22:49:39 +00:00
renovate[bot]
92b6072584 Update dependency SkiaSharp.NativeAssets.Linux.NoDependencies to v3 (#704)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 10:17:27 +00:00
renovate[bot]
b80b5aa241 Update Helm release postgresql to v16.2.5 (#701)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 10:12:11 +00:00
renovate[bot]
9d43a39b98 Update dependency SkiaSharp to v3 (#703)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 11:09:48 +01:00
renovate[bot]
c610edc819 Update dependency FlexLabs.EntityFrameworkCore.Upsert to 8.1.2 (#702)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-09 10:01:23 +01:00
renovate[bot]
9034d60565 Update dependency MeiliSearch to 0.15.5 (#700)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 21:39:57 +01:00
renovate[bot]
d69567df7b Update Helm release rabbitmq to v15.1.0 (#696)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 02:56:01 +00:00
renovate[bot]
2e266a2ad7 Update Helm release postgresql to v16.2.2 (#695)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 02:53:24 +00:00
renovate[bot]
663190425d Update dependency FlexLabs.EntityFrameworkCore.Upsert to 8.1.0 (#697)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-12-02 03:50:14 +01:00
02a5733cbf Translations update from Hosted Weblate (#681) 2024-11-30 17:59:07 +01:00
85378091ce Add nl to the list of translations (we really need to make this automatic) 2024-11-30 17:35:42 +01:00
Ronald Philipsen
aabc8fcac9 Translated using Weblate (Dutch)
Currently translated at 97.5% (202 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/nl/
2024-11-27 10:13:29 +01:00
124eb90fa0 Added translation using Weblate (Dutch) 2024-11-27 10:13:29 +01:00
7e2dfea5e7 Deleted translation using Weblate (Dutch) 2024-11-27 10:13:28 +01:00
Ronald Philipsen
ddc8c2014a Added translation using Weblate (Dutch) 2024-11-27 10:13:28 +01:00
acelinkio
7d1f227531 Update oidc configuration in helm (#693) 2024-11-27 10:13:21 +01:00
renovate[bot]
b79ab3cf4e Update dependency NSwag.AspNetCore to 14.2.0 (#690)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 02:38:01 +00:00
renovate[bot]
64ee06bac3 Update dependency Npgsql.EntityFrameworkCore.PostgreSQL to 8.0.11 (#688)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 02:30:33 +00:00
renovate[bot]
924a1169d4 Update Helm release postgresql to v16.2.1 (#689)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 02:26:19 +00:00
renovate[bot]
7e9f7fff56 Update dependency MeiliSearch to 0.15.4 (#687)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-25 03:22:55 +01:00
renovate[bot]
aa47be34de Update dependency System.ComponentModel.Composition to v9 (#686)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 08:56:40 +00:00
renovate[bot]
3af4308dcf Update skiasharp monorepo to 2.88.9 (#685)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 08:51:02 +00:00
renovate[bot]
3165f9310e Update Helm release rabbitmq to v15.0.6 (#683)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 08:45:51 +00:00
renovate[bot]
c90fe218cb Update dotnet monorepo to 8.0.11 (#684)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-18 09:43:26 +01:00
Felipe Marinho
447c047b42 Docs: Add docs for OpenID Connect configuration (#682) 2024-11-17 21:32:54 +01:00
Felipe Marinho
8312c66e07 Add language variations (#671)
Co-authored-by: Felipe Marinho <felipe.marinho@ifood.com.br>
2024-11-11 20:28:53 +00:00
renovate[bot]
049f4b0c7c Update Helm release postgresql to v16.1.2 (#676)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 21:21:23 +01:00
renovate[bot]
22b541ca48 Update Helm release postgresql to v16.1.1 (#672)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 11:31:29 +00:00
renovate[bot]
51c1d7b4d8 Update Helm release rabbitmq to v15.0.5 (#673)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-11 11:29:12 +00:00
e2c9a90fa8 Translations update from Hosted Weblate (#675) 2024-11-11 12:27:13 +01:00
Felipe Marinho
d0ea0994c1 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/pt_BR/
2024-11-11 03:00:24 +00:00
Felipe Marinho
23cb8a3b49 Translated using Weblate (Portuguese)
Currently translated at 5.3% (11 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/pt/
2024-11-11 03:00:23 +00:00
Felipe Marinho
cee6993ed0 Feat: Add missing languages options (#667)
* chg: feat: add brazillian portuguese to language options

* chg: fix: organize imports

* chg: feat: add al missing translations

* chg: fix: lint issues

* chg: fix: revert changes, lol
2024-11-10 14:58:17 +01:00
4acd2be626 Translations update from Hosted Weblate (#665) 2024-11-09 10:07:50 +01:00
tardlk
4681a141e2 Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/zh_Hans/
2024-11-08 05:00:29 +01:00
renovate[bot]
c3677b7689 Update actions/setup-python action to v5 (#663)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 17:14:52 +00:00
renovate[bot]
e29822b57c Update Helm release meilisearch to v0.10.2 (#661)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 18:09:14 +01:00
renovate[bot]
0cf10aec8d Update Helm release rabbitmq to v15.0.4 (#662)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 18:08:54 +01:00
renovate[bot]
c95ddbce78 Update Helm release postgresql to v16.1.0 (#664)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-04 18:07:17 +01:00
renovate[bot]
b51d478f35 Update dependency Serilog.Sinks.SyslogMessages to v4 (#644)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-02 14:14:15 +01:00
renovate[bot]
1ff5c25d63 Update dependency Serilog to 4.1.0 (#634)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-01 23:03:31 +00:00
renovate[bot]
0c7c9ba2a6 Update dependency Npgsql.EntityFrameworkCore.PostgreSQL to 8.0.10 (#632)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-01 22:54:34 +00:00
renovate[bot]
b7d6e9406a Update dotnet monorepo (#643)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-01 23:45:42 +01:00
renovate[bot]
02e29210d3 Update dependency Serilog.AspNetCore to 8.0.3 (#649)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-01 22:44:41 +00:00
renovate[bot]
87e45b68ce Update Helm release postgresql to v16.0.6 (#639)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-01 22:36:05 +00:00
899e90deaf Add healthcheck for auth (#658) 2024-11-01 22:32:50 +00:00
renovate[bot]
c9de1263d7 Update actions/setup-python action to v5 (#652)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-11-01 15:35:43 +00:00
5c91f8a637 Use on delete casquade for hash changes in the transcoder (#659) 2024-11-01 16:26:10 +01:00
renovate[bot]
adf534b58e Update traefik Docker tag to v3.2 (#645)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-29 15:21:22 +01:00
renovate[bot]
d308ac575f Update Helm release rabbitmq to v15.0.3 (#642)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-29 14:30:08 +01:00
55515ccc52 Improve helm values documentation (#654) 2024-10-28 11:11:03 +01:00
Arlan Lloyd
2f3e636501 improve documentation 2024-10-26 05:08:35 +00:00
Arlan Lloyd
492631034f improve docs & mount logic 2024-10-26 04:47:58 +00:00
Arlan Lloyd
4cb1c43f65 improve documentation 2024-10-26 04:22:45 +00:00
3b438e1f91 Rename auth docker image 2024-10-19 19:28:47 +02:00
eb27f7a2ce Translations update from Hosted Weblate (#640) 2024-10-19 19:25:45 +02:00
Amir
8efbff3eae Translated using Weblate (Amharic)
Currently translated at 18.3% (38 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/am/
2024-10-19 19:24:26 +02:00
Amir
a9a8ab38a8 Translated using Weblate (Amharic)
Currently translated at 9.6% (20 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/am/
2024-10-19 19:24:26 +02:00
Amir
74456d9915 Translated using Weblate (Amharic)
Currently translated at 1.9% (4 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/am/
2024-10-19 19:24:25 +02:00
Amir
fa375f4d48 Added translation using Weblate (Amharic) 2024-10-19 19:24:25 +02:00
1b5216072d Add auth dockerfile ci 2024-10-19 19:24:18 +02:00
c3b4f64941 Add initial auth module (for v5) (#610) 2024-10-19 19:14:27 +02:00
8fd57da294 Fix keibi dockerfile & ci 2024-10-19 19:06:43 +02:00
719d1609a8 Run robot tests with v5 profile 2024-10-19 18:37:34 +02:00
0d82a1349f Move old robot tests to make them not run with ci 2024-10-19 18:33:48 +02:00
e706f8974f Fix public url in .env.example 2024-10-19 18:09:22 +02:00
49fc88667a Fix robot tests 2024-10-19 18:09:22 +02:00
79b685ea8a Add proper error handling and fix del /sessions/current 2024-10-19 18:09:22 +02:00
a2df0ae305 Move pk to int autogen and uuid as handle 2024-10-19 18:09:22 +02:00
200087f2f6 Fix jwt signing verification 2024-10-19 18:09:22 +02:00
2b493e6d16 Add default config values 2024-10-19 18:09:22 +02:00
662457d0f1 Robot tests wip 2024-10-19 18:09:22 +02:00
8b1cf61209 Add robot tests for auth system 2024-10-19 18:09:22 +02:00
10d8c121b3 Add /info to retrieve public key 2024-10-19 18:09:22 +02:00
9b2f6eadc7 Add delete user routes 2024-10-19 18:09:21 +02:00
1b192c7d05 Check permissions 2024-10-19 18:09:21 +02:00
3c73196f87 Add logout and get /users/me 2024-10-19 18:09:21 +02:00
caa4cf4c8d Switch to asymetric keys for jwt signing 2024-10-19 18:09:21 +02:00
e197062f64 Add /jwt route 2024-10-19 18:09:21 +02:00
95da0184a0 Cleanup return codes and add docs comment for swagger 2024-10-19 18:09:21 +02:00
7b08afde06 Use a proper id for sessions, leave token as a separate field 2024-10-19 18:09:21 +02:00
b340958348 Add login route 2024-10-19 18:09:21 +02:00
4685f76cad Go mod tidy 2024-10-19 18:09:21 +02:00
dd1580b819 Fix timestamptz typo 2024-10-19 18:09:21 +02:00
dc41880ca7 Fix pgx configuration 2024-10-19 18:09:21 +02:00
0c64d9b15d Add dockerfile 2024-10-19 18:09:21 +02:00
cf1e7497e2 Add swagger and problem details 2024-10-19 18:09:21 +02:00
8a2fb36cb0 Setup sessions 2024-10-19 18:09:21 +02:00
306dbbd024 Create register 2024-10-19 18:09:21 +02:00
dfc411e5f6 Add configuration table 2024-10-19 18:09:20 +02:00
d285603716 Register wip 2024-10-19 18:08:33 +02:00
db08bb12c8 Register wip 2024-10-19 18:08:33 +02:00
b20c6c30ff Move users.go 2024-10-19 18:08:33 +02:00
d820a1b149 Setup validators 2024-10-19 18:08:33 +02:00
6b55ae6395 Fix queries 2024-10-19 18:08:33 +02:00
606332ba6f Add list users route & split oidc to a new table 2024-10-19 18:08:33 +02:00
629660bb79 Init user database 2024-10-19 18:08:33 +02:00
73e3c6c64b Add auth spec 2024-10-19 18:08:33 +02:00
renovate[bot]
362b4105c8 Update Helm release postgresql to v16 (#638)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-10-07 19:32:52 +02:00
6f57c4427b Update renovate.json5 2024-10-07 19:32:28 +02:00
7eed5ca957 improve quote usage (#637) 2024-10-07 11:07:10 +02:00
Arlan Lloyd
a33fbe5896 improve quote usage 2024-10-07 11:06:38 +02:00
3c22637f06 Update Helm release postgresql to v15.5.38 (#629) 2024-10-07 11:04:20 +02:00
renovate[bot]
426e29c9a7 Update Helm release postgresql to v15.5.38 2024-10-06 18:46:24 +00:00
368c9af655 Translations update from Hosted Weblate (#635) 2024-10-05 11:04:34 +02:00
JellyBrick
87fecc14cb Translated using Weblate (Korean)
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ko/
2024-10-05 06:40:17 +02:00
JellyBrick
c6c4be0431 Added translation using Weblate (Korean) 2024-10-04 12:45:03 +02:00
24b8e09801 Update Helm release rabbitmq to v15.0.1 (#627) 2024-09-30 23:01:53 +02:00
renovate[bot]
97d5312bb5 Update Helm release rabbitmq to v15.0.1 2024-09-30 19:10:35 +00:00
209e61f490 Remove - in docker compose commands of installing.md 2024-09-30 18:51:51 +02:00
renovate[bot]
9758639d2f Update rabbitmq Docker tag to v4 (#620)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-09-30 10:19:28 +00:00
0831c1eb07 Translations update from Hosted Weblate (#623) 2024-09-30 12:17:10 +02:00
kaskoo
a30ce584fe Translated using Weblate (Romanian)
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ro/
2024-09-30 12:15:28 +02:00
Bezruchenko Simon
8ef02ac7e4 Translated using Weblate (Ukrainian)
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/uk/
2024-09-30 12:15:28 +02:00
kaskoo
fcbd9c2601 Added translation using Weblate (Romanian) 2024-09-30 12:15:27 +02:00
kaskoo
d36d7f06ac Translated using Weblate (French)
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/fr/
2024-09-30 12:15:27 +02:00
1a28103e7b Add helm chart (#560) 2024-09-30 12:15:19 +02:00
Arlan Lloyd
ebb87ef2bb fix casing on key 2024-09-28 16:53:22 +00:00
Arlan Lloyd
7c61ba39bc have pipeline publish version 2024-09-28 14:16:33 +00:00
acelinkio
6c9f544500 Merge branch 'master' into feature/helmchart 2024-09-28 07:15:06 -07:00
Arlan Lloyd
88f997011e add oidc settings 2024-09-28 14:14:10 +00:00
1902ab0d81 Translations update from Hosted Weblate (#622) 2024-09-28 09:12:42 +02:00
Evgeniy
1f822413ef Translated using Weblate (Russian)
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ru/
2024-09-28 05:52:50 +02:00
Arlan Lloyd
9ed4e7570d remove media volume 2024-09-24 20:23:29 +00:00
Arlan Lloyd
861bea46f7 update example to ReadOnlyMany 2024-09-24 19:03:03 +00:00
Arlan Lloyd
9fab7b4df4 update versions 2024-09-24 15:50:03 +00:00
Arlan Lloyd
77794fa6f6 update schema settings 2024-09-24 15:44:45 +00:00
Arlan Lloyd
37fe57fdf4 fix typos in new settings 2024-09-24 14:35:23 +00:00
Arlan Lloyd
5ea78f0817 Update readme 2024-09-24 14:16:07 +00:00
acelinkio
df07e75737 Merge branch 'zoriya:master' into feature/helmchart 2024-09-23 07:59:02 -07:00
42b9e07dbf Add an user agent on matcher's requests (#617) 2024-09-20 21:21:33 +02:00
633a02af06 Add an user agent on matcher's requests 2024-09-20 21:19:56 +02:00
92100c7c43 Update biome (#618) 2024-09-20 20:06:41 +02:00
c78e2ed9e8 Update biome 2024-09-20 19:42:02 +02:00
c7d70e1eec Add new API DB schema (#607) 2024-09-20 19:40:56 +02:00
Weblate (bot)
c065aa8572 Translations update from Hosted Weblate (#613)
* Added translation using Weblate (Spanish)

* Translated using Weblate (Spanish)

Currently translated at 7.2% (15 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/

* Translated using Weblate (Spanish)

Currently translated at 7.2% (15 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/

* Translated using Weblate (Spanish)

Currently translated at 7.2% (15 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/

* Translated using Weblate (Spanish)

Currently translated at 7.7% (16 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/

* Translated using Weblate (Spanish)

Currently translated at 76.3% (158 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/

* Translated using Weblate (Spanish)

Currently translated at 84.0% (174 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/

* Translated using Weblate (Spanish)

Currently translated at 84.0% (174 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/

* Translated using Weblate (Spanish)

Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/es/

---------

Co-authored-by: Shorsh Fields <adionesis@gmail.com>
Co-authored-by: gallegonovato <fran-carro@hotmail.es>
2024-09-10 06:18:10 +00:00
925331383d Translations update from Hosted Weblate (#612) 2024-09-07 21:10:55 +02:00
MattiaPell
e260414dab Translated using Weblate (Italian)
Currently translated at 30.4% (63 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/it/
2024-09-07 12:09:22 +00:00
76dcdee761 Update module golang.org/x/text to v0.18.0 (#609) 2024-09-04 21:52:43 +02:00
renovate[bot]
c15a849bc6 Update module golang.org/x/text to v0.18.0 2024-09-04 16:12:14 +00:00
4b06a46356 Add entries/video many to many note 2024-08-29 15:49:45 +02:00
a62cc600dc Add new API DB schema 2024-08-29 12:59:39 +02:00
d11030326b Fix audio segment miscount (#604) 2024-08-27 16:09:12 +02:00
b50501907c Fix dual keyframe extractions 2024-08-27 16:03:43 +02:00
45d17fdd2c Eagerly generate audio keyframes 2024-08-27 16:03:07 +02:00
16f01257e3 Use last audio pts time for duration 2024-08-27 02:58:40 +02:00
renovate[bot]
5c8260bcbd Update dotnet monorepo to v8.0.8 (#600)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-22 15:47:36 +00:00
4176bd0f0a Fix playback with avi files missing PTS (#602) 2024-08-22 17:43:18 +02:00
da29d9753d Use genpts as an input param for transcodes 2024-08-22 00:37:05 +02:00
ae2cdab9f1 Use genpts 2024-08-22 00:07:05 +02:00
6d702e3786 Update transcoder dockerfiles 2024-08-22 00:07:05 +02:00
63e7aac754 Add custom schema handling for gocoder (#601) 2024-08-22 00:01:37 +02:00
e7c9eca524 Add schema handling via env var 2024-08-21 23:28:06 +02:00
b49eb3bffa Add N/A note on packets_nbr > frames_nbr files 2024-08-21 22:48:44 +02:00
22dd3c65d2 Fix snackbar key warning 2024-08-21 22:46:59 +02:00
809bfc49cd Fix android app not starting due to icon 2024-08-21 22:46:42 +02:00
renovate[bot]
da21984290 Update dotnet monorepo to v8.0.8 (#599)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-08-18 17:22:57 +02:00
Arlan Lloyd
7441a3a3b1 remove uneeded notes 2024-08-17 06:46:16 +00:00
Weblate (bot)
7bba4fc0d8 Translated using Weblate (Turkish) (#598)
Currently translated at 100.0% (207 of 207 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/tr/

Co-authored-by: PUFF1N <frkmhyt@gmail.com>
2024-08-16 14:37:03 +02:00
Arlan Lloyd
8e61244e7b variablize transcoder settings 2024-08-16 04:51:46 +00:00
Arlan Lloyd
839548cb44 remove unused settings 2024-08-16 04:44:28 +00:00
Arlan Lloyd
b6c5261499 add missing setting 2024-08-16 04:40:25 +00:00
Arlan Lloyd
9c98f9e03f add missing settings 2024-08-16 04:36:12 +00:00
Arlan Lloyd
464bdf201e add ingress 2024-08-16 04:26:17 +00:00
Arlan Lloyd
db7c77383d update comments 2024-08-16 03:47:46 +00:00
Arlan Lloyd
cdd2c3c457 update to support other contentdatabases 2024-08-16 03:42:31 +00:00
acelinkio
f9a0063f8d Merge branch 'master' into feature/helmchart 2024-08-14 07:27:44 -07:00
a5094e9656 Front: Change logo color using theme (#596) 2024-08-14 15:51:11 +02:00
acelinkio
ad8dbc3c1a Merge branch 'master' into feature/helmchart 2024-08-14 06:48:14 -07:00
Arthur Jamet
c2bb307a25 Front: Change logo color using theme 2024-08-14 15:00:06 +02:00
Arlan Lloyd
5f5de45be6 remove dev file 2024-08-14 06:46:05 +00:00
Arlan Lloyd
3e864999b9 update username 2024-08-14 06:24:29 +00:00
Arlan Lloyd
dc4aa237fb try slightly different format 2024-08-14 06:11:41 +00:00
Arlan Lloyd
e96a592173 add in env variables 2024-08-14 05:41:28 +00:00
Arlan Lloyd
9657648e0d prepare multi-tenant postgres 2024-08-14 05:30:38 +00:00
0bc103386a Front: Improve readability in menus (#595) 2024-08-13 22:11:54 +02:00
Arthur Jamet
35003b16f8 Front: Improve readability in menus 2024-08-13 21:12:53 +02:00
195ed11c62 Update from pacakges & make android seek better to use (#594) 2024-08-12 10:25:21 +02:00
d9685acbbf Format code 2024-08-12 09:39:01 +02:00
18a473b987 Prepare for translucient navbars 2024-08-12 09:39:01 +02:00
2f835acd2d Update rnvideo web handling 2024-08-12 09:39:01 +02:00
660175f4ed Use artist in media session for android 2024-08-12 09:39:01 +02:00
e6f4f51aea Use expo plugin for react-native-video 2024-08-12 09:39:01 +02:00
5108649bf0 Improve player behavior on android 2024-08-12 09:39:00 +02:00
58c6815dc3 Fix external subtitles key in sub menu 2024-08-12 09:39:00 +02:00
37b1ffe0ca Update packages 2024-08-12 09:39:00 +02:00
c5024eb79d Fix dockerfile warnings 2024-08-12 09:39:00 +02:00
1612019c7f Update README.md 2024-08-12 04:53:40 +02:00
b0f1dc7721 Backport fixes from #592 (#593) 2024-08-12 04:46:36 +02:00
fda0fc9dc1 Fix keyframes version update 2024-08-12 04:31:58 +02:00
0b3ed7faaa Cleanup master.m3u8 paths 2024-08-12 04:31:58 +02:00
27d769cd07 Do not copy on keyframes.Slice if not needed 2024-08-11 15:49:35 +02:00
renovate[bot]
7a827139b7 Update dependency MeiliSearch to v0.15.3 2024-08-11 15:42:35 +02:00
848819c8cd Fix formating 2024-08-11 00:46:11 +02:00
ab86cfca3a Use os.ReadDir instead of glob for subtitles 2024-08-11 00:46:11 +02:00
4e79f38d1e Update media info display 2024-08-11 00:46:11 +02:00
2618650d27 Add external subtitles support 2024-08-11 00:46:11 +02:00
6aac9d1f26 Wait for extraction to finish before returninrg attachments 2024-08-11 00:46:11 +02:00
Arthur Jamet
f9623089a2 Front: Add Gradient behind navabar if transparent 2024-08-11 00:40:12 +02:00
renovate[bot]
d187c63704 Update dependency MeiliSearch to v0.15.2 2024-08-10 16:16:55 +02:00
renovate[bot]
4f8a316da3 Update dependency Serilog.AspNetCore to v8.0.2 2024-08-09 01:08:00 +02:00
renovate[bot]
d526c23974 Update dependency Serilog to v4.0.1 2024-08-09 01:02:55 +02:00
fdf9163d7d Add a readme for gocoder 2024-08-08 17:03:35 +02:00
e623818585 Fix tracker 2024-08-08 17:03:35 +02:00
70147e4fe8 Update gocoder packages 2024-08-08 17:03:35 +02:00
eeaf919121 Remove usless cache invalidate (front) 2024-08-08 17:03:35 +02:00
26314265c9 Fix null arrays after db read 2024-08-08 17:03:35 +02:00
231f63c1b7 Fix keyframes data race 2024-08-08 17:03:35 +02:00
aba3b68eea Fix video paths 2024-08-08 17:03:35 +02:00
475813c42c Prevent keyframes scan when value already exists in db 2024-08-08 17:03:35 +02:00
8d0e362951 Cleanup 2024-08-08 17:03:35 +02:00
ca6b581c85 Fix master playlist & keyframes deadlock 2024-08-08 17:03:35 +02:00
c3ef7bc0e1 Fix keyframes store/load from db 2024-08-08 17:03:35 +02:00
286f9f7ea8 Add useless info fields for backward compatibility 2024-08-08 17:03:35 +02:00
fa6609eea9 Fix migrations 2024-08-08 17:03:35 +02:00
67f6ce308b Add .env.example specifically for gocoder 2024-08-08 17:03:35 +02:00
b14ac6ec02 Remove path/is_external in subtitle 2024-08-08 17:03:35 +02:00
fa03d835ed Suport multi video files 2024-08-08 17:03:35 +02:00
7d3c73a1e9 Add audio bitrate and video is default in info 2024-08-08 17:03:35 +02:00
c0f8f22e6a Cleanup thumbs existence check 2024-08-08 17:03:35 +02:00
8c038b42df Fix extract 2024-08-08 17:03:35 +02:00
5874e86185 Fix subtitles path 2024-08-08 17:03:35 +02:00
7d617a5d28 Add a constraint for subtitles 2024-08-08 17:03:35 +02:00
c84afc8e4c Retrive thumbs/keyframes/extract versions from db when updating infos 2024-08-08 17:03:35 +02:00
14ec227266 Fix info updates 2024-08-08 17:03:35 +02:00
6a431a5bb4 Fix versions update for info 2024-08-08 17:03:35 +02:00
6208fd2b8d Fix base64 encode 2024-08-08 17:03:35 +02:00
37f866456c Fix scan 2024-08-08 17:03:35 +02:00
6ab12b48b0 Fix insert 2024-08-08 17:03:35 +02:00
7f30c187b7 Fix sha varchar length in db 2024-08-08 17:03:35 +02:00
4e4f93bf28 Add down migration 2024-08-08 17:03:35 +02:00
a112ecb8e9 Remove sqlx 2024-08-08 17:03:35 +02:00
cc3b6f268a Run migrations on startup 2024-08-08 17:03:35 +02:00
59010797a8 Update tracker 2024-08-08 17:03:35 +02:00
e3fdf0af45 Rework keyframes retrieval system 2024-08-08 17:03:35 +02:00
cc45bb4656 Use new storage system for keyframes 2024-08-08 17:03:35 +02:00
5991916227 Rework extraction to use new cache 2024-08-08 17:03:35 +02:00
a75bd48ccf Rework thumbnail cache to use db 2024-08-08 17:03:35 +02:00
3ea2004267 Remove old info cache 2024-08-08 17:03:35 +02:00
e91e0151ba Store mediainfo in db 2024-08-08 17:03:35 +02:00
5e026449cc Add runing task dedup lock 2024-08-08 17:03:35 +02:00
5047364ad3 Update media info retrival with db schema 2024-08-08 17:03:35 +02:00
c5047babca Cleanup file stream cache 2024-08-08 17:03:35 +02:00
f16fa9686c Add query method to retrieve metadata from db 2024-08-08 17:03:35 +02:00
0f091618b7 Fix metadata directory permissions (subtitle extraction) 2024-08-08 17:03:35 +02:00
9f7607cb87 Create complete mediainfo/keyframe migration 2024-08-08 17:03:35 +02:00
5854c731a3 Init first transcoder migration 2024-08-08 17:03:35 +02:00
Arthur Jamet
605756a794 Front: Hide Ratings with value equals 0 2024-08-07 16:08:37 +02:00
Arthur Jamet
ddc3e8f61a Front: better Format of Video Metadata for Episodes 2024-08-04 20:07:17 +02:00
Arthur Jamet
7bc07baf47 Front: Pass Item's poster instead of thumbnail to MediaSessionManager 2024-08-04 20:07:17 +02:00
Arthur Jamet
7f144e8cc3 Front: Fix props of MediaSessionManager for Image 2024-08-04 20:07:17 +02:00
Felipe Marinho
67e1dadfab Translated using Weblate (Portuguese (Brazil))
Currently translated at 99.5% (205 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/pt_BR/
2024-08-04 01:46:47 +02:00
def4aa38d6 chore(deps): update dependency nswag.aspnetcore to v14.1.0 (#571) 2024-07-25 20:56:07 +07:00
renovate[bot]
dadb463042 chore(deps): update dependency nswag.aspnetcore to v14.1.0 2024-07-25 13:52:32 +00:00
80a978de5b Translations update from Hosted Weblate (#572) 2024-07-25 20:51:32 +07:00
guilherme monteiro
a00b5bf432 Translated using Weblate (Portuguese (Brazil))
Currently translated at 39.3% (81 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/pt_BR/
2024-07-24 02:09:16 +00:00
guilherme monteiro
8592a7a0a3 Added translation using Weblate (Portuguese (Brazil)) 2024-07-23 03:54:43 +02:00
guilherme monteiro
43a189e5ff Translated using Weblate (Portuguese)
Currently translated at 2.4% (5 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/pt/
2024-07-23 03:54:43 +02:00
guilherme monteiro
8d2bf0a3a2 Added translation using Weblate (Portuguese) 2024-07-23 03:45:03 +02:00
1897b1cb51 Translations update from Hosted Weblate (#569) 2024-07-19 17:47:38 +07:00
d43549816e Translated using Weblate (French)
Currently translated at 100.0% (206 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/fr/
2024-07-19 12:33:02 +02:00
99411e0ce3 Translated using Weblate (French)
Currently translated at 100.0% (206 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/fr/
2024-07-19 12:28:34 +02:00
Evgeniy
671c3006f4 Translated using Weblate (Russian)
Currently translated at 100.0% (206 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ru/
2024-07-19 12:20:18 +02:00
948c862a70 Translated using Weblate (French)
Currently translated at 100.0% (206 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/fr/
2024-07-19 12:20:17 +02:00
aa3a48f69e Translated using Weblate (English)
Currently translated at 100.0% (206 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/en/
2024-07-19 12:20:17 +02:00
Evgeniy
f11511940c Added translation using Weblate (Russian) 2024-07-18 14:40:39 +02:00
ABCraft19
990a16cfda Translated using Weblate (French)
Currently translated at 100.0% (206 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/fr/
2024-07-18 14:40:38 +02:00
ba41c40f81 Translations update from Hosted Weblate (#568) 2024-07-17 21:19:16 +07:00
elcattivo66
84dd2550a1 Translated using Weblate (German)
Currently translated at 100.0% (206 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/de/
2024-07-17 12:09:24 +02:00
Nullpinter
e7df151f14 Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (206 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/zh_Hans/
2024-07-17 12:09:23 +02:00
renovate[bot]
c39260e926 Update dependency MeiliSearch to v0.15.1 (#567)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-16 11:06:57 +07:00
Arlan Lloyd
79d586dfca remove test resource 2024-07-15 01:05:02 +00:00
7209b7d0a6 Fix page props types (#565) 2024-07-15 01:08:47 +07:00
renovate[bot]
1f7443336e Update dotnet monorepo to v8.0.7 (#564)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2024-07-15 00:16:08 +07:00
Arlan Lloyd
3657493073 remove backend media mount 2024-07-14 15:28:31 +00:00
Arlan Lloyd
d983199969 remove unneeded services/ports 2024-07-14 15:25:28 +00:00
Arlan Lloyd
b13affb84b Remove test files 2024-07-14 15:23:33 +00:00
Devin Buhl
31ee4bfd55 chore(renovate): remove biome config (#562) 2024-07-12 19:29:49 +07:00
ff4edf7694 update diagrams based upon helm updates (#561) 2024-07-12 09:24:09 +07:00
Arlan Lloyd
bfd9c79de8 adjust diagrams + add note 2024-07-12 02:05:50 +00:00
Arlan Lloyd
dcb2b8b2ee reorganize diagram 2024-07-12 02:00:33 +00:00
Arlan Lloyd
e58b356378 update formatting 2024-07-12 01:55:24 +00:00
Arlan Lloyd
1f7050ea6e change layout 2024-07-12 01:52:01 +00:00
Arlan Lloyd
923b1b92cc update layout 2024-07-12 01:49:47 +00:00
Arlan Lloyd
3a1cfcaea3 update diagrams based upon helm updates 2024-07-11 20:20:37 +00:00
9e373a3444 Translations update from Hosted Weblate (#557) 2024-07-11 16:07:33 +07:00
Arlan Lloyd
8e4bf1e1cd remove unneeded setting 2024-07-11 05:32:10 +00:00
Arlan Lloyd
3cfd3ef3b0 add comment 2024-07-11 05:20:08 +00:00
Arlan Lloyd
4a3a5bfa8d align to 63 + comment 2024-07-11 05:17:49 +00:00
acelinkio
79c7dc0ad0 Merge branch 'master' into feature/helmchart 2024-07-10 20:59:06 -07:00
Arlan Lloyd
ccdd6a8709 add helm chart 2024-07-11 03:32:08 +00:00
Akhil Raj
dfa9d9d233 Translated using Weblate (Malayalam)
Currently translated at 2.4% (5 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/ml/
2024-07-08 03:49:54 +00:00
Krzysztof
c8fa35b0c4 Translated using Weblate (Polish)
Currently translated at 99.0% (204 of 206 strings)

Translation: Kyoo/Kyoo
Translate-URL: https://hosted.weblate.org/projects/kyoo/kyoo/pl/
2024-07-08 03:49:54 +00:00
Akhil Raj
2fd50585ac Added translation using Weblate (Malayalam) 2024-07-08 03:49:53 +00:00
dd34425ee4 Update traefik Docker tag to v3.1 (#559) 2024-07-08 10:49:48 +07:00
renovate[bot]
e9403a8572 Update traefik Docker tag to v3.1 2024-07-08 02:00:42 +00:00
a15649b9df EpisodeLine: Add missing border radius (#558) 2024-07-07 18:03:35 +07:00
Arthur Jamet
f4135df502 EpisodeLine: Add missing border radius 2024-07-07 12:17:14 +02:00
998 changed files with 83076 additions and 75557 deletions

View File

@@ -1,6 +1,7 @@
# vi: ft=sh
# shellcheck disable=SC2034
# THIS IS V5 .ENV ; IF YOU ARE ON V4 PLEASE LOOK AT THE .ENV HERE: https://github.com/zoriya/Kyoo/blob/v4.7.1/.env.example
# Useful config options
@@ -9,22 +10,11 @@ LIBRARY_ROOT=./video
# You should set this to a path where kyoo can write large amount of data, this is used as a cache by the transcoder.
# It will automatically be cleaned up on kyoo's startup/shutdown/runtime.
CACHE_ROOT=/tmp/kyoo_cache
LIBRARY_LANGUAGES=en
# A pattern (regex) to ignore video files.
# Where to store downloaded images of the shows
IMAGES_PATH="./images";
# A pattern (regex) to ignore files.
LIBRARY_IGNORE_PATTERN=".*/[dD]ownloads?/.*"
# If this is true, new accounts wont have any permissions before you approve them in your admin dashboard.
REQUIRE_ACCOUNT_VERIFICATION=true
# Specify permissions of guest accounts, default is no permissions.
UNLOGGED_PERMISSIONS=
# but you can allow anyone to use your instance without account by doing:
# UNLOGGED_PERMISSIONS=overall.read,overall.play
# You can specify this to allow guests users to see your collection without behing able to play videos for example:
# UNLOGGED_PERMISSIONS=overall.read
# Specify permissions of new accounts.
DEFAULT_PERMISSIONS=overall.read,overall.play
# Hardware transcoding (equivalent of --profile docker compose option).
COMPOSE_PROFILES=cpu # cpu (no hardware acceleration) or vaapi or qsv or nvidia
# the preset used during transcode. faster means worst quality, you can probably use a slower preset with hwaccels
@@ -32,14 +22,9 @@ COMPOSE_PROFILES=cpu # cpu (no hardware acceleration) or vaapi or qsv or nvidia
GOCODER_PRESET=fast
# The following value should be set to a random sequence of characters.
# You MUST change it when installing kyoo (for security)
# You can input multiple api keys separated by a ,
KYOO_APIKEYS=t7H5!@4iMNsAaSJQ49pat4jprJgTcF656if#J3
# Keep those empty to use kyoo's default api key. You can also specify a custom API key if you want.
# go to https://www.themoviedb.org/settings/api and copy the api key (not the read access token, the api key)
THEMOVIEDB_APIKEY=
# go to https://www.themoviedb.org/settings/api and copy the read access token (not the api key)
THEMOVIEDB_API_ACCESS_TOKEN=""
# go to https://thetvdb.com/api-information/signup and copy the api key
TVDB_APIKEY=
# you can also input your subscriber's pin to support TVDB
@@ -47,49 +32,50 @@ TVDB_PIN=
# The url you can use to reach your kyoo instance. This is used during oidc to redirect users to your instance.
PUBLIC_URL=http://localhost:5000
PUBLIC_URL=http://localhost:8901
# Use a builtin oidc service (google, discord, trakt, or simkl):
# When you create a client_id, secret combo you may be asked for a redirect url. You need to specify https://YOUR-PUBLIC-URL/api/auth/logged/YOUR-SERVICE-NAME
OIDC_DISCORD_CLIENTID=
OIDC_DISCORD_SECRET=
# Or add your custom one:
OIDC_SERVICE_NAME=YourPrettyName
OIDC_SERVICE_LOGO=https://url-of-your-logo.com
OIDC_SERVICE_CLIENTID=
OIDC_SERVICE_SECRET=
OIDC_SERVICE_AUTHORIZATION=https://url-of-the-authorization-endpoint-of-the-oidc-service.com/auth
OIDC_SERVICE_TOKEN=https://url-of-the-token-endpoint-of-the-oidc-service.com/token
OIDC_SERVICE_PROFILE=https://url-of-the-profile-endpoint-of-the-oidc-service.com/userinfo
OIDC_SERVICE_SCOPE="the list of scopes space separeted like email identity"
# Token authentication method as seen in https://openid.net/specs/openid-connect-core-1_0.html#ClientAuthentication
# Supported values: ClientSecretBasic (default) or ClientSecretPost
# If in doubt, leave this empty.
OIDC_SERVICE_AUTHMETHOD=ClientSecretBasic
# on the previous list, service is the internal name of your service, you can add as many as you want.
# Default permissions of new users. They are able to browse & play videos.
# Set `verified` to true if you don't wanna manually verify users.
EXTRA_CLAIMS='{"permissions": ["core.read", "core.play"], "verified": false}'
# This is the permissions of the first user (aka the first user is admin)
FIRST_USER_CLAIMS='{"permissions": ["users.read", "users.write", "users.delete", "apikeys.read", "apikeys.write", "core.read", "core.write", "core.play", "scanner.trigger"], "verified": true}'
# Guest (meaning unlogged in users) can be:
# unauthorized (they need to connect before doing anything)
# GUEST_CLAIMS=""
# able to browse & see what you have but not able to play
GUEST_CLAIMS='{"permissions": ["core.read"], "verified": true}'
# or have browse & play permissions
GUEST_CLAIMS='{"permissions": ["core.read", "core.play"], "verified": true}'
# DO NOT change this.
PROTECTED_CLAIMS="permissions,verified"
# Following options are optional and only useful for debugging.
# You can create apikeys at runtime via POST /keys but you can also have some defined in the env.
# Replace $YOURNAME with the name of the key you want (only alpha are valid)
# The value will be the apikey (max 128 bytes)
KEIBI_APIKEY_SCANNER=EJqUB8robwKwLNt37SuHqdcsNGrtwpfYxeExfiAbokpxZVd4WctWr7gnSZ
KEIBI_APIKEY_SCANNER_CLAIMS='{"permissions": ["core.read", "core.write"]}'
# To debug the front end, you can set the following to an external backend
KYOO_URL=
# Database things
POSTGRES_USER=KyooUser
POSTGRES_PASSWORD=KyooPassword
POSTGRES_DB=kyooDB
POSTGRES_SERVER=postgres
POSTGRES_PORT=5432
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
# Read by the api container to know if it should run meilisearch's migrations/sync
# and download missing images. This is a good idea to only have one instance with this on
# Note: it does not run postgres migrations, use the migration container for that.
RUN_MIGRATIONS=true
MEILI_HOST="http://meilisearch:7700"
MEILI_MASTER_KEY="ghvjkgisbgkbgskegblfqbgjkebbhgwkjfb"
RABBITMQ_HOST=rabbitmq
RABBITMQ_PORT=5672
RABBITMQ_DEFAULT_USER=kyoo
RABBITMQ_DEFAULT_PASS=aohohunuhouhuhhoahothonseuhaoensuthoaentsuhha
# It is recommended to use the below PG environment variables when possible.
# POSTGRES_URL=postgres://user:password@hostname:port/dbname?sslmode=verify-full&sslrootcert=/path/to/server.crt&sslcert=/path/to/client.crt&sslkey=/path/to/client.key
# The behavior of the below variables match what is documented here:
# https://www.postgresql.org/docs/current/libpq-envars.html
PGUSER=kyoo
PGPASSWORD=password
PGDATABASE=kyoo
PGHOST=postgres
PGPORT=5432
# PGOPTIONS=-c search_path=kyoo,public
# PGPASSFILE=/my/password # Takes precedence over PGPASSWORD. New line characters are not trimmed.
# PGSSLMODE=verify-full
# PGSSLROOTCERT=/my/serving.crt
# PGSSLCERT=/my/client.crt
# PGSSLKEY=/my/client.key=password

View File

@@ -1,3 +0,0 @@
7e6e56a366babe17e7891a5897180efbf93c00c5
a5638203a6ecb9f372a5a61e1c8fd443bf3a17fe
18e301f26acd7f2e97eac26c5f48377fa13956f5

1
.gitattributes vendored
View File

@@ -1 +0,0 @@
*.Designer.cs linguist-generated=true

1
.github/CODEOWNERS vendored Normal file
View File

@@ -0,0 +1 @@
chart/ @acelinkio

41
.github/workflows/api-test.yml vendored Normal file
View File

@@ -0,0 +1,41 @@
name: Tests
on:
push:
branches:
- master
- next
pull_request:
workflow_dispatch:
jobs:
test:
name: Test api
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
ports:
- "5432:5432"
env:
POSTGRES_USER: kyoo
POSTGRES_PASSWORD: password
POSTGRES_DB: kyoo_test
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v6
- uses: oven-sh/setup-bun@v2
- name: Install dependencies
working-directory: ./api
run: bun install --frozen-lockfile
- name: Test
working-directory: ./api
run: bun test
env:
PGHOST: localhost
IMAGES_PATH: ./images

64
.github/workflows/auth-hurl.yml vendored Normal file
View File

@@ -0,0 +1,64 @@
name: HurlTests
on:
push:
branches:
- master
- next
pull_request:
jobs:
test:
name: Hurl tests Auth
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
ports:
- "5432:5432"
env:
POSTGRES_USER: kyoo
POSTGRES_PASSWORD: password
options: >-
--health-cmd pg_isready
--health-interval 10s
--health-timeout 5s
--health-retries 5
steps:
- uses: actions/checkout@v6
- uses: gacts/install-hurl@v1
- uses: actions/setup-go@v6
with:
go-version: '^1.22.5'
cache-dependency-path: ./auth/go.sum
- name: Install dependencies
working-directory: ./auth
run: |
go mod download
- name: Build
working-directory: ./auth
run: |
go build -o ./keibi
- name: Run hurl tests
working-directory: ./auth
run: |
./keibi > logs &
wget --retry-connrefused --retry-on-http-error=502 http://localhost:4568/auth/health
hurl --error-format long --variable host=http://localhost:4568/auth tests/*
env:
PGHOST: localhost
FIRST_USER_CLAIMS: '{"permissions": ["users.read"]}'
KEIBI_APIKEY_HURL: 1234apikey
KEIBI_APIKEY_HURL_CLAIMS: '{"permissions": ["apikeys.write", "apikeys.read"]}'
- name: Show logs
if: failure()
working-directory: ./auth
run: cat logs

View File

@@ -2,19 +2,22 @@ name: Coding Style
on: [pull_request, workflow_dispatch]
jobs:
back:
name: "Lint Back"
api:
name: "Lint api"
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./back
working-directory: ./api
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Check coding style
run: |
dotnet tool restore
dotnet csharpier . --check
- name: Setup Biome
uses: biomejs/setup-biome@v2
with:
version: latest
- name: Run Biome
run: biome ci .
front:
name: "Lint Front"
@@ -23,7 +26,7 @@ jobs:
run:
working-directory: ./front
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Setup Biome
uses: biomejs/setup-biome@v2
@@ -37,7 +40,7 @@ jobs:
name: "Lint scanner/autosync"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: chartboost/ruff-action@v1
with:
@@ -50,7 +53,19 @@ jobs:
run:
working-directory: ./transcoder
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- name: Run go fmt
run: if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then exit 1; fi
auth:
name: "Lint auth"
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./auth
steps:
- uses: actions/checkout@v6
- name: Run go fmt
run: if [ "$(gofmt -s -l . | wc -l)" -gt 0 ]; then exit 1; fi

View File

@@ -19,38 +19,40 @@ jobs:
fail-fast: false
matrix:
include:
- context: ./back
- context: ./api
dockerfile: Dockerfile
label: back
image: zoriya/kyoo_back
- context: ./back
dockerfile: Dockerfile.migrations
label: migrations
image: zoriya/kyoo_migrations
label: api
image: ${{ github.repository_owner }}/kyoo_api
- context: ./front
dockerfile: Dockerfile
label: front
image: zoriya/kyoo_front
image: ${{ github.repository_owner }}/kyoo_front
- context: ./scanner
dockerfile: Dockerfile
label: scanner
image: zoriya/kyoo_scanner
image: ${{ github.repository_owner }}/kyoo_scanner
- context: ./autosync
dockerfile: Dockerfile
label: autosync
image: zoriya/kyoo_autosync
image: ${{ github.repository_owner }}/kyoo_autosync
- context: ./transcoder
dockerfile: Dockerfile
label: transcoder
image: zoriya/kyoo_transcoder
image: ${{ github.repository_owner }}/kyoo_transcoder
- context: ./auth
dockerfile: Dockerfile
label: auth
image: ${{ github.repository_owner }}/kyoo_auth
env:
DOCKERHUB_ENABLED: ${{ secrets.DOCKER_USERNAME && secrets.DOCKER_PASSWORD && 'true' || 'false' }}
name: Build ${{matrix.label}}
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v6
- uses: dorny/paths-filter@v3
id: filter
@@ -64,7 +66,7 @@ jobs:
uses: docker/metadata-action@v5
with:
images: |
docker.io/${{matrix.image}}
docker.io/${{matrix.image}},enable=${{ env.DOCKERHUB_ENABLED }}
ghcr.io/${{matrix.image}}
tags: |
type=edge
@@ -84,7 +86,7 @@ jobs:
uses: docker/setup-buildx-action@v3
- name: Login to DockerHub
if: env.SHOULD_PUSH == 'true'
if: env.SHOULD_PUSH == 'true' && env.DOCKERHUB_ENABLED == 'true'
uses: docker/login-action@v3
with:
username: ${{ secrets.DOCKER_USERNAME }}
@@ -114,7 +116,7 @@ jobs:
cache-to: type=gha,mode=max
- name: Sync README.MD
if: env.SHOULD_PUSH == 'true'
if: env.SHOULD_PUSH == 'true' && env.DOCKERHUB_ENABLED == 'true'
uses: ms-jpq/sync-dockerhub-readme@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}

View File

@@ -0,0 +1,54 @@
name: Release Helm Chart
on:
push:
tags:
- v*
workflow_dispatch:
inputs:
channel:
description: 'Release channel (master, edge, or leave blank for tag-based)'
required: false
default: 'master'
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@1af3b93b6815bc44a9784bd300feb67ff0d1eeb3 # v6.0.0
- name: Set up Helm
uses: azure/setup-helm@1a275c3b69536ee54be43f2070a358922e12c8d4 # v4.3.1
- name: Log in to GHCR
uses: docker/login-action@5e57cd118135c172c3672efd75eb46360885c0ef # v3.6.0
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Update Helm Dependencies
run: helm dependency update ./chart
- name: Determine Chart Version
id: version
run: |
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
TAG="${{ github.event.inputs.channel }}"
else
TAG=$(echo ${GITHUB_REF#refs/tags/} | sed 's/^v//')
fi
echo "TAG=$TAG" >> "${GITHUB_ENV}"
echo "Using chart version: $TAG"
- name: Package Helm Chart
run: helm package ./chart --version $TAG --app-version $TAG
- name: Build Helm-safe repo name
run: |
REPO_NAME="$(echo "oci://ghcr.io/${GITHUB_REPOSITORY_OWNER}/helm-charts" | tr '[:upper:]' '[:lower:]')"
echo "REPO_NAME=${REPO_NAME}" >> "${GITHUB_ENV}"
- name: Push Helm Chart to GHCR
run: helm push kyoo-*.tgz "${REPO_NAME}"

45
.github/workflows/helm-test-chart.yml vendored Normal file
View File

@@ -0,0 +1,45 @@
name: Test Helm Chart
on:
push:
branches:
- master
- next
pull_request:
workflow_dispatch:
jobs:
test-helm-chart:
name: Test Helm Chart
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v6
- name: Set up Helm
uses: azure/setup-helm@v4
- name: Lint the Helm chart
run: |
helm lint ./chart
- name: Create Kind cluster
uses: helm/kind-action@v1
- name: Install Helm chart in Kind cluster (Dry Run)
run: |
helm dependency update ./chart
helm install test-release ./chart --dry-run --debug
- name: Deploy Helm chart to Kind cluster
run: |
helm install test-release ./chart
- name: Verify Helm release
run: |
kubectl get all
- name: Cleanup Kind cluster
run: |
kind delete cluster

View File

@@ -13,52 +13,63 @@ jobs:
working-directory: ./front
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Check for EXPO_TOKEN
# This is required because GHA doesn't support secrets in the `if` condition
- name: Check if Expo build is enabled
env:
IS_SECRET_SET: ${{ env.IS_EXPO_ENABLED == 'true' && 'true' || 'false' }}
run: echo "IS_EXPO_ENABLED=${IS_SECRET_SET}" >> "${GITHUB_ENV}"
- name: Log if Expo build is disabled due to fork
if: env.IS_EXPO_ENABLED != 'true'
run: |
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions"
exit 1
fi
echo "Expo build is disabled for forks. To enable it, add an EXPO_TOKEN secret to this repository. See https://docs.expo.dev/eas-update/github-actions/ for more information."
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
if: env.IS_EXPO_ENABLED == 'true'
with:
node-version: 18.x
node-version: 24.x
cache: yarn
cache-dependency-path: front/yarn.lock
- name: Setup Expo
uses: expo/expo-github-action@v8
if: env.IS_EXPO_ENABLED == 'true'
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Install dependencies
if: env.IS_EXPO_ENABLED == 'true'
run: yarn install --immutable
- name: Build Mobile Release
if: env.IS_EXPO_ENABLED == 'true'
run: yarn build:mobile:apk | tee log.txt
- name: Parse Asset URL
id: url
if: env.IS_EXPO_ENABLED == 'true'
run: |
ASSET_URL=$(cat log.txt | jq '.[0].artifacts.buildUrl' -r)
echo The android url is $ASSET_URL
echo "assetUrl=$ASSET_URL" >> $GITHUB_OUTPUT
- name: Download APK Asset
if: env.IS_EXPO_ENABLED == 'true'
run: wget -O kyoo.apk ${{ steps.url.outputs.assetUrl }}
- uses: actions/upload-artifact@v4
- uses: actions/upload-artifact@v5
if: env.IS_EXPO_ENABLED == 'true'
with:
name: kyoo.apk
path: ./front/kyoo.apk
- name: Upload release artifacts
uses: softprops/action-gh-release@v2
if: startsWith(github.ref, 'refs/tags/')
if: env.IS_EXPO_ENABLED == 'true' && startsWith(github.ref, 'refs/tags/')
with:
files: ./front/kyoo.apk

View File

@@ -13,31 +13,39 @@ jobs:
working-directory: ./front
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Check for EXPO_TOKEN
# This is required because GHA doesn't support secrets in the `if` condition
- name: Check if Expo build is enabled
env:
IS_SECRET_SET: ${{ env.IS_EXPO_ENABLED == 'true' && 'true' || 'false' }}
run: echo "IS_EXPO_ENABLED=${IS_SECRET_SET}" >> "${GITHUB_ENV}"
- name: Log if Expo build is disabled due to fork
if: env.IS_EXPO_ENABLED != 'true'
run: |
if [ -z "${{ secrets.EXPO_TOKEN }}" ]; then
echo "You must provide an EXPO_TOKEN secret linked to this project's Expo account in this repo's secrets. Learn more: https://docs.expo.dev/eas-update/github-actions"
exit 1
fi
echo "Expo build is disabled for forks. To enable it, add an EXPO_TOKEN secret to this repository. See https://docs.expo.dev/eas-update/github-actions/ for more information."
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v6
if: env.IS_EXPO_ENABLED == 'true'
with:
node-version: 18.x
node-version: 24.x
cache: yarn
cache-dependency-path: front/yarn.lock
- name: Setup Expo
uses: expo/expo-github-action@v8
if: env.IS_EXPO_ENABLED == 'true'
with:
expo-version: latest
eas-version: latest
token: ${{ secrets.EXPO_TOKEN }}
- name: Install dependencies
if: env.IS_EXPO_ENABLED == 'true'
run: yarn install --immutable
- name: Publish update
if: env.IS_EXPO_ENABLED == 'true'
run: yarn update

View File

@@ -10,7 +10,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v4
uses: actions/checkout@v6
- name: Set correct versions
run: |
@@ -19,12 +19,9 @@ jobs:
VERSION=${VERSION%.*} # Remove minor version
sed "s/edge/$VERSION/" -i docker-compose.yml
- uses: actions/upload-artifact@v4
with:
name: docker-compose.yml
path: ./docker-compose.yml
- name: Upload release artifacts
uses: softprops/action-gh-release@v2
with:
files: ./docker-compose.yml
files: |
./docker-compose.yml
./.env.example

View File

@@ -1,50 +0,0 @@
name: RobotTests
on:
push:
branches:
- master
- next
pull_request:
jobs:
test:
name: Run Robot Tests
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Pull images
run: |
cp .env.example .env
docker compose version
docker compose pull
- name: Docker cache
uses: satackey/action-docker-layer-caching@v0.0.11
continue-on-error: true
- name: Start the service
run: |
docker compose up -d back postgres traefik meilisearch --wait
- name: Perform healthchecks
run: |
docker compose ps -a
docker compose logs
wget --retry-connrefused --retry-on-http-error=502 http://localhost:8901/api/health || (docker compose logs && exit 1)
- name: Run robot tests
run: |
pip install -r back/tests/robot/requirements.txt
robot -d out back/tests/robot/
- name: Show logs
if: failure()
run: docker compose logs
- uses: actions/upload-artifact@v4
with:
name: results
path: out

4
.gitignore vendored
View File

@@ -1,4 +1,5 @@
/video
.devspace/
.env
.venv
.idea
@@ -6,3 +7,6 @@
log.html
output.xml
report.html
chart/charts
chart/Chart.lock
tmp

View File

@@ -3,3 +3,5 @@ function-case=1 #lowercase
keyword-case=1
type-case=1
no-space-function=1
keep-newline=1
nogrouping=1

View File

@@ -1,4 +0,0 @@
# Authors
Ordered by the date of the first commit.
* Zoe Roux ([@zoriya](http://github.com/zoriya))

View File

@@ -1,30 +1,30 @@
# Diagrams
These diagrams are created with Mermaid and rendered locally. For the best experience, please use a browser.
# Project Structure
Kyoo is a monorepo that consists of several projects each in their own directory. Diagram below shows an outline of kyoo, projects, and artifacts.
```mermaid
block-beta
block
columns 1
block:proj1:1
proj_name["Kyoo"]:1
end
block:proj2:1
dir_1["autosync/"]
dir_2["back/"]
dir_1["api/"]
dir_2["auth/"]
dir_3["front/"]
dir_4["transcoder/"]
dir_5["scanner/"]
end
block:proj3:1
%% columns auto (default)
block:autosync_b:1
autosync_i1("kyoo_autosync")
block:api_b:1
autosync_i1("kyoo_api")
end
block:back_b:1
block:auth_b:1
columns 1
back_i1("kyoo_back")
back_i2("kyoo_migrations")
back_i1("kyoo_auth")
end
block:front_b:1
front_i1("kyoo_front")
@@ -35,7 +35,6 @@ block-beta
block:scanner_b:1
columns 1
scanner_i1("kyoo_scanner")
scanner_i2("kyoo_scanner*")
end
end
@@ -50,19 +49,17 @@ block-beta
style dir_4 fill:#438dd5,stroke-width:0px
style dir_5 fill:#438dd5,stroke-width:0px
style autosync_b fill:#438dd5,stroke-width:0px
style back_b fill:#438dd5,stroke-width:0px
style api_b fill:#438dd5,stroke-width:0px
style auth_b fill:#438dd5,stroke-width:0px
style front_b fill:#438dd5,stroke-width:0px
style transcoder_b fill:#438dd5,stroke-width:0px
style scanner_b fill:#438dd5,stroke-width:0px
style autosync_i1 fill:#85bbf0,stroke-width:0px
style back_i1 fill:#85bbf0,stroke-width:0px
style back_i2 fill:#85bbf0,stroke-width:0px
style front_i1 fill:#85bbf0,stroke-width:0px
style transcoder_i1 fill:#85bbf0,stroke-width:0px
style scanner_i1 fill:#85bbf0,stroke-width:0px
style scanner_i2 fill:#85bbf0,stroke-width:0px
```
# C4 Diagrams
@@ -88,217 +85,165 @@ C4Context
```
## Container
Messaging is middleware. EnterpriseMessageBus is for any messaging handled between different projects.
Kyoo leverages the [API Gateway](https://learn.microsoft.com/en-us/azure/architecture/microservices/design/gateway) approach to microservices and [offloads](https://learn.microsoft.com/en-us/azure/architecture/patterns/gateway-offloading) authentication at the gateway.
```mermaid
C4Container
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="3")
UpdateLayoutConfig($c4ShapeInRow="3", $c4BoundaryInRow="1")
title Container diagram for Kyoo System
Person(user, "User")
System_Boundary(internal, "Kyoo") {
Container(frontend, "front/")
Container(backend, "back/")
Container(transcoder, "transcoder/")
Container(scanner, "scanner/")
ContainerQueue(emb, "emb", "", "EnterpriseMessageBus")
Container(autosync, "autosync/")
}
System_Boundary(external, "") {
System_Ext(content, "ContentDatabase", "")
}
System_Boundary(external2, "") {
System_Ext(tracker, "ActivityTracker", "")
}
System_Boundary(external3, "") {
System_Ext(media, "MediaLibrary", "")
}
Container(apigateway, "API Gateway")
Container(auth, "auth")
Container(transcoder, "transcoder")
Container(scanner, "scanner")
Container(frontend, "front")
System_Ext(media, "MediaLibrary", "")
System_Ext(content, "ContentDatabase", "")
Container(api, "api")
System_Ext(tracker, "ActivityTracker", "")
Rel(user, frontend, "")
Rel(user, backend, "")
Rel(frontend, backend, "")
Rel(backend, emb, "")
Rel(backend, media, "")
Rel(backend, transcoder, "")
Rel_Back(autosync, emb, "")
Rel(autosync, tracker, "")
Rel_Back(scanner, emb, "")
Rel(scanner, backend, "")
Rel(user, apigateway, "")
Rel(apigateway, frontend, "")
Rel(apigateway, scanner, "")
Rel(apigateway, transcoder, "")
Rel(apigateway, api, "")
Rel(apigateway, auth, "")
Rel(frontend, api, "")
Rel(api, tracker, "")
Rel(api, content, "")
Rel(scanner, api, "")
Rel(scanner, media, "")
Rel(scanner, content, "")
Rel(transcoder, media, "")
```
## Component
### Autosync
#### Auth
Auth microservice is implicitly used by each other microservice for both end user authentication and microservice to microservice communications. Auth microservice will not be directly represented in the other component diagrams. Instead in their relationsihp will specify "auth via middleware".
```mermaid
C4Component
UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="2")
UpdateLayoutConfig($c4ShapeInRow="5", $c4BoundaryInRow="2")
title Component Diagram for Autosync
Container_Boundary(autosync, "autosync") {
Component(autosync_c1, "kyoo_autosync", "python, python3.12", "")
}
Container_Boundary(emb, "emb") {
ComponentQueue(emb_q1, "autosync", "RabbitMQ, Queue", "")
ComponentQueue(emb_e1, "events.watched", "RabbitMQ, Exchange", "")
}
Container_Boundary(tracker, "ActivityTracker") {
Component_Ext(tracker_c1, "TrackerProvider", "API", "simkl")
}
Container_Boundary(backend, "back") {
Component(backend_c2, "kyoo_back", "C#, .NET 8.0", "API Backend")
}
title Auth Component Diagram
Rel(emb_e1, emb_q1, "bound")
Rel_Back(autosync_c1, emb_q1, "consumes")
Rel(backend_c2, emb_e1, "produces")
Rel(autosync_c1, tracker_c1, "updates")
Container_Boundary(auth, "auth") {
Component(auth_c1, "kyoo_auth", "Go", "")
ComponentDb(auth_db1, "kelbi", "Postgres", "")
}
Rel(auth_c1, auth_db1, "")
```
### Back
```mermaid
C4Component
UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="3")
title Component Diagram for Back
Person(user, "User")
Container_Boundary(frontend, "front") {
Component(frontend_c1, "kyoo_front", "typescript, node.js", "Static Content")
}
Container_Boundary(backend, "back") {
Component(backend_c1, "kyoo_migrations", "C#, .NET 8.0", "Postgres Migration")
ComponentDb(backend_db1, "backend", "Postgres", "user data and session state")
Component(backend_c3, "BackendMetadata", "Volume", "Persistent. Distributed Metadata")
ComponentDb(backend_db2, "search", "Meilisearch", "search resource")
Component(backend_c2, "kyoo_back", "C#, .NET 8.0", "API Backend")
}
Container_Boundary(media, "MediaLibrary") {
Component_Ext(media_c1, "MediaShare", "Volume", "Read Only")
}
Container_Boundary(transcoder, "transcoder") {
Component(transcoder_c1, "kyoo_transcoder", "go, go", "Video Transcoder")
}
Container_Boundary(emb, "emb") {
ComponentQueue(emb_e1, "events.watched", "RabbitMQ, Exchange", "")
ComponentQueue(emb_q2, "scanner.rescan", "RabbitMQ, Queue", "")
ComponentQueue(emb_q1, "autosync", "RabbitMQ, Queue", "")
ComponentQueue(emb_e2, "events.resource", "RabbitMQ, Exchange", "unused")
}
Container_Boundary(scanner, "scanner") {
Component(scanner_c1, "kyoo_scanner", "python, python3.12", "scanner")
Component(scanner_c2, "kyoo_scanner", "python, python3.12", "matcher")
}
Container_Boundary(autosync, "autosync") {
Component(autosync_c1, "kyoo_autosync", "python, python3.12", "")
}
Rel(user, backend_c2, "")
Rel(backend_c1, backend_db1, "")
Rel(backend_c2, backend_db1, "")
Rel(backend_c2, backend_db2, "")
Rel(backend_c2, media_c1, "")
Rel(backend_c2, transcoder_c1, "")
Rel(backend_c2, backend_c3, "")
Rel(backend_c2, emb_q2, "produces")
Rel(backend_c2, emb_e1, "produces")
Rel(backend_c2, emb_e2, "produces")
Rel(emb_e1, emb_q1, "bound")
Rel_Back(autosync_c1, emb_q1, "consumes")
Rel_Back(scanner_c1, emb_q2, "consumes")
Rel(scanner_c1, backend_c2, "")
Rel(scanner_c2, backend_c2, "")
Rel(frontend_c1, backend_c2, "")
```
### Front
```mermaid
C4Component
UpdateLayoutConfig($c4ShapeInRow="4", $c4BoundaryInRow="2")
title Component Diagram for Front
Person(user, "User")
Container_Boundary(frontend, "front") {
Component(frontend_c1, "kyoo_front", "typescript, node.js", "Static Content")
}
Container_Boundary(backend, "back") {
Component(backend_c2, "kyoo_back", "C#, .NET 8.0", "API Backend")
}
Rel(frontend_c1, backend_c2, "ssr")
Rel(user, frontend_c1, "")
```
### Scanner
```mermaid
C4Component
UpdateLayoutConfig($c4ShapeInRow="5", $c4BoundaryInRow="3")
title Component Diagram for Scanner
Container_Boundary(media, "MediaLibrary") {
Component_Ext(media_c1, "MediaShare", "Volume", "Read Only")
}
Container_Boundary(content, "ContentDatabase") {
Component_Ext(content_c1, "ContentProvider", "API", "tmdb or tvdb")
}
Container_Boundary(scanner, "scanner") {
Component(scanner_c2, "kyoo_scanner", "python, python3.12", "matcher")
ComponentQueue(scanner_q1, "scanner", "RabbitMQ, Queue", "")
Component(scanner_c1, "kyoo_scanner", "python, python3.12", "scanner")
}
Container_Boundary(emb, "emb") {
ComponentQueue(emb_q2, "scanner.rescan", "RabbitMQ, Queue", "")
}
Container_Boundary(backend, "back") {
Component(backend_c2, "kyoo_back", "C#, .NET 8.0", "API Backend")
}
Rel(scanner_c1, scanner_q1, "produces")
Rel(scanner_c1, media_c1, "watches")
Rel(scanner_c1, backend_c2, "Fetch existing scans")
Rel(scanner_c2, content_c1, "Fetch media data")
Rel(scanner_c2, backend_c2, "Pushes media data")
Rel_Back(scanner_c2, scanner_q1, "consumes")
Rel_Back(scanner_c1, emb_q2, "consumes")
Rel(backend_c2, emb_q2, "produces")
```
### Transcoder
#### Api
```mermaid
C4Component
UpdateLayoutConfig($c4ShapeInRow="2", $c4BoundaryInRow="2")
title Component Diagram for Transcoder
title Api Component Diagram
Person(user, "User")
Container_Boundary(api, "api") {
ComponentDb(api_db1, "kyoo", "Postgres", "")
Component(api_c1, "kyoo_api", "TypeScript", "")
Component(api_c2, "ApiMetadata", "S3/Volume", "Persistent. Distributed Metadata")
}
Container_Boundary(scanner, "scanner") {
Component(scanner_c1, "kyoo_scanner", "Python", "")
}
System_Boundary(external, "") {
System_Ext(tracker, "ActivityTracker", "")
System_Ext(content, "ContentDatabase", "")
}
Container_Boundary(front, "front") {
Component(front_c1, "kyoo_front", "TypeScript", "")
}
Rel(user, api_c1, "auth via middleware")
Rel(api_c1, api_db1, "")
Rel(api_c1, api_c2, "")
Rel(api_c1, content, "http(s) <br/> retries media images")
Rel(api_c1, tracker, "")
Rel(scanner_c1, api_c1, "auth via middleware")
Rel(front_c1, api_c1, "http(s) SSR <br/> auth via middleware")
```
#### Front
```mermaid
C4Component
UpdateLayoutConfig($c4ShapeInRow="5", $c4BoundaryInRow="2")
title Front Component Diagram
Person(user, "User")
Container_Boundary(front, "front") {
Component(front_c1, "kyoo_front", "TypeScript", "")
}
Container_Boundary(api, "api") {
Component(api_c1, "kyoo_api", "TypeScript", "")
}
Rel(user, front_c1, "")
Rel(front_c1, api_c1, "http(s) SSR <br/> auth via middleware")
```
#### Transcoder
```mermaid
C4Component
UpdateLayoutConfig($c4ShapeInRow="2", $c4BoundaryInRow="1")
title Transcoder Component Diagram
Person(user, "User")
Container_Boundary(transcoder, "transcoder") {
Component(transcoder_c2, "TranscodeMetadata", "Volume", "Persistent. Distributed Metadata")
Component(transcoder_c1, "kyoo_transcoder", "go, go", "Video Transcoder")
ComponentDb(transcoder_db1, "gocoder", "Postgres", "")
Component(transcoder_c1, "kyoo_transcoder", "Go", "")
Component(transcoder_c2, "TranscodeMetadata", "S3/Volume", "Persistent. Distributed Metadata")
Component(transcoder_c3, "TranscodeCache", "Volume", "Volatile. Local cache")
}
Container_Boundary(media, "MediaLibrary") {
Component_Ext(media_c1, "MediaShare", "Volume", "Read Only")
}
Container_Boundary(backend, "back") {
Component(backend_c2, "kyoo_back", "C#, .NET 8.0", "API Backend")
System_Boundary(external, "") {
System_Ext(media, "MediaLibrary", "")
}
Rel(transcoder_c1, media_c1, "mounts")
Rel(user, transcoder_c1, "auth via middleware")
Rel(transcoder_c1, media, "mounted to filesystem <br/> reads")
Rel(transcoder_c1, transcoder_db1, "")
Rel(transcoder_c1, transcoder_c2, "")
Rel(transcoder_c1, transcoder_c3, "")
Rel(backend_c2, transcoder_c1, "")
```
#### Scanner
```mermaid
C4Component
UpdateLayoutConfig($c4ShapeInRow="5", $c4BoundaryInRow="2")
title Scanner Component Diagram
Person(user, "User")
Container_Boundary(api, "api") {
Component(api_c1, "kyoo_api", "TypeScript", "")
}
Container_Boundary(scanner, "scanner") {
Component(scanner_c1, "kyoo_scanner", "Python", "")
ComponentDb(scanner_db1, "scanner", "Postgres", "")
}
System_Boundary(external, "") {
System_Ext(content, "ContentDatabase", "")
System_Ext(media, "MediaLibrary", "")
}
Rel(user, scanner_c1, "http(s) <br/> auth via middleware")
Rel(scanner_c1, api_c1, "http(s) <br/> auth via middleware")
Rel(scanner_c1, scanner_db1, "")
Rel(scanner_c1, content, "http(s) <br/> gathers media metadata")
Rel(scanner_c1, media, "mounted to filesystem <br/> watches")
```

View File

@@ -3,10 +3,10 @@
1. Install docker & docker-compose
2. Download the
[`docker-compose.yml`](https://github.com/zoriya/kyoo/releases/latest/download/docker-compose.yml) and
[`.env`](https://raw.githubusercontent.com/zoriya/Kyoo/master/.env.example) files
3. Fill the `.env` file with your configuration options
[`.env`](https://github.com/zoriya/kyoo/releases/latest/download/env.example) files
3. Fill the `.env` file with your configuration options. Ensure it's named `.env` (nothing before the dot)
4. Look at [Hardware Acceleration section](#Hardware-Acceleration) if you need it
5. Look at [Custom Volumes](#Custom-Volumes) if you need it,
5. Look at [FAQ](#FAQ) if you need it,
6. Run `docker compose up -d` and see kyoo at `http://localhost:8901`
# Installing
@@ -23,7 +23,7 @@ Those files can be put in any directory of your choice.
Those files are:
- A `docker-compose.yml` (simply download docker-compose.yml from [the latest release](https://github.com/zoriya/kyoo/releases/latest/download/docker-compose.yml)).
- A `.env` file that you will need to **fill**. Look at the example [.env.example](https://raw.githubusercontent.com/zoriya/Kyoo/master/.env.example)
- A `.env` file that you will need to **fill**. Look at the example [.env.example](https://github.com/zoriya/kyoo/releases/latest/download/env.example). It's name NEEDS to be `.env` (nothing before the dot)
> If you want an explanation of what are those files, you can read the following:
> The `docker-compose.yml` file describes the different services of Kyoo, where they should be downloaded and their start order. \
@@ -33,7 +33,7 @@ If you need hardware acceleration, look at [Hardware Acceleration section](#Hard
If you need custom volumes (because video directories are on different disks and you can't use raid, because you use network drives or another custom volume type), look at [Custom Volumes](#Custom-Volumes).
The next and last step is actually starting Kyoo. To do that, open a terminal in the same directory as the 3 configurations files
and run `docker-compose up -d`.
and run `docker compose up -d`.
Congratulation, everything is now ready to use Kyoo. You can navigate to `http://localhost:8901` on a web browser to see your instance of Kyoo.
@@ -43,11 +43,11 @@ Updating Kyoo is exactly the same as installing it. Get an updated version of th
unsure that your `.env` contains all the options specified in the updated `.env.example` file.
After that, you will need to update Kyoo's services. For that, open a terminal in the configuration's directory and run
the command `docker-compose pull`. You are now ready to restart Kyoo, you can run `docker-compose up -d`.
the command `docker compose pull`. You are now ready to restart Kyoo, you can run `docker compose up -d`.
# Uninstalling
To uninstall Kyoo, you need to open a terminal in the configuration's directory and run `docker-compose down`. This will
To uninstall Kyoo, you need to open a terminal in the configuration's directory and run `docker compose down`. This will
stop Kyoo's services. You can then remove the configuration files.
# Hardware Acceleration
@@ -91,7 +91,9 @@ You can also add `COMPOSE_PROFILES=nvidia` to your `.env` instead of adding the
Note that most nvidia cards have an artificial limit on the number of encodes. You can confirm your card limit [here](https://developer.nvidia.com/video-encode-and-decode-gpu-support-matrix-new).
This limit can also be removed by applying an [unofficial patch](https://github.com/keylase/nvidia-patch) to you driver.
# Custom volumes
# FAQ
## Custom volumes
To customize volumes, you can edit the `docker-compose.yml` manually.
@@ -107,8 +109,6 @@ For example, if your library is split into multiples paths you can edit the `vol
restart: unless-stopped
env_file:
- ./.env
environment:
- GOCODER_PREFIX=/video
volumes:
- - ${LIBRARY_ROOT}:/video:ro
+ - /my_path/number1:/video/1:ro
@@ -119,3 +119,19 @@ For example, if your library is split into multiples paths you can edit the `vol
You can also edit the volume definition to use advanced volume drivers if you need to access smb or network drives. Mounting a drive into your filesystem and binding it in this volume section is also a valid choice (especially for fuse filesystems like cloud drives for example).
Don't forget to **also edit the scanner's volumes** if you edit the transcoder's volume.
## Ignoring Directories
Kyoo supports excluding specific directories from scanning and monitoring by detecting the presence of a `.ignore` file. When a directory contains a `.ignore` file, Kyoo will recursively exclude that directory and all its contents from processing.
Example:
To exclude `/media/extras/**`, add a `.ignore` file:
```bash
touch /media/extras/.ignore
```
Kyoo will skip `/media/extras` and its contents in all future scans and monitoring events.
# OpenID Connect
Kyoo supports OpenID Connect (OIDC) for authentication. Please refer to the [OIDC.md](OIDC.md) file for more information.
<!-- vim: set wrap: -->

64
OIDC.md Normal file
View File

@@ -0,0 +1,64 @@
# OpenID Connect
Kyoo supports OpenID Connect (OIDC) for authentication. This allows you to use your existing identity provider to authenticate users in Kyoo.
## Configuration
To enable OIDC, you need to fill the following environment variables in your `.env` file:
```env
PUBLIC_URL=https://your-kyoo-instance.com
OIDC_<name>_NAME=<name>
OIDC_<name>_LOGO=https://url-of-your-logo.com
OIDC_<name>_CLIENTID=
OIDC_<name>_SECRET=
OIDC_<name>_AUTHORIZATION=https://url-of-the-authorization-endpoint-of-the-oidc-service.com/auth
OIDC_<name>_TOKEN=https://url-of-the-token-endpoint-of-the-oidc-service.com/token
OIDC_<name>_PROFILE=https://url-of-the-profile-endpoint-of-the-oidc-service.com/userinfo
OIDC_<name>_SCOPE="email openid profile"
OIDC_<name>_AUTHMETHOD=ClientSecretBasic
```
- `PUBLIC_URL` is the URL of your Kyoo instance. This is required for OIDC to work.
- `<name>` is the name of the OIDC provider. It can be anything you want. This will be the display name of the OIDC provider on the login page.
- `OIDC_<name>_LOGO` is the URL of the logo of the OIDC provider. It will be displayed on the login page.
- `OIDC_<name>_CLIENTID` is the client ID of the OIDC provider.
- `OIDC_<name>_SECRET` is the client secret of the OIDC provider.
- `OIDC_<name>_AUTHORIZATION` is the URL of the authorization endpoint of the OIDC provider.
- `OIDC_<name>_TOKEN` is the URL of the token endpoint of the OIDC provider.
- `OIDC_<name>_PROFILE` is the URL of the profile endpoint of the OIDC provider.
- `OIDC_<name>_SCOPE` is the scope of the OIDC provider. This is a space-separated list of scopes.
- `OIDC_<name>_AUTHMETHOD` is the authentication method of the OIDC provider. This can be `ClientSecretBasic` or `ClientSecretPost`.
## Example
### Google OIDC
To enable Google OIDC, please follow the instructions from the [Google Developers](https://developers.google.com/identity/gsi/web/guides/get-google-api-clientid) to create a new project and get the client ID and secret.
When creating the Oauth 2.0 Client ID, make sure to add the following redirect URI: `https://your-kyoo-instance.com/api/auth/logged/google`.
For the authorized JavaScript origins, add `https://your-kyoo-instance.com`.
Then, fill the following environment variables in your `.env` file:
```env
PUBLIC_URL=https://your-kyoo-instance.com
OIDC_GOOGLE_NAME=Google
OIDC_GOOGLE_LOGO=https://www.gstatic.com/marketing-cms/assets/images/d5/dc/cfe9ce8b4425b410b49b7f2dd3f3/g.webp=s200
OIDC_GOOGLE_CLIENTID=<client-id> # the client ID you got from Google
OIDC_GOOGLE_SECRET=<client-secret> # the client secret you got from Google
OIDC_GOOGLE_AUTHORIZATION=https://accounts.google.com/o/oauth2/auth
OIDC_GOOGLE_TOKEN=https://oauth2.googleapis.com/token
OIDC_GOOGLE_PROFILE=https://www.googleapis.com/oauth2/v2/userinfo
OIDC_GOOGLE_SCOPE="email openid profile"
OIDC_GOOGLE_AUTHMETHOD=ClientSecretPost
```
### Another OIDC providers
To enable another OIDC provider, just fill the environment variables with the information you got from the provider.
Remember that when `<name>` is `XYZ`, the environment variables should start with `OIDC_XYZ_`.
In that case, the callback URL will be `https://your-kyoo-instance.com/api/auth/logged/xyz`.

View File

@@ -12,7 +12,7 @@ Kyoo does not have a plugin system and aim to have every features built-in (see
- **[Installation](./INSTALLING.md):** Basic installation guidelines, how to start Kyoo, enable OIDC or hardware transcoding.
- **[Join the discord](https://discord.gg/E6Apw3aFaA):** Ask questions, talk about the development, feature you might want or bugs you might encounter.
- **[API Documentation](https://kyoo.zoriya.dev/api/doc):** The API to integrate Kyoo with other services, if you have any questions, please ask on github or discord!
- **[API Documentation](https://kyoo.zoriya.dev/api/doc):** The API to integrate Kyoo with other services, if you have any questions, please ask on GitHub or Discord!
- **[Contributing](./CONTRIBUTING.md):** Feel free to open issues, submit pull requests, and contribute to making Kyoo even better. We need you!
[![](https://discord.com/api/guilds/1216460898139635753/widget.png?style=banner2)](https://discord.gg/zpA74Qpvj5)
@@ -29,24 +29,21 @@ Kyoo does not have a plugin system and aim to have every features built-in (see
- **Watch List Scrubbing Support:** Your watch list is automatically synced to connected services (SIMKL and soon others [#351](https://github.com/zoriya/Kyoo/issues/351), [#352](https://github.com/zoriya/Kyoo/issues/352)). No need to manually mark episodes as watched.
- **Download and Offline Support:** Download videos to watch them without internet access, you progress will automatically be synced next time your devices goes online.
- **Download and Offline Support:** Download videos to watch them without internet access, your progress will automatically be synced next time your devices goes online.
- **Enhanced Subtitle Support:** Subtitles are important, Kyoo supports SSA/ASS and uses the video's embedded fonts when available.
- **Anime Name Parsing**: While there are still some issues (see [#466](https://github.com/zoriya/Kyoo/issues/466), Kyoo will match weird anime names (like `[Some-Stuffs] Jojo's Bizarre Adventure Stone Ocean 24 (1920x1080 Blu-Ray Opus) [2750810F].mkv`) without issue.
- **Cloud Native:** Still an ongoing effort (see [#357](https://github.com/zoriya/Kyoo/issues/357)) but Kyoo is made with the idea that it could run distributed or standalone, on an RPI or on huge home-datacenters.
- **Helm Chart:** Deploy Kyoo to your Kubernetes cluster today! There is an official Helm chart. Multiple replicas is a WIP!
## 📺 Clients
Clients is a bit part of media servers but for now, Kyoo's focus is on features. Only a web version and an android apps are available for now. The front is written with react-native (expo) so adapting for others platform is possible. Here is a rough roadmap of clients supports:
- Today: Web & Android
- End of 2024: Chromecast support
- Summer 2025: Android TV app
Kyoo currently supports Web and Android clients, with additional platforms being thought about.
Apple devices are not planned for now because I do not own any of their device, and it requires $100/year.
Don't see your client? Kyoo is focused on adding features, but welcomes contributors! The frontend is built with React-Native and Expo. Come hang and develop with us on Discord.
If you would like to have a client sooner or on devices not listed on the roadmap, come hang on the discord and consider contributing to Kyoo.
Support for Apple devices (iOS, tvOS) is not currently planned due to buying hardware and yearly developer fee (~$100).
## 📖 Translations
@@ -58,9 +55,9 @@ If Kyoo is not available on your language, you can use [weblate](https://hosted.
From a technical standpoint, both Jellyfin and Plex lean on SQLite and confine everything within a single container, Kyoo takes a different route. We're not afraid to bring in additional containers when it makes sense whether for specialized features like Meilisearch powering our search system or for scalability, as seen with our transcoder.
Kyoo embraces the "setup once, forget about it" philosophy. Unlike Plex and Jellyfin, we don't burden you with manual file renaming or specific folder structures. Kyoo seamlessly works with files straight from your download directory, minimizing the maintenance headache for server admins.
Kyoo embraces the setup once, forget about it philosophy. Unlike Plex and Jellyfin, we don't burden you with manual file renaming or specific folder structures. Kyoo seamlessly works with files straight from your download directory, minimizing the maintenance headache for server admins.
Kyoo narrows its focus to movies, TV shows, and anime streaming. No music, ebooks, or games just pure cinematic delight.
Kyoo narrows its focus to movies, TV shows, and anime streaming. No music, e-books, or games just pure cinematic delight.
## 🔗 Live Demo

7
api/.dockerignore Normal file
View File

@@ -0,0 +1,7 @@
**
!/package.json
!/bun.lock
!/tsconfig.json
!/patches
!/src
!/drizzle

31
api/.env.example Normal file
View File

@@ -0,0 +1,31 @@
# vi: ft=sh
# shellcheck disable=SC2034
# either an hard-coded secret to decode jwts or empty to use keibi's public secret.
# this should only be used in tests
JWT_SECRET=
# used to verify who's making the jwt
JWT_ISSUER=$PUBLIC_URL
# keibi's server to retrieve the public jwt secret
AUTH_SERVER=http://auth:4568
IMAGES_PATH=./images
OTEL_EXPORTER_OTLP_PROTOCOL="http/protobuf"
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4317"
# It is recommended to use the below PG environment variables when possible.
# POSTGRES_URL=postgres://user:password@hostname:port/dbname?sslmode=verify-full&sslrootcert=/path/to/server.crt&sslcert=/path/to/client.crt&sslkey=/path/to/client.key
# The behavior of the below variables match what is documented here:
# https://www.postgresql.org/docs/current/libpq-envars.html
PGUSER=kyoo
PGPASSWORD=password
PGDATABASE=kyoo
PGHOST=postgres
PGPORT=5432
# PGOPTIONS=-c search_path=kyoo,public
# PGPASSFILE=/my/password # Takes precedence over PGPASSWORD. New line characters are not trimmed.
# PGSSLMODE=verify-full
# PGSSLROOTCERT=/my/serving.crt
# PGSSLCERT=/my/client.crt
# PGSSLKEY=/my/client.key

3
api/.gitignore vendored Normal file
View File

@@ -0,0 +1,3 @@
/node_modules
**/*.bun
images

30
api/Dockerfile Normal file
View File

@@ -0,0 +1,30 @@
FROM oven/bun:debian AS builder
WORKDIR /app
COPY package.json bun.lock .
COPY patches patches
RUN bun install --production
COPY src src
COPY drizzle drizzle
COPY tsconfig.json .
ENV NODE_ENV=production
RUN bun build \
--compile \
--minify-whitespace \
--minify-syntax \
--target bun \
--outfile server \
./src/index.ts
FROM debian
WORKDIR /app
COPY --from=builder /app/server server
COPY --from=builder /app/node_modules/@img /app/node_modules/@img
COPY ./drizzle ./drizzle
ENV NODE_ENV=production
EXPOSE 3567
CMD ["/app/server"]

12
api/Dockerfile.dev Normal file
View File

@@ -0,0 +1,12 @@
FROM oven/bun AS builder
WORKDIR /app
COPY package.json bun.lock .
COPY patches patches
RUN bun install --production
COPY . .
EXPOSE 3567
CMD ["bun", "dev"]

164
api/README.md Normal file
View File

@@ -0,0 +1,164 @@
# Kyoo API
## Database schema
The many-to-many relation between entries (episodes/movies) & videos is NOT a mistake. Some video files can contain multiples episodes (like `MyShow 2&3.mvk`). One video file can also contain only a portion of an episode (like `MyShow 2 Part 1.mkv`)
```mermaid
erDiagram
shows {
guid id PK
kind kind "serie|movie|collection"
string(128) slug UK
genre[] genres
int rating "From 0 to 100"
status status "NN"
datetime added_date
date start_air
date end_air "null for movies"
datetime next_refresh
jsonb external_id
guid studio_id FK
string original_language
guid collection_id FK
}
show_translations {
guid id PK, FK
string language PK
string name "NN"
string tagline
string[] aliases
string description
string[] tags
string trailerUrl
jsonb poster
jsonb banner
jsonb logo
jsonb thumbnail
}
shows ||--|{ show_translations : has
shows |o--|| entries : has
shows |o--|| shows : has_collection
entries {
guid id PK
string(256) slug UK
guid show_id FK, UK
%% Order is absolute number.
uint order "NN"
uint season_number UK
uint episode_number UK "NN"
type type "episode|movie|special|extra"
date air_date
uint runtime
jsonb thumbnail
datetime next_refresh
jsonb external_id
}
entry_translations {
guid id PK, FK
string language PK
string name
string description
}
entries ||--|{ entry_translations : has
videos {
guid id PK
string path "NN"
uint rendering "dedup for duplicates part1/2"
uint part
uint version "max version is preferred rendering"
}
videos }|--|{ entries : for
seasons {
guid id PK
string(256) slug UK
guid show_id FK
uint season_number "NN"
datetime added_date
date start_air
date end_air
datetime next_refresh
jsonb external_id
}
season_translations {
guid id PK,FK
string language PK
string name
string description
jsonb poster
jsonb banner
jsonb logo
jsonb thumbnail
}
seasons ||--|{ season_translations : has
seasons ||--o{ entries : has
shows ||--|{ seasons : has
users {
guid id PK
}
watchlist {
guid show_id PK, FK
guid user_id PK, FK
status status "completed|watching|rewatching|dropped|planned"
uint seen_entry_count "NN"
guid next_entry FK
}
shows ||--|{ watchlist : has
users ||--|{ watchlist : has
watchlist ||--|o entries : next_entry
history {
int id PK
guid entry_id FK
guid profile_id FK
guid video_id FK
jsonb progress "{ percent, time }"
datetime played_date
}
entries ||--|{ history : part_of
users ||--|{ history : has
videos o|--o{ history : has
roles {
guid show_id PK, FK
guid staff_id PK, FK
uint order
type type "actor|director|writer|producer|music|other"
string character_name
string character_latin_name
jsonb character_image
}
staff {
guid id PK
string(256) slug UK
string name "NN"
string latin_name
jsonb image
datetime next_refresh
jsonb external_id
}
staff ||--|{ roles : has
shows ||--|{ roles : has
studios {
guid id PK
string(128) slug UK
jsonb logo
datetime next_refresh
jsonb external_id
}
studio_translations {
guid id PK,FK
string language PK
string name
}
studios ||--|{ studio_translations : has
shows }|--|{ studios : has
```

3
api/biome.json Normal file
View File

@@ -0,0 +1,3 @@
{
"extends": "//"
}

492
api/bun.lock Normal file
View File

@@ -0,0 +1,492 @@
{
"lockfileVersion": 1,
"configVersion": 0,
"workspaces": {
"": {
"name": "api",
"dependencies": {
"@elysiajs/opentelemetry": "^1.4.8",
"@elysiajs/swagger": "zoriya/elysia-swagger#build",
"@kubiks/otel-drizzle": "zoriya/drizzle-otel#build",
"@types/bun": "^1.3.1",
"blurhash": "^2.0.5",
"drizzle-kit": "^0.31.5",
"drizzle-orm": "0.44.7",
"elysia": "^1.4.13",
"jose": "^6.1.0",
"node-addon-api": "^8.5.0",
"parjs": "^1.3.9",
"pg": "^8.16.3",
"sharp": "^0.34.4",
},
"devDependencies": {
"@biomejs/biome": "2.3.7",
"@types/pg": "^8.15.5",
},
},
},
"patchedDependencies": {
"drizzle-orm@0.44.7": "patches/drizzle-orm@0.44.7.patch",
},
"packages": {
"@biomejs/biome": ["@biomejs/biome@2.3.7", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.7", "@biomejs/cli-darwin-x64": "2.3.7", "@biomejs/cli-linux-arm64": "2.3.7", "@biomejs/cli-linux-arm64-musl": "2.3.7", "@biomejs/cli-linux-x64": "2.3.7", "@biomejs/cli-linux-x64-musl": "2.3.7", "@biomejs/cli-win32-arm64": "2.3.7", "@biomejs/cli-win32-x64": "2.3.7" }, "bin": { "biome": "bin/biome" } }, "sha512-CTbAS/jNAiUc6rcq94BrTB8z83O9+BsgWj2sBCQg9rD6Wkh2gjfR87usjx0Ncx0zGXP1NKgT7JNglay5Zfs9jw=="],
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.7", "", { "os": "darwin", "cpu": "arm64" }, "sha512-LirkamEwzIUULhXcf2D5b+NatXKeqhOwilM+5eRkbrnr6daKz9rsBL0kNZ16Hcy4b8RFq22SG4tcLwM+yx/wFA=="],
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.7", "", { "os": "darwin", "cpu": "x64" }, "sha512-Q4TO633kvrMQkKIV7wmf8HXwF0dhdTD9S458LGE24TYgBjSRbuhvio4D5eOQzirEYg6eqxfs53ga/rbdd8nBKg=="],
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-inHOTdlstUBzgjDcx0ge71U4SVTbwAljmkfi3MC5WzsYCRhancqfeL+sa4Ke6v2ND53WIwCFD5hGsYExoI3EZQ=="],
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.7", "", { "os": "linux", "cpu": "arm64" }, "sha512-/afy8lto4CB8scWfMdt+NoCZtatBUF62Tk3ilWH2w8ENd5spLhM77zKlFZEvsKJv9AFNHknMl03zO67CiklL2Q=="],
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-fJMc3ZEuo/NaMYo5rvoWjdSS5/uVSW+HPRQujucpZqm2ZCq71b8MKJ9U4th9yrv2L5+5NjPF0nqqILCl8HY/fg=="],
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.7", "", { "os": "linux", "cpu": "x64" }, "sha512-CQUtgH1tIN6e5wiYSJqzSwJumHYolNtaj1dwZGCnZXm2PZU1jOJof9TsyiP3bXNDb+VOR7oo7ZvY01If0W3iFQ=="],
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.7", "", { "os": "win32", "cpu": "arm64" }, "sha512-aJAE8eCNyRpcfx2JJAtsPtISnELJ0H4xVVSwnxm13bzI8RwbXMyVtxy2r5DV1xT3WiSP+7LxORcApWw0LM8HiA=="],
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.7", "", { "os": "win32", "cpu": "x64" }, "sha512-pulzUshqv9Ed//MiE8MOUeeEkbkSHVDVY5Cz5wVAnH1DUqliCQG3j6s1POaITTFqFfo7AVIx2sWdKpx/GS+Nqw=="],
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
"@elysiajs/opentelemetry": ["@elysiajs/opentelemetry@1.4.8", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/instrumentation": "^0.200.0", "@opentelemetry/sdk-node": "^0.200.0" }, "peerDependencies": { "elysia": ">= 1.4.0" } }, "sha512-c9unbcdXfehExCv1GsiTCfos5SyIAyDwP7apcMeXmUMBaJZiAYMfiEH8RFFFIfIHJHC/xlNJzUPodkcUaaoJJQ=="],
"@elysiajs/swagger": ["@elysiajs/swagger@github:zoriya/elysia-swagger#f88fbc7", { "dependencies": { "@scalar/themes": "^0.9.81", "@scalar/types": "^0.1.3", "openapi-types": "^12.1.3", "pathe": "^1.1.2" }, "peerDependencies": { "elysia": ">= 1.3.0" } }, "zoriya-elysia-swagger-f88fbc7"],
"@emnapi/runtime": ["@emnapi/runtime@1.6.0", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-obtUmAHTMjll499P+D9A3axeJFlhdjOWdKUNs/U6QIGT7V5RjcUW1xToAzjvmgTSQhDbYn/NwfTRoJcQ2rNBxA=="],
"@esbuild-kit/core-utils": ["@esbuild-kit/core-utils@3.3.2", "", { "dependencies": { "esbuild": "~0.18.20", "source-map-support": "^0.5.21" } }, "sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ=="],
"@esbuild-kit/esm-loader": ["@esbuild-kit/esm-loader@2.6.5", "", { "dependencies": { "@esbuild-kit/core-utils": "^3.3.2", "get-tsconfig": "^4.7.0" } }, "sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA=="],
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="],
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.11", "", { "os": "android", "cpu": "arm" }, "sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg=="],
"@esbuild/android-arm64": ["@esbuild/android-arm64@0.25.11", "", { "os": "android", "cpu": "arm64" }, "sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ=="],
"@esbuild/android-x64": ["@esbuild/android-x64@0.25.11", "", { "os": "android", "cpu": "x64" }, "sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g=="],
"@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.25.11", "", { "os": "darwin", "cpu": "arm64" }, "sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w=="],
"@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.25.11", "", { "os": "darwin", "cpu": "x64" }, "sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ=="],
"@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.25.11", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA=="],
"@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.25.11", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw=="],
"@esbuild/linux-arm": ["@esbuild/linux-arm@0.25.11", "", { "os": "linux", "cpu": "arm" }, "sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw=="],
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA=="],
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.11", "", { "os": "linux", "cpu": "ia32" }, "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw=="],
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw=="],
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ=="],
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.11", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw=="],
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww=="],
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.11", "", { "os": "linux", "cpu": "s390x" }, "sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw=="],
"@esbuild/linux-x64": ["@esbuild/linux-x64@0.25.11", "", { "os": "linux", "cpu": "x64" }, "sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ=="],
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg=="],
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.11", "", { "os": "none", "cpu": "x64" }, "sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A=="],
"@esbuild/openbsd-arm64": ["@esbuild/openbsd-arm64@0.25.11", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg=="],
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.11", "", { "os": "openbsd", "cpu": "x64" }, "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw=="],
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ=="],
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.11", "", { "os": "sunos", "cpu": "x64" }, "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA=="],
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q=="],
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA=="],
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.11", "", { "os": "win32", "cpu": "x64" }, "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA=="],
"@grpc/grpc-js": ["@grpc/grpc-js@1.14.1", "", { "dependencies": { "@grpc/proto-loader": "^0.8.0", "@js-sdsl/ordered-map": "^4.4.2" } }, "sha512-sPxgEWtPUR3EnRJCEtbGZG2iX8LQDUls2wUS3o27jg07KqJFMq6YDeWvMo1wfpmy3rqRdS0rivpLwhqQtEyCuQ=="],
"@grpc/proto-loader": ["@grpc/proto-loader@0.8.0", "", { "dependencies": { "lodash.camelcase": "^4.3.0", "long": "^5.0.0", "protobufjs": "^7.5.3", "yargs": "^17.7.2" }, "bin": { "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" } }, "sha512-rc1hOQtjIWGxcxpb9aHAfLpIctjEnsDehj0DAiVfBlmT84uvR0uUtN2hEi/ecvWVjXUGf5qPF4qEgiLOx1YIMQ=="],
"@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="],
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.2.3" }, "os": "darwin", "cpu": "arm64" }, "sha512-sitdlPzDVyvmINUdJle3TNHl+AG9QcwiAMsXmccqsCOMZNIdW2/7S26w0LyU8euiLVzFBL3dXPwVCq/ODnf2vA=="],
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.2.3" }, "os": "darwin", "cpu": "x64" }, "sha512-rZheupWIoa3+SOdF/IcUe1ah4ZDpKBGWcsPX6MT0lYniH9micvIU7HQkYTfrx5Xi8u+YqwLtxC/3vl8TQN6rMg=="],
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw=="],
"@img/sharp-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.2.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Ju+g2xn1E2AKO6YBhxjj+ACcsPQRHT0bhpglxcEf+3uyPY+/gL8veniKoo96335ZaPo03bdDXMv0t+BBFAbmRA=="],
"@img/sharp-libvips-linux-arm": ["@img/sharp-libvips-linux-arm@1.2.3", "", { "os": "linux", "cpu": "arm" }, "sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA=="],
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ=="],
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg=="],
"@img/sharp-libvips-linux-s390x": ["@img/sharp-libvips-linux-s390x@1.2.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w=="],
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg=="],
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw=="],
"@img/sharp-libvips-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.2.3", "", { "os": "linux", "cpu": "x64" }, "sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g=="],
"@img/sharp-linux-arm": ["@img/sharp-linux-arm@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.2.3" }, "os": "linux", "cpu": "arm" }, "sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA=="],
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.2.3" }, "os": "linux", "cpu": "arm64" }, "sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ=="],
"@img/sharp-linux-ppc64": ["@img/sharp-linux-ppc64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-ppc64": "1.2.3" }, "os": "linux", "cpu": "ppc64" }, "sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ=="],
"@img/sharp-linux-s390x": ["@img/sharp-linux-s390x@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.2.3" }, "os": "linux", "cpu": "s390x" }, "sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw=="],
"@img/sharp-linux-x64": ["@img/sharp-linux-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.2.3" }, "os": "linux", "cpu": "x64" }, "sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A=="],
"@img/sharp-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.2.3" }, "os": "linux", "cpu": "arm64" }, "sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA=="],
"@img/sharp-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.4", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.2.3" }, "os": "linux", "cpu": "x64" }, "sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg=="],
"@img/sharp-wasm32": ["@img/sharp-wasm32@0.34.4", "", { "dependencies": { "@emnapi/runtime": "^1.5.0" }, "cpu": "none" }, "sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA=="],
"@img/sharp-win32-arm64": ["@img/sharp-win32-arm64@0.34.4", "", { "os": "win32", "cpu": "arm64" }, "sha512-2Q250do/5WXTwxW3zjsEuMSv5sUU4Tq9VThWKlU2EYLm4MB7ZeMwF+SFJutldYODXF6jzc6YEOC+VfX0SZQPqA=="],
"@img/sharp-win32-ia32": ["@img/sharp-win32-ia32@0.34.4", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ZeLue5V82dT92CNL6rsal6I2weKw1cYu+rGKm8fOCCtJTR2gYeUfY3FqUnIJsMUPIH68oS5jmZ0NiJ508YpEw=="],
"@img/sharp-win32-x64": ["@img/sharp-win32-x64@0.34.4", "", { "os": "win32", "cpu": "x64" }, "sha512-xIyj4wpYs8J18sVN3mSQjwrw7fKUqRw+Z5rnHNCy5fYTxigBz81u5mOMPmFumwjcn8+ld1ppptMBCLic1nz6ig=="],
"@js-sdsl/ordered-map": ["@js-sdsl/ordered-map@4.4.2", "", {}, "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw=="],
"@kubiks/otel-drizzle": ["@kubiks/otel-drizzle@github:zoriya/drizzle-otel#cc1d59b", { "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <2.0.0", "drizzle-orm": ">=0.28.0" } }, "zoriya-drizzle-otel-cc1d59b"],
"@opentelemetry/api": ["@opentelemetry/api@1.9.0", "", {}, "sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg=="],
"@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IKJBQxh91qJ+3ssRly5hYEJ8NDHu9oY/B1PXVSCWf7zytmYO9RNLB0Ox9XQ/fJ8m6gY6Q6NtBWlmXfaXt5Uc4Q=="],
"@opentelemetry/context-async-hooks": ["@opentelemetry/context-async-hooks@2.0.0", "", { "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-IEkJGzK1A9v3/EHjXh3s2IiFc6L4jfK+lNgKVgUjeUJQRRhnVFMIO3TAvKwonm9O1HebCuoOt98v8bZW7oVQHA=="],
"@opentelemetry/core": ["@opentelemetry/core@2.0.0", "", { "dependencies": { "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-SLX36allrcnVaPYG3R78F/UZZsBsvbc7lMCLx37LyH5MJ1KAAZ2E3mW9OAD3zGz0G8q/BtoS5VUrjzDydhD6LQ=="],
"@opentelemetry/exporter-logs-otlp-grpc": ["@opentelemetry/exporter-logs-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/sdk-logs": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+3MDfa5YQPGM3WXxW9kqGD85Q7s9wlEMVNhXXG7tYFLnIeaseUt9YtCeFhEDFzfEktacdFpOtXmJuNW8cHbU5A=="],
"@opentelemetry/exporter-logs-otlp-http": ["@opentelemetry/exporter-logs-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/sdk-logs": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-KfWw49htbGGp9s8N4KI8EQ9XuqKJ0VG+yVYVYFiCYSjEV32qpQ5qZ9UZBzOZ6xRb+E16SXOSCT3RkqBVSABZ+g=="],
"@opentelemetry/exporter-logs-otlp-proto": ["@opentelemetry/exporter-logs-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-GmahpUU/55hxfH4TP77ChOfftADsCq/nuri73I/AVLe2s4NIglvTsaACkFVZAVmnXXyPS00Fk3x27WS3yO07zA=="],
"@opentelemetry/exporter-metrics-otlp-grpc": ["@opentelemetry/exporter-metrics-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-uHawPRvKIrhqH09GloTuYeq2BjyieYHIpiklOvxm9zhrCL2eRsnI/6g9v2BZTVtGp8tEgIa7rCQ6Ltxw6NBgew=="],
"@opentelemetry/exporter-metrics-otlp-http": ["@opentelemetry/exporter-metrics-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-5BiR6i8yHc9+qW7F6LqkuUnIzVNA7lt0qRxIKcKT+gq3eGUPHZ3DY29sfxI3tkvnwMgtnHDMNze5DdxW39HsAw=="],
"@opentelemetry/exporter-metrics-otlp-proto": ["@opentelemetry/exporter-metrics-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-E+uPj0yyvz81U9pvLZp3oHtFrEzNSqKGVkIViTQY1rH3TOobeJPSpLnTVXACnCwkPR5XeTvPnK3pZ2Kni8AFMg=="],
"@opentelemetry/exporter-prometheus": ["@opentelemetry/exporter-prometheus@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-metrics": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-ZYdlU9r0USuuYppiDyU2VFRA0kFl855ylnb3N/2aOlXrbA4PMCznen7gmPbetGQu7pz8Jbaf4fwvrDnVdQQXSw=="],
"@opentelemetry/exporter-trace-otlp-grpc": ["@opentelemetry/exporter-trace-otlp-grpc@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-grpc-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-hmeZrUkFl1YMsgukSuHCFPYeF9df0hHoKeHUthRKFCxiURs+GwF1VuabuHmBMZnjTbsuvNjOB+JSs37Csem/5Q=="],
"@opentelemetry/exporter-trace-otlp-http": ["@opentelemetry/exporter-trace-otlp-http@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-Goi//m/7ZHeUedxTGVmEzH19NgqJY+Bzr6zXo1Rni1+hwqaksEyJ44gdlEMREu6dzX1DlAaH/qSykSVzdrdafA=="],
"@opentelemetry/exporter-trace-otlp-proto": ["@opentelemetry/exporter-trace-otlp-proto@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-V9TDSD3PjK1OREw2iT9TUTzNYEVWJk4Nhodzhp9eiz4onDMYmPy3LaGbPv81yIR6dUb/hNp/SIhpiCHwFUq2Vg=="],
"@opentelemetry/exporter-zipkin": ["@opentelemetry/exporter-zipkin@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0" } }, "sha512-icxaKZ+jZL/NHXX8Aru4HGsrdhK0MLcuRXkX5G5IRmCgoRLw+Br6I/nMVozX2xjGGwV7hw2g+4Slj8K7s4HbVg=="],
"@opentelemetry/instrumentation": ["@opentelemetry/instrumentation@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@types/shimmer": "^1.2.0", "import-in-the-middle": "^1.8.1", "require-in-the-middle": "^7.1.1", "shimmer": "^1.2.1" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-pmPlzfJd+vvgaZd/reMsC8RWgTXn2WY1OWT5RT42m3aOn5532TozwXNDhg1vzqJ+jnvmkREcdLr27ebJEQt0Jg=="],
"@opentelemetry/otlp-exporter-base": ["@opentelemetry/otlp-exporter-base@0.200.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-IxJgA3FD7q4V6gGq4bnmQM5nTIyMDkoGFGrBrrDjB6onEiq1pafma55V+bHvGYLWvcqbBbRfezr1GED88lacEQ=="],
"@opentelemetry/otlp-grpc-exporter-base": ["@opentelemetry/otlp-grpc-exporter-base@0.200.0", "", { "dependencies": { "@grpc/grpc-js": "^1.7.1", "@opentelemetry/core": "2.0.0", "@opentelemetry/otlp-exporter-base": "0.200.0", "@opentelemetry/otlp-transformer": "0.200.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-CK2S+bFgOZ66Bsu5hlDeOX6cvW5FVtVjFFbWuaJP0ELxJKBB6HlbLZQ2phqz/uLj1cWap5xJr/PsR3iGoB7Vqw=="],
"@opentelemetry/otlp-transformer": ["@opentelemetry/otlp-transformer@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "protobufjs": "^7.3.0" }, "peerDependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-+9YDZbYybOnv7sWzebWOeK6gKyt2XE7iarSyBFkwwnP559pEevKOUD8NyDHhRjCSp13ybh9iVXlMfcj/DwF/yw=="],
"@opentelemetry/propagator-b3": ["@opentelemetry/propagator-b3@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-blx9S2EI49Ycuw6VZq+bkpaIoiJFhsDuvFGhBIoH3vJ5oYjJ2U0s3fAM5jYft99xVIAv6HqoPtlP9gpVA2IZtA=="],
"@opentelemetry/propagator-jaeger": ["@opentelemetry/propagator-jaeger@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-Mbm/LSFyAtQKP0AQah4AfGgsD+vsZcyreZoQ5okFBk33hU7AquU4TltgyL9dvaO8/Zkoud8/0gEvwfOZ5d7EPA=="],
"@opentelemetry/resources": ["@opentelemetry/resources@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-rnZr6dML2z4IARI4zPGQV4arDikF/9OXZQzrC01dLmn0CZxU5U5OLd/m1T7YkGRj5UitjeoCtg/zorlgMQcdTg=="],
"@opentelemetry/sdk-logs": ["@opentelemetry/sdk-logs@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.4.0 <1.10.0" } }, "sha512-VZG870063NLfObmQQNtCVcdXXLzI3vOjjrRENmU37HYiPFa0ZXpXVDsTD02Nh3AT3xYJzQaWKl2X2lQ2l7TWJA=="],
"@opentelemetry/sdk-metrics": ["@opentelemetry/sdk-metrics@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.9.0 <1.10.0" } }, "sha512-Bvy8QDjO05umd0+j+gDeWcTaVa1/R2lDj/eOvjzpm8VQj1K1vVZJuyjThpV5/lSHyYW2JaHF2IQ7Z8twJFAhjA=="],
"@opentelemetry/sdk-node": ["@opentelemetry/sdk-node@0.200.0", "", { "dependencies": { "@opentelemetry/api-logs": "0.200.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/exporter-logs-otlp-grpc": "0.200.0", "@opentelemetry/exporter-logs-otlp-http": "0.200.0", "@opentelemetry/exporter-logs-otlp-proto": "0.200.0", "@opentelemetry/exporter-metrics-otlp-grpc": "0.200.0", "@opentelemetry/exporter-metrics-otlp-http": "0.200.0", "@opentelemetry/exporter-metrics-otlp-proto": "0.200.0", "@opentelemetry/exporter-prometheus": "0.200.0", "@opentelemetry/exporter-trace-otlp-grpc": "0.200.0", "@opentelemetry/exporter-trace-otlp-http": "0.200.0", "@opentelemetry/exporter-trace-otlp-proto": "0.200.0", "@opentelemetry/exporter-zipkin": "2.0.0", "@opentelemetry/instrumentation": "0.200.0", "@opentelemetry/propagator-b3": "2.0.0", "@opentelemetry/propagator-jaeger": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/sdk-logs": "0.200.0", "@opentelemetry/sdk-metrics": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0", "@opentelemetry/sdk-trace-node": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-S/YSy9GIswnhYoDor1RusNkmRughipvTCOQrlF1dzI70yQaf68qgf5WMnzUxdlCl3/et/pvaO75xfPfuEmCK5A=="],
"@opentelemetry/sdk-trace-base": ["@opentelemetry/sdk-trace-base@2.0.0", "", { "dependencies": { "@opentelemetry/core": "2.0.0", "@opentelemetry/resources": "2.0.0", "@opentelemetry/semantic-conventions": "^1.29.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, "sha512-qQnYdX+ZCkonM7tA5iU4fSRsVxbFGml8jbxOgipRGMFHKaXKHQ30js03rTobYjKjIfnOsZSbHKWF0/0v0OQGfw=="],
"@opentelemetry/sdk-trace-node": ["@opentelemetry/sdk-trace-node@2.0.0", "", { "dependencies": { "@opentelemetry/context-async-hooks": "2.0.0", "@opentelemetry/core": "2.0.0", "@opentelemetry/sdk-trace-base": "2.0.0" }, "peerDependencies": { "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, "sha512-omdilCZozUjQwY3uZRBwbaRMJ3p09l4t187Lsdf0dGMye9WKD4NGcpgZRvqhI1dwcH6og+YXQEtoO9Wx3ykilg=="],
"@opentelemetry/semantic-conventions": ["@opentelemetry/semantic-conventions@1.38.0", "", {}, "sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg=="],
"@protobufjs/aspromise": ["@protobufjs/aspromise@1.1.2", "", {}, "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ=="],
"@protobufjs/base64": ["@protobufjs/base64@1.1.2", "", {}, "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg=="],
"@protobufjs/codegen": ["@protobufjs/codegen@2.0.4", "", {}, "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg=="],
"@protobufjs/eventemitter": ["@protobufjs/eventemitter@1.1.0", "", {}, "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q=="],
"@protobufjs/fetch": ["@protobufjs/fetch@1.1.0", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.1", "@protobufjs/inquire": "^1.1.0" } }, "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ=="],
"@protobufjs/float": ["@protobufjs/float@1.0.2", "", {}, "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ=="],
"@protobufjs/inquire": ["@protobufjs/inquire@1.1.0", "", {}, "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q=="],
"@protobufjs/path": ["@protobufjs/path@1.1.2", "", {}, "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA=="],
"@protobufjs/pool": ["@protobufjs/pool@1.1.0", "", {}, "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw=="],
"@protobufjs/utf8": ["@protobufjs/utf8@1.1.0", "", {}, "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw=="],
"@scalar/openapi-types": ["@scalar/openapi-types@0.1.9", "", {}, "sha512-HQQudOSQBU7ewzfnBW9LhDmBE2XOJgSfwrh5PlUB7zJup/kaRkBGNgV2wMjNz9Af/uztiU/xNrO179FysmUT+g=="],
"@scalar/themes": ["@scalar/themes@0.9.81", "", { "dependencies": { "@scalar/types": "0.1.3" } }, "sha512-asTgdqo8ZYibBBWVYy0503qPx3cvwDlYNuc/cLbrCmTav0MAEL4wNb/gz9iScMVSMwhdkSkL5g9LPdr2mQrHzw=="],
"@scalar/types": ["@scalar/types@0.1.3", "", { "dependencies": { "@scalar/openapi-types": "0.1.9", "@unhead/schema": "^1.11.11", "zod": "^3.23.8" } }, "sha512-Fxtgjp5wHhTzXiyODYWIoTsTy3oFC70vme+0I7MNwd8i6D8qplFNnpURueqBuP4MglBM2ZhFv3hPLw4D69anDA=="],
"@sinclair/typebox": ["@sinclair/typebox@0.34.33", "", {}, "sha512-5HAV9exOMcXRUxo+9iYB5n09XxzCXnfy4VTNW4xnDv+FgjzAGY989C28BIdljKqmF+ZltUwujE3aossvcVtq6g=="],
"@tokenizer/inflate": ["@tokenizer/inflate@0.2.7", "", { "dependencies": { "debug": "^4.4.0", "fflate": "^0.8.2", "token-types": "^6.0.0" } }, "sha512-MADQgmZT1eKjp06jpI2yozxaU9uVs4GzzgSL+uEq7bVcJ9V1ZXQkeGNql1fsSI0gMy1vhvNTNbUqrx+pZfJVmg=="],
"@tokenizer/token": ["@tokenizer/token@0.3.0", "", {}, "sha512-OvjF+z51L3ov0OyAU0duzsYuvO01PH7x4t6DJx+guahgTnBHkhJdG7soQeTSFLWN3efnHyibZ4Z8l2EuWwJN3A=="],
"@types/bun": ["@types/bun@1.3.1", "", { "dependencies": { "bun-types": "1.3.1" } }, "sha512-4jNMk2/K9YJtfqwoAa28c8wK+T7nvJFOjxI4h/7sORWcypRNxBpr+TPNaCfVWq70tLCJsqoFwcf0oI0JU/fvMQ=="],
"@types/node": ["@types/node@22.13.13", "", { "dependencies": { "undici-types": "~6.20.0" } }, "sha512-ClsL5nMwKaBRwPcCvH8E7+nU4GxHVx1axNvMZTFHMEfNI7oahimt26P5zjVCRrjiIWj6YFXfE1v3dEp94wLcGQ=="],
"@types/pg": ["@types/pg@8.15.5", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^2.2.0" } }, "sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ=="],
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
"@types/shimmer": ["@types/shimmer@1.2.0", "", {}, "sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg=="],
"@unhead/schema": ["@unhead/schema@1.11.20", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-0zWykKAaJdm+/Y7yi/Yds20PrUK7XabLe9c3IRcjnwYmSWY6z0Cr19VIs3ozCj8P+GhR+/TI2mwtGlueCEYouA=="],
"acorn": ["acorn@8.15.0", "", { "bin": { "acorn": "bin/acorn" } }, "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg=="],
"acorn-import-attributes": ["acorn-import-attributes@1.9.5", "", { "peerDependencies": { "acorn": "^8" } }, "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ=="],
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
"ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="],
"blurhash": ["blurhash@2.0.5", "", {}, "sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w=="],
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
"bun-types": ["bun-types@1.3.1", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-NMrcy7smratanWJ2mMXdpatalovtxVggkj11bScuWuiOoXTiKIu2eVS1/7qbyI/4yHedtsn175n4Sm4JcdHLXw=="],
"char-info": ["char-info@0.3.5", "", { "dependencies": { "node-interval-tree": "^1.3.3" } }, "sha512-gRslEBFEcuLMGLNO1EFIrdN1MMUfO+aqa7y8iWzNyAzB3mYKnTIvP+ioW3jpyeEvqA5WapVLIPINGtFjEIH4cQ=="],
"cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="],
"cliui": ["cliui@8.0.1", "", { "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", "wrap-ansi": "^7.0.0" } }, "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ=="],
"color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="],
"color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="],
"cookie": ["cookie@1.0.2", "", {}, "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA=="],
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
"debug": ["debug@4.4.0", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA=="],
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
"drizzle-kit": ["drizzle-kit@0.31.5", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.4", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-+CHgPFzuoTQTt7cOYCV6MOw2w8vqEn/ap1yv4bpZOWL03u7rlVRQhUY0WYT3rHsgVTXwYQDZaSUJSQrMBUKuWg=="],
"drizzle-orm": ["drizzle-orm@0.44.7", "", { "peerDependencies": { "@aws-sdk/client-rds-data": ">=3", "@cloudflare/workers-types": ">=4", "@electric-sql/pglite": ">=0.2.0", "@libsql/client": ">=0.10.0", "@libsql/client-wasm": ">=0.10.0", "@neondatabase/serverless": ">=0.10.0", "@op-engineering/op-sqlite": ">=2", "@opentelemetry/api": "^1.4.1", "@planetscale/database": ">=1.13", "@prisma/client": "*", "@tidbcloud/serverless": "*", "@types/better-sqlite3": "*", "@types/pg": "*", "@types/sql.js": "*", "@upstash/redis": ">=1.34.7", "@vercel/postgres": ">=0.8.0", "@xata.io/client": "*", "better-sqlite3": ">=7", "bun-types": "*", "expo-sqlite": ">=14.0.0", "gel": ">=2", "knex": "*", "kysely": "*", "mysql2": ">=2", "pg": ">=8", "postgres": ">=3", "sql.js": ">=1", "sqlite3": ">=5" }, "optionalPeers": ["@aws-sdk/client-rds-data", "@cloudflare/workers-types", "@electric-sql/pglite", "@libsql/client", "@libsql/client-wasm", "@neondatabase/serverless", "@op-engineering/op-sqlite", "@opentelemetry/api", "@planetscale/database", "@prisma/client", "@tidbcloud/serverless", "@types/better-sqlite3", "@types/pg", "@types/sql.js", "@upstash/redis", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ=="],
"elysia": ["elysia@1.4.13", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.2.2", "fast-decode-uri-component": "^1.0.1", "memoirist": "^0.4.0" }, "peerDependencies": { "@sinclair/typebox": ">= 0.34.0 < 1", "@types/bun": ">= 1.2.0", "file-type": ">= 20.0.0", "openapi-types": ">= 12.0.0", "typescript": ">= 5.0.0" }, "optionalPeers": ["@types/bun", "typescript"] }, "sha512-6QaWQEm7QN1UCo1TPpEjaRJPHUmnM7R29y6LY224frDGk5PrpAnWmdHkoZxkcv+JRWp1j2ROr2IHbxHbG/jRjw=="],
"emoji-regex": ["emoji-regex@8.0.0", "", {}, "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A=="],
"esbuild": ["esbuild@0.25.11", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.11", "@esbuild/android-arm": "0.25.11", "@esbuild/android-arm64": "0.25.11", "@esbuild/android-x64": "0.25.11", "@esbuild/darwin-arm64": "0.25.11", "@esbuild/darwin-x64": "0.25.11", "@esbuild/freebsd-arm64": "0.25.11", "@esbuild/freebsd-x64": "0.25.11", "@esbuild/linux-arm": "0.25.11", "@esbuild/linux-arm64": "0.25.11", "@esbuild/linux-ia32": "0.25.11", "@esbuild/linux-loong64": "0.25.11", "@esbuild/linux-mips64el": "0.25.11", "@esbuild/linux-ppc64": "0.25.11", "@esbuild/linux-riscv64": "0.25.11", "@esbuild/linux-s390x": "0.25.11", "@esbuild/linux-x64": "0.25.11", "@esbuild/netbsd-arm64": "0.25.11", "@esbuild/netbsd-x64": "0.25.11", "@esbuild/openbsd-arm64": "0.25.11", "@esbuild/openbsd-x64": "0.25.11", "@esbuild/openharmony-arm64": "0.25.11", "@esbuild/sunos-x64": "0.25.11", "@esbuild/win32-arm64": "0.25.11", "@esbuild/win32-ia32": "0.25.11", "@esbuild/win32-x64": "0.25.11" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q=="],
"esbuild-register": ["esbuild-register@3.6.0", "", { "dependencies": { "debug": "^4.3.4" }, "peerDependencies": { "esbuild": ">=0.12 <1" } }, "sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg=="],
"escalade": ["escalade@3.2.0", "", {}, "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA=="],
"exact-mirror": ["exact-mirror@0.2.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-CrGe+4QzHZlnrXZVlo/WbUZ4qQZq8C0uATQVGVgXIrNXgHDBBNFD1VRfssRA2C9t3RYvh3MadZSdg2Wy7HBoQA=="],
"fast-decode-uri-component": ["fast-decode-uri-component@1.0.1", "", {}, "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg=="],
"fflate": ["fflate@0.8.2", "", {}, "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A=="],
"file-type": ["file-type@20.5.0", "", { "dependencies": { "@tokenizer/inflate": "^0.2.6", "strtok3": "^10.2.0", "token-types": "^6.0.0", "uint8array-extras": "^1.4.0" } }, "sha512-BfHZtG/l9iMm4Ecianu7P8HRD2tBHLtjXinm4X62XBOYzi7CYA7jyqfJzOvXHqzVrVPYqBo2/GvbARMaaJkKVg=="],
"function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="],
"get-caller-file": ["get-caller-file@2.0.5", "", {}, "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg=="],
"get-tsconfig": ["get-tsconfig@4.10.0", "", { "dependencies": { "resolve-pkg-maps": "^1.0.0" } }, "sha512-kGzZ3LWWQcGIAmg6iWvXn0ei6WDtV26wzHRMwDSzmAbcXrTEXxHy6IehI6/4eT6VRKyMP1eF1VqwrVUmE/LR7A=="],
"hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="],
"hookable": ["hookable@5.5.3", "", {}, "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ=="],
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
"import-in-the-middle": ["import-in-the-middle@1.15.0", "", { "dependencies": { "acorn": "^8.14.0", "acorn-import-attributes": "^1.9.5", "cjs-module-lexer": "^1.2.2", "module-details-from-path": "^1.0.3" } }, "sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA=="],
"is-core-module": ["is-core-module@2.16.1", "", { "dependencies": { "hasown": "^2.0.2" } }, "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w=="],
"is-fullwidth-code-point": ["is-fullwidth-code-point@3.0.0", "", {}, "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg=="],
"jose": ["jose@6.1.0", "", {}, "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA=="],
"lodash.camelcase": ["lodash.camelcase@4.3.0", "", {}, "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA=="],
"long": ["long@5.3.2", "", {}, "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA=="],
"memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="],
"module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="],
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
"node-addon-api": ["node-addon-api@8.5.0", "", {}, "sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A=="],
"node-interval-tree": ["node-interval-tree@1.3.3", "", { "dependencies": { "shallowequal": "^1.0.2" } }, "sha512-K9vk96HdTK5fEipJwxSvIIqwTqr4e3HRJeJrNxBSeVMNSC/JWARRaX7etOLOuTmrRMeOI/K5TCJu3aWIwZiNTw=="],
"openapi-types": ["openapi-types@12.1.3", "", {}, "sha512-N4YtSYJqghVu4iek2ZUvcN/0aqH1kRDuNqzcycDxhOUpg7GdvLa2F3DgS6yBNhInhv2r/6I0Flkn7CqL8+nIcw=="],
"parjs": ["parjs@1.3.9", "", { "dependencies": { "char-info": "0.3.*" } }, "sha512-zmQhbzWM3M391tjwTGvNvvtoT8rRE/bBTjw6+54g8ANaPpnyekDF1d8q5tzN4kxmVud82cNj8zSd+uxSL4LE0A=="],
"path-parse": ["path-parse@1.0.7", "", {}, "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw=="],
"pathe": ["pathe@1.1.2", "", {}, "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ=="],
"peek-readable": ["peek-readable@7.0.0", "", {}, "sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ=="],
"pg": ["pg@8.16.3", "", { "dependencies": { "pg-connection-string": "^2.9.1", "pg-pool": "^3.10.1", "pg-protocol": "^1.10.3", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.2.7" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-enxc1h0jA/aq5oSDMvqyW3q89ra6XIIDZgCX9vkMrnz5DFTw/Ny3Li2lFQ+pt3L6MCgm/5o2o8HW9hiJji+xvw=="],
"pg-cloudflare": ["pg-cloudflare@1.2.7", "", {}, "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg=="],
"pg-connection-string": ["pg-connection-string@2.9.1", "", {}, "sha512-nkc6NpDcvPVpZXxrreI/FOtX3XemeLl8E0qFr6F2Lrm/I8WOnaWNhIPK2Z7OHpw7gh5XJThi6j6ppgNoaT1w4w=="],
"pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="],
"pg-pool": ["pg-pool@3.10.1", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-Tu8jMlcX+9d8+QVzKIvM/uJtp07PKr82IUOYEphaWcoBhIYkoHpLXN3qO59nAI11ripznDsEzEv8nUxBVWajGg=="],
"pg-protocol": ["pg-protocol@1.10.0", "", {}, "sha512-IpdytjudNuLv8nhlHs/UrVBhU0e78J0oIS/0AVdTbWxSOkFUVdsHC/NrorO6nXsQNDTT1kzDSOMJubBQviX18Q=="],
"pg-types": ["pg-types@2.2.0", "", { "dependencies": { "pg-int8": "1.0.1", "postgres-array": "~2.0.0", "postgres-bytea": "~1.0.0", "postgres-date": "~1.0.4", "postgres-interval": "^1.1.0" } }, "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA=="],
"pgpass": ["pgpass@1.0.5", "", { "dependencies": { "split2": "^4.1.0" } }, "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug=="],
"postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
"postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="],
"postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
"postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
"protobufjs": ["protobufjs@7.5.4", "", { "dependencies": { "@protobufjs/aspromise": "^1.1.2", "@protobufjs/base64": "^1.1.2", "@protobufjs/codegen": "^2.0.4", "@protobufjs/eventemitter": "^1.1.0", "@protobufjs/fetch": "^1.1.0", "@protobufjs/float": "^1.0.2", "@protobufjs/inquire": "^1.1.0", "@protobufjs/path": "^1.1.2", "@protobufjs/pool": "^1.1.0", "@protobufjs/utf8": "^1.1.0", "@types/node": ">=13.7.0", "long": "^5.0.0" } }, "sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg=="],
"require-directory": ["require-directory@2.1.1", "", {}, "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q=="],
"require-in-the-middle": ["require-in-the-middle@7.5.2", "", { "dependencies": { "debug": "^4.3.5", "module-details-from-path": "^1.0.3", "resolve": "^1.22.8" } }, "sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ=="],
"resolve": ["resolve@1.22.11", "", { "dependencies": { "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, "bin": { "resolve": "bin/resolve" } }, "sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ=="],
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
"semver": ["semver@7.7.2", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA=="],
"shallowequal": ["shallowequal@1.1.0", "", {}, "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="],
"sharp": ["sharp@0.34.4", "", { "dependencies": { "@img/colour": "^1.0.0", "detect-libc": "^2.1.0", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.4", "@img/sharp-darwin-x64": "0.34.4", "@img/sharp-libvips-darwin-arm64": "1.2.3", "@img/sharp-libvips-darwin-x64": "1.2.3", "@img/sharp-libvips-linux-arm": "1.2.3", "@img/sharp-libvips-linux-arm64": "1.2.3", "@img/sharp-libvips-linux-ppc64": "1.2.3", "@img/sharp-libvips-linux-s390x": "1.2.3", "@img/sharp-libvips-linux-x64": "1.2.3", "@img/sharp-libvips-linuxmusl-arm64": "1.2.3", "@img/sharp-libvips-linuxmusl-x64": "1.2.3", "@img/sharp-linux-arm": "0.34.4", "@img/sharp-linux-arm64": "0.34.4", "@img/sharp-linux-ppc64": "0.34.4", "@img/sharp-linux-s390x": "0.34.4", "@img/sharp-linux-x64": "0.34.4", "@img/sharp-linuxmusl-arm64": "0.34.4", "@img/sharp-linuxmusl-x64": "0.34.4", "@img/sharp-wasm32": "0.34.4", "@img/sharp-win32-arm64": "0.34.4", "@img/sharp-win32-ia32": "0.34.4", "@img/sharp-win32-x64": "0.34.4" } }, "sha512-FUH39xp3SBPnxWvd5iib1X8XY7J0K0X7d93sie9CJg2PO8/7gmg89Nve6OjItK53/MlAushNNxteBYfM6DEuoA=="],
"shimmer": ["shimmer@1.2.1", "", {}, "sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw=="],
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
"source-map-support": ["source-map-support@0.5.21", "", { "dependencies": { "buffer-from": "^1.0.0", "source-map": "^0.6.0" } }, "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w=="],
"split2": ["split2@4.2.0", "", {}, "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg=="],
"string-width": ["string-width@4.2.3", "", { "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", "strip-ansi": "^6.0.1" } }, "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g=="],
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
"strtok3": ["strtok3@10.2.2", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "peek-readable": "^7.0.0" } }, "sha512-Xt18+h4s7Z8xyZ0tmBoRmzxcop97R4BAh+dXouUDCYn+Em+1P3qpkUfI5ueWLT8ynC5hZ+q4iPEmGG1urvQGBg=="],
"supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="],
"token-types": ["token-types@6.0.0", "", { "dependencies": { "@tokenizer/token": "^0.3.0", "ieee754": "^1.2.1" } }, "sha512-lbDrTLVsHhOMljPscd0yitpozq7Ga2M5Cvez5AjGg8GASBjtt6iERCAJ93yommPmz62fb45oFIXHEZ3u9bfJEA=="],
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
"uint8array-extras": ["uint8array-extras@1.4.0", "", {}, "sha512-ZPtzy0hu4cZjv3z5NW9gfKnNLjoz4y6uv4HlelAjDK7sY/xOkKZv9xK/WQpcsBB3jEybChz9DPC2U/+cusjJVQ=="],
"undici-types": ["undici-types@6.20.0", "", {}, "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg=="],
"wrap-ansi": ["wrap-ansi@7.0.0", "", { "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", "strip-ansi": "^6.0.0" } }, "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q=="],
"xtend": ["xtend@4.0.2", "", {}, "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="],
"y18n": ["y18n@5.0.8", "", {}, "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA=="],
"yargs": ["yargs@17.7.2", "", { "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", "string-width": "^4.2.3", "y18n": "^5.0.5", "yargs-parser": "^21.1.1" } }, "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w=="],
"yargs-parser": ["yargs-parser@21.1.1", "", {}, "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw=="],
"zhead": ["zhead@2.2.4", "", {}, "sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag=="],
"zod": ["zod@3.24.2", "", {}, "sha512-lY7CDW43ECgW9u1TcT3IoXHflywfVqDYze4waEz812jR/bZ8FHDsl7pFQoSZTz5N+2NqRXs8GBwnAwo3ZNxqhQ=="],
"@esbuild-kit/core-utils/esbuild": ["esbuild@0.18.20", "", { "optionalDependencies": { "@esbuild/android-arm": "0.18.20", "@esbuild/android-arm64": "0.18.20", "@esbuild/android-x64": "0.18.20", "@esbuild/darwin-arm64": "0.18.20", "@esbuild/darwin-x64": "0.18.20", "@esbuild/freebsd-arm64": "0.18.20", "@esbuild/freebsd-x64": "0.18.20", "@esbuild/linux-arm": "0.18.20", "@esbuild/linux-arm64": "0.18.20", "@esbuild/linux-ia32": "0.18.20", "@esbuild/linux-loong64": "0.18.20", "@esbuild/linux-mips64el": "0.18.20", "@esbuild/linux-ppc64": "0.18.20", "@esbuild/linux-riscv64": "0.18.20", "@esbuild/linux-s390x": "0.18.20", "@esbuild/linux-x64": "0.18.20", "@esbuild/netbsd-x64": "0.18.20", "@esbuild/openbsd-x64": "0.18.20", "@esbuild/sunos-x64": "0.18.20", "@esbuild/win32-arm64": "0.18.20", "@esbuild/win32-ia32": "0.18.20", "@esbuild/win32-x64": "0.18.20" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA=="],
"pg/pg-protocol": ["pg-protocol@1.10.3", "", {}, "sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm": ["@esbuild/android-arm@0.18.20", "", { "os": "android", "cpu": "arm" }, "sha512-fyi7TDI/ijKKNZTUJAQqiG5T7YjJXgnzkURqmGj13C6dCqckZBLdl4h7bkhHt/t0WP+zO9/zwroDvANaOqO5Sw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-arm64": ["@esbuild/android-arm64@0.18.20", "", { "os": "android", "cpu": "arm64" }, "sha512-Nz4rJcchGDtENV0eMKUNa6L12zz2zBDXuhj/Vjh18zGqB44Bi7MBMSXjgunJgjRhCmKOjnPuZp4Mb6OKqtMHLQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/android-x64": ["@esbuild/android-x64@0.18.20", "", { "os": "android", "cpu": "x64" }, "sha512-8GDdlePJA8D6zlZYJV/jnrRAi6rOiNaCC/JclcXpB+KIuvfBN4owLtgzY2bsxnx666XjJx2kDPUmnTtR8qKQUg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-arm64": ["@esbuild/darwin-arm64@0.18.20", "", { "os": "darwin", "cpu": "arm64" }, "sha512-bxRHW5kHU38zS2lPTPOyuyTm+S+eobPUnTNkdJEfAddYgEcll4xkT8DB9d2008DtTbl7uJag2HuE5NZAZgnNEA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/darwin-x64": ["@esbuild/darwin-x64@0.18.20", "", { "os": "darwin", "cpu": "x64" }, "sha512-pc5gxlMDxzm513qPGbCbDukOdsGtKhfxD1zJKXjCCcU7ju50O7MeAZ8c4krSJcOIJGFR+qx21yMMVYwiQvyTyQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-arm64": ["@esbuild/freebsd-arm64@0.18.20", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-yqDQHy4QHevpMAaxhhIwYPMv1NECwOvIpGCZkECn8w2WFHXjEwrBn3CeNIYsibZ/iZEUemj++M26W3cNR5h+Tw=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/freebsd-x64": ["@esbuild/freebsd-x64@0.18.20", "", { "os": "freebsd", "cpu": "x64" }, "sha512-tgWRPPuQsd3RmBZwarGVHZQvtzfEBOreNuxEMKFcd5DaDn2PbBxfwLcj4+aenoh7ctXcbXmOQIn8HI6mCSw5MQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm": ["@esbuild/linux-arm@0.18.20", "", { "os": "linux", "cpu": "arm" }, "sha512-/5bHkMWnq1EgKr1V+Ybz3s1hWXok7mDFUMQ4cG10AfW3wL02PSZi5kFpYKrptDsgb2WAJIvRcDm+qIvXf/apvg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.18.20", "", { "os": "linux", "cpu": "arm64" }, "sha512-2YbscF+UL7SQAVIpnWvYwM+3LskyDmPhe31pE7/aoTMFKKzIc9lLbyGUpmmb8a8AixOL61sQ/mFh3jEjHYFvdA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.18.20", "", { "os": "linux", "cpu": "ia32" }, "sha512-P4etWwq6IsReT0E1KHU40bOnzMHoH73aXp96Fs8TIT6z9Hu8G6+0SHSw9i2isWrD2nbx2qo5yUqACgdfVGx7TA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-nXW8nqBTrOpDLPgPY9uV+/1DjxoQ7DoB2N8eocyq8I9XuqJ7BiAMDMf9n1xZM9TgW0J8zrquIb/A7s3BJv7rjg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-d5NeaXZcHp8PzYy5VnXV3VSd2D328Zb+9dEq5HE6bw6+N86JVPExrA6O68OPwobntbNJ0pzCpUFZTo3w0GyetQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.18.20", "", { "os": "linux", "cpu": "ppc64" }, "sha512-WHPyeScRNcmANnLQkq6AfyXRFr5D6N2sKgkFo2FqguP44Nw2eyDlbTdZwd9GYk98DZG9QItIiTlFLHJHjxP3FA=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.18.20", "", { "os": "linux", "cpu": "none" }, "sha512-WSxo6h5ecI5XH34KC7w5veNnKkju3zBRLEQNY7mv5mtBmrP/MjNBCAlsM2u5hDBlS3NGcTQpoBvRzqBcRtpq1A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.18.20", "", { "os": "linux", "cpu": "s390x" }, "sha512-+8231GMs3mAEth6Ja1iK0a1sQ3ohfcpzpRLH8uuc5/KVDFneH6jtAJLFGafpzpMRO6DzJ6AvXKze9LfFMrIHVQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/linux-x64": ["@esbuild/linux-x64@0.18.20", "", { "os": "linux", "cpu": "x64" }, "sha512-UYqiqemphJcNsFEskc73jQ7B9jgwjWrSayxawS6UVFZGWrAAtkzjxSqnoclCXxWtfwLdzU+vTpcNYhpn43uP1w=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.18.20", "", { "os": "none", "cpu": "x64" }, "sha512-iO1c++VP6xUBUmltHZoMtCUdPlnPGdBom6IrO4gyKPFFVBKioIImVooR5I83nTew5UOYrk3gIJhbZh8X44y06A=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.18.20", "", { "os": "openbsd", "cpu": "x64" }, "sha512-e5e4YSsuQfX4cxcygw/UCPIEP6wbIL+se3sxPdCiMbFLBWu0eiZOJ7WoD+ptCLrmjZBK1Wk7I6D/I3NglUGOxg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.18.20", "", { "os": "sunos", "cpu": "x64" }, "sha512-kDbFRFp0YpTQVVrqUd5FTYmWo45zGaXe0X8E1G/LKFC0v8x0vWrhOWSLITcCn63lmZIxfOMXtCfti/RxN/0wnQ=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.18.20", "", { "os": "win32", "cpu": "arm64" }, "sha512-ddYFR6ItYgoaq4v4JmQQaAI5s7npztfV4Ag6NrhiaW0RrnOXqBkgwZLofVTlq1daVTQNhtI5oieTvkRPfZrePg=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.18.20", "", { "os": "win32", "cpu": "ia32" }, "sha512-Wv7QBi3ID/rROT08SABTS7eV4hX26sVduqDOTe1MvGMjNd3EjOz4b7zeexIR62GTIEKrfJXKL9LFxTYgkyeu7g=="],
"@esbuild-kit/core-utils/esbuild/@esbuild/win32-x64": ["@esbuild/win32-x64@0.18.20", "", { "os": "win32", "cpu": "x64" }, "sha512-kTdfRcSiDfQca/y9QIkng02avJ+NCaQvrMejlsB3RRv5sE9rRoeBPISaZpKxHELzRxZyLvNts1P27W3wV+8geQ=="],
}
}

2
api/bunfig.toml Normal file
View File

@@ -0,0 +1,2 @@
[test]
preload = ["./tests/setup.ts"]

23
api/devspace.yaml Normal file
View File

@@ -0,0 +1,23 @@
version: v2beta1
name: api
dev:
api:
imageSelector: ghcr.io/zoriya/kyoo_api
devImage: docker.io/oven/bun:latest
workingDir: /app
sync:
- path: .:/app
excludePaths:
- node_modules
startContainer: true
onUpload:
exec:
- command: bun install --frozen-lockfile
onChange:
- "./bun.lock"
command:
- bash
- -c
- "bun install && bun dev"
ports:
- port: "3567"

14
api/drizzle.config.ts Normal file
View File

@@ -0,0 +1,14 @@
import { defineConfig } from "drizzle-kit";
export default defineConfig({
out: "./drizzle",
schema: "./src/db/schema",
dialect: "postgresql",
casing: "snake_case",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
migrations: {
schema: "kyoo",
},
});

102
api/drizzle/0000_init.sql Normal file
View File

@@ -0,0 +1,102 @@
CREATE TYPE "kyoo"."entry_type" AS ENUM('unknown', 'episode', 'movie', 'special', 'extra');--> statement-breakpoint
CREATE TYPE "kyoo"."genres" AS ENUM('action', 'adventure', 'animation', 'comedy', 'crime', 'documentary', 'drama', 'family', 'fantasy', 'history', 'horror', 'music', 'mystery', 'romance', 'science-fiction', 'thriller', 'war', 'western', 'kids', 'reality', 'politics', 'soap', 'talk');--> statement-breakpoint
CREATE TYPE "kyoo"."show_kind" AS ENUM('serie', 'movie');--> statement-breakpoint
CREATE TYPE "kyoo"."show_status" AS ENUM('unknown', 'finished', 'airing', 'planned');--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "kyoo"."entries" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."entries_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"slug" varchar(255) NOT NULL,
"show_pk" integer,
"order" integer NOT NULL,
"season_number" integer,
"episode_number" integer,
"type" "kyoo"."entry_type" NOT NULL,
"air_date" date,
"runtime" integer,
"thumbnails" jsonb,
"external_id" jsonb DEFAULT '{}'::jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now(),
"next_refresh" timestamp with time zone,
CONSTRAINT "entries_id_unique" UNIQUE("id"),
CONSTRAINT "entries_slug_unique" UNIQUE("slug"),
CONSTRAINT "entries_showPk_seasonNumber_episodeNumber_unique" UNIQUE("show_pk","season_number","episode_number"),
CONSTRAINT "order_positive" CHECK ("entries"."order" >= 0)
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "kyoo"."entries_translation" (
"pk" integer NOT NULL,
"language" varchar(255) NOT NULL,
"name" text,
"description" text,
CONSTRAINT "entries_translation_pk_language_pk" PRIMARY KEY("pk","language")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "kyoo"."show_translations" (
"pk" integer NOT NULL,
"language" varchar(255) NOT NULL,
"name" text NOT NULL,
"description" text,
"tagline" text,
"aliases" text[] NOT NULL,
"tags" text[] NOT NULL,
"trailer_url" text,
"poster" jsonb,
"thumbnail" jsonb,
"banner" jsonb,
"logo" jsonb,
CONSTRAINT "show_translations_pk_language_pk" PRIMARY KEY("pk","language")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "kyoo"."shows" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."shows_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"slug" varchar(255) NOT NULL,
"kind" "kyoo"."show_kind" NOT NULL,
"genres" "kyoo"."genres"[] NOT NULL,
"rating" smallint,
"runtime" integer,
"status" "kyoo"."show_status" NOT NULL,
"start_air" date,
"end_air" date,
"original_language" varchar(255),
"external_id" jsonb DEFAULT '{}'::jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"next_refresh" timestamp with time zone NOT NULL,
CONSTRAINT "shows_id_unique" UNIQUE("id"),
CONSTRAINT "shows_slug_unique" UNIQUE("slug"),
CONSTRAINT "rating_valid" CHECK ("shows"."rating" between 0 and 100),
CONSTRAINT "runtime_valid" CHECK ("shows"."runtime" >= 0)
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "kyoo"."videos" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."videos_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"path" text NOT NULL,
"rendering" integer,
"part" integer,
"version" integer,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "videos_id_unique" UNIQUE("id"),
CONSTRAINT "videos_path_unique" UNIQUE("path"),
CONSTRAINT "rendering_pos" CHECK ("videos"."rendering" >= 0),
CONSTRAINT "part_pos" CHECK ("videos"."part" >= 0),
CONSTRAINT "version_pos" CHECK ("videos"."version" >= 0)
);
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."entries" ADD CONSTRAINT "entries_show_pk_shows_pk_fk" FOREIGN KEY ("show_pk") REFERENCES "kyoo"."shows"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."entries_translation" ADD CONSTRAINT "entries_translation_pk_entries_pk_fk" FOREIGN KEY ("pk") REFERENCES "kyoo"."entries"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."show_translations" ADD CONSTRAINT "show_translations_pk_shows_pk_fk" FOREIGN KEY ("pk") REFERENCES "kyoo"."shows"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1,7 @@
ALTER TABLE "kyoo"."videos" DROP CONSTRAINT "rendering_pos";--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ALTER COLUMN "rendering" SET DATA TYPE text;--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ALTER COLUMN "rendering" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ALTER COLUMN "version" SET DEFAULT 1;--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ALTER COLUMN "version" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ADD COLUMN "slug" varchar(255) NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ADD CONSTRAINT "videos_slug_unique" UNIQUE("slug");

View File

@@ -0,0 +1,40 @@
CREATE TABLE IF NOT EXISTS "kyoo"."season_translation" (
"pk" integer NOT NULL,
"language" varchar(255) NOT NULL,
"name" text,
"description" text,
"poster" jsonb,
"thumbnail" jsonb,
"logo" jsonb,
"banner" jsonb,
CONSTRAINT "season_translation_pk_language_pk" PRIMARY KEY("pk","language")
);
--> statement-breakpoint
CREATE TABLE IF NOT EXISTS "kyoo"."seasons" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."seasons_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"slug" varchar(255) NOT NULL,
"show_pk" integer,
"season_number" integer NOT NULL,
"start_air" date,
"end_air" date,
"external_id" jsonb DEFAULT '{}'::jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now(),
"next_refresh" timestamp with time zone,
CONSTRAINT "seasons_id_unique" UNIQUE("id"),
CONSTRAINT "seasons_slug_unique" UNIQUE("slug"),
CONSTRAINT "seasons_showPk_seasonNumber_unique" UNIQUE("show_pk","season_number")
);
--> statement-breakpoint
ALTER TABLE "kyoo"."entries" ALTER COLUMN "order" DROP NOT NULL;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."season_translation" ADD CONSTRAINT "season_translation_pk_seasons_pk_fk" FOREIGN KEY ("pk") REFERENCES "kyoo"."seasons"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."seasons" ADD CONSTRAINT "seasons_show_pk_shows_pk_fk" FOREIGN KEY ("show_pk") REFERENCES "kyoo"."shows"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;

View File

@@ -0,0 +1,3 @@
ALTER TABLE "kyoo"."entries" ALTER COLUMN "order" SET DATA TYPE real;--> statement-breakpoint
ALTER TABLE "kyoo"."entries_translation" ADD COLUMN "tagline" text;--> statement-breakpoint
ALTER TABLE "kyoo"."season_translation" DROP COLUMN IF EXISTS "logo";

View File

@@ -0,0 +1,56 @@
CREATE TABLE IF NOT EXISTS "kyoo"."entry_video_jointure" (
"entry" integer NOT NULL,
"video" integer NOT NULL,
"slug" varchar(255) NOT NULL,
CONSTRAINT "entry_video_jointure_entry_video_pk" PRIMARY KEY("entry","video"),
CONSTRAINT "entry_video_jointure_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
ALTER TABLE "kyoo"."entries_translation" RENAME TO "entry_translations";--> statement-breakpoint
ALTER TABLE "kyoo"."season_translation" RENAME TO "season_translations";--> statement-breakpoint
ALTER TABLE "kyoo"."videos" DROP CONSTRAINT "videos_slug_unique";--> statement-breakpoint
ALTER TABLE "kyoo"."entries" DROP CONSTRAINT "order_positive";--> statement-breakpoint
ALTER TABLE "kyoo"."shows" DROP CONSTRAINT "rating_valid";--> statement-breakpoint
ALTER TABLE "kyoo"."shows" DROP CONSTRAINT "runtime_valid";--> statement-breakpoint
ALTER TABLE "kyoo"."videos" DROP CONSTRAINT "part_pos";--> statement-breakpoint
ALTER TABLE "kyoo"."videos" DROP CONSTRAINT "version_pos";--> statement-breakpoint
ALTER TABLE "kyoo"."entry_translations" DROP CONSTRAINT "entries_translation_pk_entries_pk_fk";
--> statement-breakpoint
ALTER TABLE "kyoo"."season_translations" DROP CONSTRAINT "season_translation_pk_seasons_pk_fk";
--> statement-breakpoint
ALTER TABLE "kyoo"."entry_translations" DROP CONSTRAINT "entries_translation_pk_language_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."season_translations" DROP CONSTRAINT "season_translation_pk_language_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."entry_translations" ADD CONSTRAINT "entry_translations_pk_language_pk" PRIMARY KEY("pk","language");--> statement-breakpoint
ALTER TABLE "kyoo"."season_translations" ADD CONSTRAINT "season_translations_pk_language_pk" PRIMARY KEY("pk","language");--> statement-breakpoint
ALTER TABLE "kyoo"."entry_translations" ADD COLUMN "poster" jsonb;--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ADD COLUMN "guess" jsonb DEFAULT '{}'::jsonb NOT NULL;--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."entry_video_jointure" ADD CONSTRAINT "entry_video_jointure_entry_entries_pk_fk" FOREIGN KEY ("entry") REFERENCES "kyoo"."entries"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."entry_video_jointure" ADD CONSTRAINT "entry_video_jointure_video_videos_pk_fk" FOREIGN KEY ("video") REFERENCES "kyoo"."videos"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."entry_translations" ADD CONSTRAINT "entry_translations_pk_entries_pk_fk" FOREIGN KEY ("pk") REFERENCES "kyoo"."entries"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "kyoo"."season_translations" ADD CONSTRAINT "season_translations_pk_seasons_pk_fk" FOREIGN KEY ("pk") REFERENCES "kyoo"."seasons"("pk") ON DELETE cascade ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "kyoo"."videos" DROP COLUMN IF EXISTS "slug";--> statement-breakpoint
ALTER TABLE "kyoo"."entries" ADD CONSTRAINT "order_positive" CHECK ("kyoo"."entries"."order" >= 0);--> statement-breakpoint
ALTER TABLE "kyoo"."shows" ADD CONSTRAINT "rating_valid" CHECK ("kyoo"."shows"."rating" between 0 and 100);--> statement-breakpoint
ALTER TABLE "kyoo"."shows" ADD CONSTRAINT "runtime_valid" CHECK ("kyoo"."shows"."runtime" >= 0);--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ADD CONSTRAINT "part_pos" CHECK ("kyoo"."videos"."part" >= 0);--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ADD CONSTRAINT "version_pos" CHECK ("kyoo"."videos"."version" >= 0);

View File

@@ -0,0 +1,5 @@
CREATE INDEX "name_trgm" ON "kyoo"."show_translations" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
CREATE INDEX "tags" ON "kyoo"."show_translations" USING btree ("tags");--> statement-breakpoint
CREATE INDEX "kind" ON "kyoo"."shows" USING hash ("kind");--> statement-breakpoint
CREATE INDEX "rating" ON "kyoo"."shows" USING btree ("rating");--> statement-breakpoint
CREATE INDEX "startAir" ON "kyoo"."shows" USING btree ("start_air");

View File

@@ -0,0 +1,5 @@
ALTER TABLE "kyoo"."entries" ALTER COLUMN "created_at" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."entries" ALTER COLUMN "next_refresh" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."seasons" ALTER COLUMN "created_at" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."seasons" ALTER COLUMN "next_refresh" SET NOT NULL;--> statement-breakpoint
CREATE INDEX "show_fk" ON "kyoo"."seasons" USING hash ("show_pk");

View File

@@ -0,0 +1,3 @@
ALTER TABLE "kyoo"."entries" RENAME COLUMN "type" TO "kind";--> statement-breakpoint
ALTER TABLE "kyoo"."entries" ALTER COLUMN "show_pk" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."entries" ADD COLUMN "extra_kind" text;

View File

@@ -0,0 +1,12 @@
ALTER TABLE "kyoo"."entry_video_jointure" RENAME TO "entry_video_join";--> statement-breakpoint
ALTER TABLE "kyoo"."entries" RENAME COLUMN "thumbnails" TO "thumbnail";--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_jointure_slug_unique";--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_jointure_entry_entries_pk_fk";
--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_jointure_video_videos_pk_fk";
--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_jointure_entry_video_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_entry_video_pk" PRIMARY KEY("entry","video");--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_entry_entries_pk_fk" FOREIGN KEY ("entry") REFERENCES "kyoo"."entries"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_video_videos_pk_fk" FOREIGN KEY ("video") REFERENCES "kyoo"."videos"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_slug_unique" UNIQUE("slug");

View File

@@ -0,0 +1,3 @@
ALTER TYPE "kyoo"."show_kind" ADD VALUE 'collection';--> statement-breakpoint
ALTER TABLE "kyoo"."shows" ADD COLUMN "collection_pk" integer;--> statement-breakpoint
ALTER TABLE "kyoo"."shows" ADD CONSTRAINT "shows_collection_pk_shows_pk_fk" FOREIGN KEY ("collection_pk") REFERENCES "kyoo"."shows"("pk") ON DELETE set null ON UPDATE no action;

View File

@@ -0,0 +1,38 @@
CREATE TABLE "kyoo"."show_studio_join" (
"show" integer NOT NULL,
"studio" integer NOT NULL,
CONSTRAINT "show_studio_join_show_studio_pk" PRIMARY KEY("show","studio")
);
--> statement-breakpoint
CREATE TABLE "kyoo"."studio_translations" (
"pk" integer NOT NULL,
"language" varchar(255) NOT NULL,
"name" text NOT NULL,
"logo" jsonb,
CONSTRAINT "studio_translations_pk_language_pk" PRIMARY KEY("pk","language")
);
--> statement-breakpoint
CREATE TABLE "kyoo"."studios" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."studios_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"slug" varchar(255) NOT NULL,
"external_id" jsonb DEFAULT '{}'::jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone NOT NULL,
CONSTRAINT "studios_id_unique" UNIQUE("id"),
CONSTRAINT "studios_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
ALTER TABLE "kyoo"."entries" ADD COLUMN "updated_at" timestamp with time zone NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."seasons" ADD COLUMN "updated_at" timestamp with time zone NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."shows" ADD COLUMN "updated_at" timestamp with time zone NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ADD COLUMN "updated_at" timestamp with time zone NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" ADD CONSTRAINT "show_studio_join_show_shows_pk_fk" FOREIGN KEY ("show") REFERENCES "kyoo"."shows"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" ADD CONSTRAINT "show_studio_join_studio_studios_pk_fk" FOREIGN KEY ("studio") REFERENCES "kyoo"."studios"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."studio_translations" ADD CONSTRAINT "studio_translations_pk_studios_pk_fk" FOREIGN KEY ("pk") REFERENCES "kyoo"."studios"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "studio_name_trgm" ON "kyoo"."studio_translations" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
CREATE INDEX "entry_kind" ON "kyoo"."entries" USING hash ("kind");--> statement-breakpoint
CREATE INDEX "entry_order" ON "kyoo"."entries" USING btree ("order");--> statement-breakpoint
CREATE INDEX "entry_name_trgm" ON "kyoo"."entry_translations" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
CREATE INDEX "season_name_trgm" ON "kyoo"."season_translations" USING gin ("name" gin_trgm_ops);--> statement-breakpoint
CREATE INDEX "season_nbr" ON "kyoo"."seasons" USING btree ("season_number");

View File

@@ -0,0 +1,20 @@
ALTER TABLE "kyoo"."show_studio_join" RENAME COLUMN "show" TO "show_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" RENAME COLUMN "studio" TO "studio_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" RENAME COLUMN "entry" TO "entry_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" RENAME COLUMN "video" TO "video_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" DROP CONSTRAINT "show_studio_join_show_shows_pk_fk";
--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" DROP CONSTRAINT "show_studio_join_studio_studios_pk_fk";
--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_join_entry_entries_pk_fk";
--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_join_video_videos_pk_fk";
--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" DROP CONSTRAINT "show_studio_join_show_studio_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" DROP CONSTRAINT "entry_video_join_entry_video_pk";--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" ADD CONSTRAINT "show_studio_join_show_pk_studio_pk_pk" PRIMARY KEY("show_pk","studio_pk");--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_entry_pk_video_pk_pk" PRIMARY KEY("entry_pk","video_pk");--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" ADD CONSTRAINT "show_studio_join_show_pk_shows_pk_fk" FOREIGN KEY ("show_pk") REFERENCES "kyoo"."shows"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."show_studio_join" ADD CONSTRAINT "show_studio_join_studio_pk_studios_pk_fk" FOREIGN KEY ("studio_pk") REFERENCES "kyoo"."studios"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_entry_pk_entries_pk_fk" FOREIGN KEY ("entry_pk") REFERENCES "kyoo"."entries"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."entry_video_join" ADD CONSTRAINT "entry_video_join_video_pk_videos_pk_fk" FOREIGN KEY ("video_pk") REFERENCES "kyoo"."videos"("pk") ON DELETE cascade ON UPDATE no action;

View File

@@ -0,0 +1,2 @@
ALTER TABLE "kyoo"."shows" ADD COLUMN "entries_count" integer NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."shows" ADD COLUMN "available_count" integer DEFAULT 0 NOT NULL;

View File

@@ -0,0 +1,3 @@
ALTER TABLE "kyoo"."videos" ALTER COLUMN "guess" DROP DEFAULT;--> statement-breakpoint
ALTER TABLE "kyoo"."shows" ADD COLUMN "original" jsonb NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."shows" DROP COLUMN "original_language";

View File

@@ -0,0 +1,28 @@
CREATE TYPE "kyoo"."role_kind" AS ENUM('actor', 'director', 'writter', 'producer', 'music', 'other');--> statement-breakpoint
CREATE TABLE "kyoo"."roles" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."roles_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"show_pk" integer NOT NULL,
"staff_pk" integer NOT NULL,
"kind" "kyoo"."role_kind" NOT NULL,
"order" integer NOT NULL,
"character" jsonb
);
--> statement-breakpoint
CREATE TABLE "kyoo"."staff" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."staff_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"id" uuid DEFAULT gen_random_uuid() NOT NULL,
"slug" varchar(255) NOT NULL,
"name" text NOT NULL,
"latin_name" text,
"image" jsonb,
"external_id" jsonb DEFAULT '{}'::jsonb NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone NOT NULL,
CONSTRAINT "staff_id_unique" UNIQUE("id"),
CONSTRAINT "staff_slug_unique" UNIQUE("slug")
);
--> statement-breakpoint
ALTER TABLE "kyoo"."roles" ADD CONSTRAINT "roles_show_pk_shows_pk_fk" FOREIGN KEY ("show_pk") REFERENCES "kyoo"."shows"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."roles" ADD CONSTRAINT "roles_staff_pk_staff_pk_fk" FOREIGN KEY ("staff_pk") REFERENCES "kyoo"."staff"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "role_kind" ON "kyoo"."roles" USING hash ("kind");--> statement-breakpoint
CREATE INDEX "role_order" ON "kyoo"."roles" USING btree ("order");

View File

@@ -0,0 +1 @@
ALTER TABLE "kyoo"."entries" ADD COLUMN "available_since" timestamp with time zone;

View File

@@ -0,0 +1,9 @@
CREATE TABLE "kyoo"."mqueue" (
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
"kind" varchar(255) NOT NULL,
"message" jsonb NOT NULL,
"attempt" integer DEFAULT 0 NOT NULL,
"created_at" timestamp with time zone DEFAULT now() NOT NULL
);
--> statement-breakpoint
CREATE INDEX "mqueue_created" ON "kyoo"."mqueue" USING btree ("created_at");

View File

@@ -0,0 +1,40 @@
CREATE TYPE "kyoo"."watchlist_status" AS ENUM('completed', 'watching', 'rewatching', 'dropped', 'planned');--> statement-breakpoint
CREATE TABLE "kyoo"."history" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."history_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"profile_pk" integer NOT NULL,
"entry_pk" integer NOT NULL,
"video_pk" integer NOT NULL,
"percent" integer DEFAULT 0 NOT NULL,
"time" integer,
"played_date" timestamp with time zone DEFAULT now() NOT NULL,
CONSTRAINT "percent_valid" CHECK ("kyoo"."history"."percent" between 0 and 100)
);
--> statement-breakpoint
CREATE TABLE "kyoo"."profiles" (
"pk" integer PRIMARY KEY GENERATED ALWAYS AS IDENTITY (sequence name "kyoo"."profiles_pk_seq" INCREMENT BY 1 MINVALUE 1 MAXVALUE 2147483647 START WITH 1 CACHE 1),
"id" uuid NOT NULL,
CONSTRAINT "profiles_id_unique" UNIQUE("id")
);
--> statement-breakpoint
CREATE TABLE "kyoo"."watchlist" (
"profile_pk" integer NOT NULL,
"show_pk" integer NOT NULL,
"status" "kyoo"."watchlist_status" NOT NULL,
"seen_count" integer DEFAULT 0 NOT NULL,
"next_entry" integer,
"score" integer,
"started_at" timestamp with time zone,
"completed_at" timestamp with time zone,
"created_at" timestamp with time zone DEFAULT now() NOT NULL,
"updated_at" timestamp with time zone NOT NULL,
CONSTRAINT "watchlist_profile_pk_show_pk_pk" PRIMARY KEY("profile_pk","show_pk"),
CONSTRAINT "score_percent" CHECK ("kyoo"."watchlist"."score" between 0 and 100)
);
--> statement-breakpoint
ALTER TABLE "kyoo"."history" ADD CONSTRAINT "history_profile_pk_profiles_pk_fk" FOREIGN KEY ("profile_pk") REFERENCES "kyoo"."profiles"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."history" ADD CONSTRAINT "history_entry_pk_entries_pk_fk" FOREIGN KEY ("entry_pk") REFERENCES "kyoo"."entries"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."history" ADD CONSTRAINT "history_video_pk_videos_pk_fk" FOREIGN KEY ("video_pk") REFERENCES "kyoo"."videos"("pk") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."watchlist" ADD CONSTRAINT "watchlist_profile_pk_profiles_pk_fk" FOREIGN KEY ("profile_pk") REFERENCES "kyoo"."profiles"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."watchlist" ADD CONSTRAINT "watchlist_show_pk_shows_pk_fk" FOREIGN KEY ("show_pk") REFERENCES "kyoo"."shows"("pk") ON DELETE cascade ON UPDATE no action;--> statement-breakpoint
ALTER TABLE "kyoo"."watchlist" ADD CONSTRAINT "watchlist_next_entry_entries_pk_fk" FOREIGN KEY ("next_entry") REFERENCES "kyoo"."entries"("pk") ON DELETE set null ON UPDATE no action;--> statement-breakpoint
CREATE INDEX "history_play_date" ON "kyoo"."history" USING btree ("played_date" DESC NULLS LAST);

View File

@@ -0,0 +1,5 @@
ALTER TABLE "kyoo"."history" ALTER COLUMN "video_pk" DROP NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."watchlist" ALTER COLUMN "status" SET DATA TYPE text;--> statement-breakpoint
DROP TYPE "kyoo"."watchlist_status";--> statement-breakpoint
CREATE TYPE "kyoo"."watchlist_status" AS ENUM('watching', 'rewatching', 'completed', 'dropped', 'planned');--> statement-breakpoint
ALTER TABLE "kyoo"."watchlist" ALTER COLUMN "status" SET DATA TYPE "kyoo"."watchlist_status" USING "status"::"kyoo"."watchlist_status";

View File

@@ -0,0 +1 @@
ALTER TABLE "kyoo"."watchlist" ADD COLUMN "last_played_at" timestamp with time zone;

View File

@@ -0,0 +1,5 @@
ALTER TABLE "kyoo"."entries" ALTER COLUMN "kind" SET DATA TYPE text;--> statement-breakpoint
DROP TYPE "kyoo"."entry_type";--> statement-breakpoint
CREATE TYPE "kyoo"."entry_type" AS ENUM('episode', 'movie', 'special', 'extra');--> statement-breakpoint
ALTER TABLE "kyoo"."entries" ALTER COLUMN "kind" SET DATA TYPE "kyoo"."entry_type" USING "kind"::"kyoo"."entry_type";--> statement-breakpoint
ALTER TABLE "kyoo"."videos" ADD CONSTRAINT "rendering_unique" UNIQUE NULLS NOT DISTINCT("rendering","part","version");

View File

@@ -0,0 +1 @@
ALTER TYPE "kyoo"."role_kind" ADD VALUE 'crew' BEFORE 'other';

View File

@@ -0,0 +1,2 @@
ALTER TABLE "kyoo"."seasons" ADD COLUMN "entries_count" integer NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."seasons" ADD COLUMN "available_count" integer DEFAULT 0 NOT NULL;

View File

@@ -0,0 +1,3 @@
ALTER TABLE "kyoo"."history" ALTER COLUMN "time" SET DEFAULT 0;--> statement-breakpoint
ALTER TABLE "kyoo"."history" ALTER COLUMN "time" SET NOT NULL;--> statement-breakpoint
ALTER TABLE "kyoo"."mqueue" ADD COLUMN "priority" integer DEFAULT 0 NOT NULL;

View File

@@ -0,0 +1 @@
ALTER TABLE "kyoo"."seasons" ALTER COLUMN "entries_count" SET DEFAULT 0;

View File

@@ -0,0 +1,589 @@
{
"id": "82560792-5f4a-4723-9543-808719ade682",
"prevId": "00000000-0000-0000-0000-000000000000",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnails": {
"name": "thumbnails",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entries_translation": {
"name": "entries_translation",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_translation_pk_entries_pk_fk": {
"name": "entries_translation_pk_entries_pk_fk",
"tableFrom": "entries_translation",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entries_translation_pk_language_pk": {
"name": "entries_translation_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"rendering_pos": {
"name": "rendering_pos",
"value": "\"videos\".\"rendering\" >= 0"
},
"part_pos": {
"name": "part_pos",
"value": "\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,597 @@
{
"id": "32090852-33a7-430a-9df1-97608c063124",
"prevId": "82560792-5f4a-4723-9543-808719ade682",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnails": {
"name": "thumbnails",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entries_translation": {
"name": "entries_translation",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_translation_pk_entries_pk_fk": {
"name": "entries_translation_pk_entries_pk_fk",
"tableFrom": "entries_translation",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entries_translation_pk_language_pk": {
"name": "entries_translation_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_slug_unique": {
"name": "videos_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,788 @@
{
"id": "d0f6c500-aa2b-4592-aa31-db646817f708",
"prevId": "32090852-33a7-430a-9df1-97608c063124",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"order": {
"name": "order",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnails": {
"name": "thumbnails",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entries_translation": {
"name": "entries_translation",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_translation_pk_entries_pk_fk": {
"name": "entries_translation_pk_entries_pk_fk",
"tableFrom": "entries_translation",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entries_translation_pk_language_pk": {
"name": "entries_translation_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.season_translation": {
"name": "season_translation",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"season_translation_pk_seasons_pk_fk": {
"name": "season_translation_pk_seasons_pk_fk",
"tableFrom": "season_translation",
"tableTo": "seasons",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"season_translation_pk_language_pk": {
"name": "season_translation_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.seasons": {
"name": "seasons",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "seasons_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"seasons_show_pk_shows_pk_fk": {
"name": "seasons_show_pk_shows_pk_fk",
"tableFrom": "seasons",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_id_unique": {
"name": "seasons_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"seasons_slug_unique": {
"name": "seasons_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"seasons_showPk_seasonNumber_unique": {
"name": "seasons_showPk_seasonNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_slug_unique": {
"name": "videos_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,788 @@
{
"id": "2210fd60-8e6a-4503-a2b3-56cc7f3cf15a",
"prevId": "d0f6c500-aa2b-4592-aa31-db646817f708",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"order": {
"name": "order",
"type": "real",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnails": {
"name": "thumbnails",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entries_translation": {
"name": "entries_translation",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_translation_pk_entries_pk_fk": {
"name": "entries_translation_pk_entries_pk_fk",
"tableFrom": "entries_translation",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entries_translation_pk_language_pk": {
"name": "entries_translation_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.season_translation": {
"name": "season_translation",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"season_translation_pk_seasons_pk_fk": {
"name": "season_translation_pk_seasons_pk_fk",
"tableFrom": "season_translation",
"tableTo": "seasons",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"season_translation_pk_language_pk": {
"name": "season_translation_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.seasons": {
"name": "seasons",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "seasons_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"seasons_show_pk_shows_pk_fk": {
"name": "seasons_show_pk_shows_pk_fk",
"tableFrom": "seasons",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_id_unique": {
"name": "seasons_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"seasons_slug_unique": {
"name": "seasons_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"seasons_showPk_seasonNumber_unique": {
"name": "seasons_showPk_seasonNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_slug_unique": {
"name": "videos_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,853 @@
{
"id": "0d5d6d22-dc13-4f3d-9975-cb7b38f628d4",
"prevId": "2210fd60-8e6a-4503-a2b3-56cc7f3cf15a",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"order": {
"name": "order",
"type": "real",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnails": {
"name": "thumbnails",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"kyoo\".\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_translations": {
"name": "entry_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entry_translations_pk_entries_pk_fk": {
"name": "entry_translations_pk_entries_pk_fk",
"tableFrom": "entry_translations",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_translations_pk_language_pk": {
"name": "entry_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.season_translations": {
"name": "season_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"season_translations_pk_seasons_pk_fk": {
"name": "season_translations_pk_seasons_pk_fk",
"tableFrom": "season_translations",
"tableTo": "seasons",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"season_translations_pk_language_pk": {
"name": "season_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.seasons": {
"name": "seasons",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "seasons_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"seasons_show_pk_shows_pk_fk": {
"name": "seasons_show_pk_shows_pk_fk",
"tableFrom": "seasons",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_id_unique": {
"name": "seasons_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"seasons_slug_unique": {
"name": "seasons_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"seasons_showPk_seasonNumber_unique": {
"name": "seasons_showPk_seasonNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"kyoo\".\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"kyoo\".\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_video_jointure": {
"name": "entry_video_jointure",
"schema": "kyoo",
"columns": {
"entry": {
"name": "entry",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"video": {
"name": "video",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entry_video_jointure_entry_entries_pk_fk": {
"name": "entry_video_jointure_entry_entries_pk_fk",
"tableFrom": "entry_video_jointure",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["entry"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"entry_video_jointure_video_videos_pk_fk": {
"name": "entry_video_jointure_video_videos_pk_fk",
"tableFrom": "entry_video_jointure",
"tableTo": "videos",
"schemaTo": "kyoo",
"columnsFrom": ["video"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_video_jointure_entry_video_pk": {
"name": "entry_video_jointure_entry_video_pk",
"columns": ["entry", "video"]
}
},
"uniqueConstraints": {
"entry_video_jointure_slug_unique": {
"name": "entry_video_jointure_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"guess": {
"name": "guess",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"kyoo\".\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"kyoo\".\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,930 @@
{
"id": "1d98727c-290d-4491-8bb8-74390da0c021",
"prevId": "0d5d6d22-dc13-4f3d-9975-cb7b38f628d4",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"order": {
"name": "order",
"type": "real",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnails": {
"name": "thumbnails",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"kyoo\".\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_translations": {
"name": "entry_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entry_translations_pk_entries_pk_fk": {
"name": "entry_translations_pk_entries_pk_fk",
"tableFrom": "entry_translations",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_translations_pk_language_pk": {
"name": "entry_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.season_translations": {
"name": "season_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"season_translations_pk_seasons_pk_fk": {
"name": "season_translations_pk_seasons_pk_fk",
"tableFrom": "season_translations",
"tableTo": "seasons",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"season_translations_pk_language_pk": {
"name": "season_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.seasons": {
"name": "seasons",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "seasons_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"seasons_show_pk_shows_pk_fk": {
"name": "seasons_show_pk_shows_pk_fk",
"tableFrom": "seasons",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_id_unique": {
"name": "seasons_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"seasons_slug_unique": {
"name": "seasons_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"seasons_showPk_seasonNumber_unique": {
"name": "seasons_showPk_seasonNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"name_trgm": {
"name": "name_trgm",
"columns": [
{
"expression": "\"name\" gin_trgm_ops",
"asc": true,
"isExpression": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "gin",
"with": {}
},
"tags": {
"name": "tags",
"columns": [
{
"expression": "tags",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"kind": {
"name": "kind",
"columns": [
{
"expression": "kind",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
},
"rating": {
"name": "rating",
"columns": [
{
"expression": "rating",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"startAir": {
"name": "startAir",
"columns": [
{
"expression": "start_air",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"kyoo\".\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"kyoo\".\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_video_jointure": {
"name": "entry_video_jointure",
"schema": "kyoo",
"columns": {
"entry": {
"name": "entry",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"video": {
"name": "video",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entry_video_jointure_entry_entries_pk_fk": {
"name": "entry_video_jointure_entry_entries_pk_fk",
"tableFrom": "entry_video_jointure",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["entry"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"entry_video_jointure_video_videos_pk_fk": {
"name": "entry_video_jointure_video_videos_pk_fk",
"tableFrom": "entry_video_jointure",
"tableTo": "videos",
"schemaTo": "kyoo",
"columnsFrom": ["video"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_video_jointure_entry_video_pk": {
"name": "entry_video_jointure_entry_video_pk",
"columns": ["entry", "video"]
}
},
"uniqueConstraints": {
"entry_video_jointure_slug_unique": {
"name": "entry_video_jointure_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"guess": {
"name": "guess",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"kyoo\".\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"kyoo\".\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,946 @@
{
"id": "ca86d88f-b380-4b41-9c3d-d8acef369e4c",
"prevId": "1d98727c-290d-4491-8bb8-74390da0c021",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"order": {
"name": "order",
"type": "real",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"type": {
"name": "type",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnails": {
"name": "thumbnails",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"kyoo\".\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_translations": {
"name": "entry_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entry_translations_pk_entries_pk_fk": {
"name": "entry_translations_pk_entries_pk_fk",
"tableFrom": "entry_translations",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_translations_pk_language_pk": {
"name": "entry_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.season_translations": {
"name": "season_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"season_translations_pk_seasons_pk_fk": {
"name": "season_translations_pk_seasons_pk_fk",
"tableFrom": "season_translations",
"tableTo": "seasons",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"season_translations_pk_language_pk": {
"name": "season_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.seasons": {
"name": "seasons",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "seasons_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"show_fk": {
"name": "show_fk",
"columns": [
{
"expression": "show_pk",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
}
},
"foreignKeys": {
"seasons_show_pk_shows_pk_fk": {
"name": "seasons_show_pk_shows_pk_fk",
"tableFrom": "seasons",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_id_unique": {
"name": "seasons_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"seasons_slug_unique": {
"name": "seasons_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"seasons_showPk_seasonNumber_unique": {
"name": "seasons_showPk_seasonNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"name_trgm": {
"name": "name_trgm",
"columns": [
{
"expression": "\"name\" gin_trgm_ops",
"asc": true,
"isExpression": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "gin",
"with": {}
},
"tags": {
"name": "tags",
"columns": [
{
"expression": "tags",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"kind": {
"name": "kind",
"columns": [
{
"expression": "kind",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
},
"rating": {
"name": "rating",
"columns": [
{
"expression": "rating",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"startAir": {
"name": "startAir",
"columns": [
{
"expression": "start_air",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"kyoo\".\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"kyoo\".\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_video_jointure": {
"name": "entry_video_jointure",
"schema": "kyoo",
"columns": {
"entry": {
"name": "entry",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"video": {
"name": "video",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entry_video_jointure_entry_entries_pk_fk": {
"name": "entry_video_jointure_entry_entries_pk_fk",
"tableFrom": "entry_video_jointure",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["entry"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"entry_video_jointure_video_videos_pk_fk": {
"name": "entry_video_jointure_video_videos_pk_fk",
"tableFrom": "entry_video_jointure",
"tableTo": "videos",
"schemaTo": "kyoo",
"columnsFrom": ["video"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_video_jointure_entry_video_pk": {
"name": "entry_video_jointure_entry_video_pk",
"columns": ["entry", "video"]
}
},
"uniqueConstraints": {
"entry_video_jointure_slug_unique": {
"name": "entry_video_jointure_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"guess": {
"name": "guess",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"kyoo\".\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"kyoo\".\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,952 @@
{
"id": "e70b1585-a927-4436-b2a0-d0ef216911f1",
"prevId": "ca86d88f-b380-4b41-9c3d-d8acef369e4c",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"order": {
"name": "order",
"type": "real",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"kind": {
"name": "kind",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"extra_kind": {
"name": "extra_kind",
"type": "text",
"primaryKey": false,
"notNull": false
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnails": {
"name": "thumbnails",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"kyoo\".\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_translations": {
"name": "entry_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entry_translations_pk_entries_pk_fk": {
"name": "entry_translations_pk_entries_pk_fk",
"tableFrom": "entry_translations",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_translations_pk_language_pk": {
"name": "entry_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.season_translations": {
"name": "season_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"season_translations_pk_seasons_pk_fk": {
"name": "season_translations_pk_seasons_pk_fk",
"tableFrom": "season_translations",
"tableTo": "seasons",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"season_translations_pk_language_pk": {
"name": "season_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.seasons": {
"name": "seasons",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "seasons_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"show_fk": {
"name": "show_fk",
"columns": [
{
"expression": "show_pk",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
}
},
"foreignKeys": {
"seasons_show_pk_shows_pk_fk": {
"name": "seasons_show_pk_shows_pk_fk",
"tableFrom": "seasons",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_id_unique": {
"name": "seasons_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"seasons_slug_unique": {
"name": "seasons_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"seasons_showPk_seasonNumber_unique": {
"name": "seasons_showPk_seasonNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"name_trgm": {
"name": "name_trgm",
"columns": [
{
"expression": "\"name\" gin_trgm_ops",
"asc": true,
"isExpression": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "gin",
"with": {}
},
"tags": {
"name": "tags",
"columns": [
{
"expression": "tags",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"kind": {
"name": "kind",
"columns": [
{
"expression": "kind",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
},
"rating": {
"name": "rating",
"columns": [
{
"expression": "rating",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"startAir": {
"name": "startAir",
"columns": [
{
"expression": "start_air",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"kyoo\".\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"kyoo\".\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_video_jointure": {
"name": "entry_video_jointure",
"schema": "kyoo",
"columns": {
"entry": {
"name": "entry",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"video": {
"name": "video",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entry_video_jointure_entry_entries_pk_fk": {
"name": "entry_video_jointure_entry_entries_pk_fk",
"tableFrom": "entry_video_jointure",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["entry"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"entry_video_jointure_video_videos_pk_fk": {
"name": "entry_video_jointure_video_videos_pk_fk",
"tableFrom": "entry_video_jointure",
"tableTo": "videos",
"schemaTo": "kyoo",
"columnsFrom": ["video"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_video_jointure_entry_video_pk": {
"name": "entry_video_jointure_entry_video_pk",
"columns": ["entry", "video"]
}
},
"uniqueConstraints": {
"entry_video_jointure_slug_unique": {
"name": "entry_video_jointure_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"guess": {
"name": "guess",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"kyoo\".\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"kyoo\".\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,952 @@
{
"id": "5c17dd71-409a-4c80-870d-f12386676738",
"prevId": "e70b1585-a927-4436-b2a0-d0ef216911f1",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"order": {
"name": "order",
"type": "real",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"kind": {
"name": "kind",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"extra_kind": {
"name": "extra_kind",
"type": "text",
"primaryKey": false,
"notNull": false
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"kyoo\".\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_translations": {
"name": "entry_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entry_translations_pk_entries_pk_fk": {
"name": "entry_translations_pk_entries_pk_fk",
"tableFrom": "entry_translations",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_translations_pk_language_pk": {
"name": "entry_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.season_translations": {
"name": "season_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"season_translations_pk_seasons_pk_fk": {
"name": "season_translations_pk_seasons_pk_fk",
"tableFrom": "season_translations",
"tableTo": "seasons",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"season_translations_pk_language_pk": {
"name": "season_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.seasons": {
"name": "seasons",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "seasons_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"show_fk": {
"name": "show_fk",
"columns": [
{
"expression": "show_pk",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
}
},
"foreignKeys": {
"seasons_show_pk_shows_pk_fk": {
"name": "seasons_show_pk_shows_pk_fk",
"tableFrom": "seasons",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_id_unique": {
"name": "seasons_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"seasons_slug_unique": {
"name": "seasons_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"seasons_showPk_seasonNumber_unique": {
"name": "seasons_showPk_seasonNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"name_trgm": {
"name": "name_trgm",
"columns": [
{
"expression": "\"name\" gin_trgm_ops",
"asc": true,
"isExpression": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "gin",
"with": {}
},
"tags": {
"name": "tags",
"columns": [
{
"expression": "tags",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"kind": {
"name": "kind",
"columns": [
{
"expression": "kind",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
},
"rating": {
"name": "rating",
"columns": [
{
"expression": "rating",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"startAir": {
"name": "startAir",
"columns": [
{
"expression": "start_air",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"kyoo\".\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"kyoo\".\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_video_join": {
"name": "entry_video_join",
"schema": "kyoo",
"columns": {
"entry": {
"name": "entry",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"video": {
"name": "video",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entry_video_join_entry_entries_pk_fk": {
"name": "entry_video_join_entry_entries_pk_fk",
"tableFrom": "entry_video_join",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["entry"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"entry_video_join_video_videos_pk_fk": {
"name": "entry_video_join_video_videos_pk_fk",
"tableFrom": "entry_video_join",
"tableTo": "videos",
"schemaTo": "kyoo",
"columnsFrom": ["video"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_video_join_entry_video_pk": {
"name": "entry_video_join_entry_video_pk",
"columns": ["entry", "video"]
}
},
"uniqueConstraints": {
"entry_video_join_slug_unique": {
"name": "entry_video_join_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"guess": {
"name": "guess",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"kyoo\".\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"kyoo\".\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

View File

@@ -0,0 +1,969 @@
{
"id": "7a04670c-5fb9-4535-b6be-dc291b8b0b09",
"prevId": "5c17dd71-409a-4c80-870d-f12386676738",
"version": "7",
"dialect": "postgresql",
"tables": {
"kyoo.entries": {
"name": "entries",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "entries_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"order": {
"name": "order",
"type": "real",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"episode_number": {
"name": "episode_number",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"kind": {
"name": "kind",
"type": "entry_type",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"extra_kind": {
"name": "extra_kind",
"type": "text",
"primaryKey": false,
"notNull": false
},
"air_date": {
"name": "air_date",
"type": "date",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entries_show_pk_shows_pk_fk": {
"name": "entries_show_pk_shows_pk_fk",
"tableFrom": "entries",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"entries_id_unique": {
"name": "entries_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"entries_slug_unique": {
"name": "entries_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"entries_showPk_seasonNumber_episodeNumber_unique": {
"name": "entries_showPk_seasonNumber_episodeNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number", "episode_number"]
}
},
"policies": {},
"checkConstraints": {
"order_positive": {
"name": "order_positive",
"value": "\"kyoo\".\"entries\".\"order\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_translations": {
"name": "entry_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"entry_translations_pk_entries_pk_fk": {
"name": "entry_translations_pk_entries_pk_fk",
"tableFrom": "entry_translations",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_translations_pk_language_pk": {
"name": "entry_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.season_translations": {
"name": "season_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": false
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
}
},
"indexes": {},
"foreignKeys": {
"season_translations_pk_seasons_pk_fk": {
"name": "season_translations_pk_seasons_pk_fk",
"tableFrom": "season_translations",
"tableTo": "seasons",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"season_translations_pk_language_pk": {
"name": "season_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.seasons": {
"name": "seasons",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "seasons_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"show_pk": {
"name": "show_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"season_number": {
"name": "season_number",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"show_fk": {
"name": "show_fk",
"columns": [
{
"expression": "show_pk",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
}
},
"foreignKeys": {
"seasons_show_pk_shows_pk_fk": {
"name": "seasons_show_pk_shows_pk_fk",
"tableFrom": "seasons",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["show_pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"seasons_id_unique": {
"name": "seasons_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"seasons_slug_unique": {
"name": "seasons_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
},
"seasons_showPk_seasonNumber_unique": {
"name": "seasons_showPk_seasonNumber_unique",
"nullsNotDistinct": false,
"columns": ["show_pk", "season_number"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.show_translations": {
"name": "show_translations",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"language": {
"name": "language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"name": {
"name": "name",
"type": "text",
"primaryKey": false,
"notNull": true
},
"description": {
"name": "description",
"type": "text",
"primaryKey": false,
"notNull": false
},
"tagline": {
"name": "tagline",
"type": "text",
"primaryKey": false,
"notNull": false
},
"aliases": {
"name": "aliases",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"tags": {
"name": "tags",
"type": "text[]",
"primaryKey": false,
"notNull": true
},
"poster": {
"name": "poster",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"thumbnail": {
"name": "thumbnail",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"banner": {
"name": "banner",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"logo": {
"name": "logo",
"type": "jsonb",
"primaryKey": false,
"notNull": false
},
"trailer_url": {
"name": "trailer_url",
"type": "text",
"primaryKey": false,
"notNull": false
}
},
"indexes": {
"name_trgm": {
"name": "name_trgm",
"columns": [
{
"expression": "\"name\" gin_trgm_ops",
"asc": true,
"isExpression": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "gin",
"with": {}
},
"tags": {
"name": "tags",
"columns": [
{
"expression": "tags",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"show_translations_pk_shows_pk_fk": {
"name": "show_translations_pk_shows_pk_fk",
"tableFrom": "show_translations",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["pk"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"show_translations_pk_language_pk": {
"name": "show_translations_pk_language_pk",
"columns": ["pk", "language"]
}
},
"uniqueConstraints": {},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.shows": {
"name": "shows",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "shows_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
},
"kind": {
"name": "kind",
"type": "show_kind",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"genres": {
"name": "genres",
"type": "genres[]",
"primaryKey": false,
"notNull": true
},
"rating": {
"name": "rating",
"type": "smallint",
"primaryKey": false,
"notNull": false
},
"runtime": {
"name": "runtime",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"status": {
"name": "status",
"type": "show_status",
"typeSchema": "kyoo",
"primaryKey": false,
"notNull": true
},
"start_air": {
"name": "start_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"end_air": {
"name": "end_air",
"type": "date",
"primaryKey": false,
"notNull": false
},
"original_language": {
"name": "original_language",
"type": "varchar(255)",
"primaryKey": false,
"notNull": false
},
"collection_pk": {
"name": "collection_pk",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"external_id": {
"name": "external_id",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
},
"next_refresh": {
"name": "next_refresh",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true
}
},
"indexes": {
"kind": {
"name": "kind",
"columns": [
{
"expression": "kind",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "hash",
"with": {}
},
"rating": {
"name": "rating",
"columns": [
{
"expression": "rating",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
},
"startAir": {
"name": "startAir",
"columns": [
{
"expression": "start_air",
"isExpression": false,
"asc": true,
"nulls": "last"
}
],
"isUnique": false,
"concurrently": false,
"method": "btree",
"with": {}
}
},
"foreignKeys": {
"shows_collection_pk_shows_pk_fk": {
"name": "shows_collection_pk_shows_pk_fk",
"tableFrom": "shows",
"tableTo": "shows",
"schemaTo": "kyoo",
"columnsFrom": ["collection_pk"],
"columnsTo": ["pk"],
"onDelete": "set null",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"shows_id_unique": {
"name": "shows_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"shows_slug_unique": {
"name": "shows_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {
"rating_valid": {
"name": "rating_valid",
"value": "\"kyoo\".\"shows\".\"rating\" between 0 and 100"
},
"runtime_valid": {
"name": "runtime_valid",
"value": "\"kyoo\".\"shows\".\"runtime\" >= 0"
}
},
"isRLSEnabled": false
},
"kyoo.entry_video_join": {
"name": "entry_video_join",
"schema": "kyoo",
"columns": {
"entry": {
"name": "entry",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"video": {
"name": "video",
"type": "integer",
"primaryKey": false,
"notNull": true
},
"slug": {
"name": "slug",
"type": "varchar(255)",
"primaryKey": false,
"notNull": true
}
},
"indexes": {},
"foreignKeys": {
"entry_video_join_entry_entries_pk_fk": {
"name": "entry_video_join_entry_entries_pk_fk",
"tableFrom": "entry_video_join",
"tableTo": "entries",
"schemaTo": "kyoo",
"columnsFrom": ["entry"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
},
"entry_video_join_video_videos_pk_fk": {
"name": "entry_video_join_video_videos_pk_fk",
"tableFrom": "entry_video_join",
"tableTo": "videos",
"schemaTo": "kyoo",
"columnsFrom": ["video"],
"columnsTo": ["pk"],
"onDelete": "cascade",
"onUpdate": "no action"
}
},
"compositePrimaryKeys": {
"entry_video_join_entry_video_pk": {
"name": "entry_video_join_entry_video_pk",
"columns": ["entry", "video"]
}
},
"uniqueConstraints": {
"entry_video_join_slug_unique": {
"name": "entry_video_join_slug_unique",
"nullsNotDistinct": false,
"columns": ["slug"]
}
},
"policies": {},
"checkConstraints": {},
"isRLSEnabled": false
},
"kyoo.videos": {
"name": "videos",
"schema": "kyoo",
"columns": {
"pk": {
"name": "pk",
"type": "integer",
"primaryKey": true,
"notNull": true,
"identity": {
"type": "always",
"name": "videos_pk_seq",
"schema": "kyoo",
"increment": "1",
"startWith": "1",
"minValue": "1",
"maxValue": "2147483647",
"cache": "1",
"cycle": false
}
},
"id": {
"name": "id",
"type": "uuid",
"primaryKey": false,
"notNull": true,
"default": "gen_random_uuid()"
},
"path": {
"name": "path",
"type": "text",
"primaryKey": false,
"notNull": true
},
"rendering": {
"name": "rendering",
"type": "text",
"primaryKey": false,
"notNull": true
},
"part": {
"name": "part",
"type": "integer",
"primaryKey": false,
"notNull": false
},
"version": {
"name": "version",
"type": "integer",
"primaryKey": false,
"notNull": true,
"default": 1
},
"guess": {
"name": "guess",
"type": "jsonb",
"primaryKey": false,
"notNull": true,
"default": "'{}'::jsonb"
},
"created_at": {
"name": "created_at",
"type": "timestamp with time zone",
"primaryKey": false,
"notNull": true,
"default": "now()"
}
},
"indexes": {},
"foreignKeys": {},
"compositePrimaryKeys": {},
"uniqueConstraints": {
"videos_id_unique": {
"name": "videos_id_unique",
"nullsNotDistinct": false,
"columns": ["id"]
},
"videos_path_unique": {
"name": "videos_path_unique",
"nullsNotDistinct": false,
"columns": ["path"]
}
},
"policies": {},
"checkConstraints": {
"part_pos": {
"name": "part_pos",
"value": "\"kyoo\".\"videos\".\"part\" >= 0"
},
"version_pos": {
"name": "version_pos",
"value": "\"kyoo\".\"videos\".\"version\" >= 0"
}
},
"isRLSEnabled": false
}
},
"enums": {
"kyoo.entry_type": {
"name": "entry_type",
"schema": "kyoo",
"values": ["unknown", "episode", "movie", "special", "extra"]
},
"kyoo.genres": {
"name": "genres",
"schema": "kyoo",
"values": [
"action",
"adventure",
"animation",
"comedy",
"crime",
"documentary",
"drama",
"family",
"fantasy",
"history",
"horror",
"music",
"mystery",
"romance",
"science-fiction",
"thriller",
"war",
"western",
"kids",
"reality",
"politics",
"soap",
"talk"
]
},
"kyoo.show_kind": {
"name": "show_kind",
"schema": "kyoo",
"values": ["serie", "movie", "collection"]
},
"kyoo.show_status": {
"name": "show_status",
"schema": "kyoo",
"values": ["unknown", "finished", "airing", "planned"]
}
},
"schemas": {
"kyoo": "kyoo"
},
"sequences": {},
"roles": {},
"policies": {},
"views": {},
"_meta": {
"columns": {},
"schemas": {},
"tables": {}
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,181 @@
{
"version": "7",
"dialect": "postgresql",
"entries": [
{
"idx": 0,
"version": "7",
"when": 1731105746157,
"tag": "0000_init",
"breakpoints": true
},
{
"idx": 1,
"version": "7",
"when": 1731149082556,
"tag": "0001_video",
"breakpoints": true
},
{
"idx": 2,
"version": "7",
"when": 1731165599920,
"tag": "0002_seasons",
"breakpoints": true
},
{
"idx": 3,
"version": "7",
"when": 1731258712255,
"tag": "0003_order",
"breakpoints": true
},
{
"idx": 4,
"version": "7",
"when": 1732738409330,
"tag": "0004_jointures",
"breakpoints": true
},
{
"idx": 5,
"version": "7",
"when": 1737742695309,
"tag": "0005_trigram",
"breakpoints": true
},
{
"idx": 6,
"version": "7",
"when": 1737763164759,
"tag": "0006_seasons",
"breakpoints": true
},
{
"idx": 7,
"version": "7",
"when": 1737913931275,
"tag": "0007_entries",
"breakpoints": true
},
{
"idx": 8,
"version": "7",
"when": 1738064522937,
"tag": "0008_entries",
"breakpoints": true
},
{
"idx": 9,
"version": "7",
"when": 1740872363604,
"tag": "0009_collections",
"breakpoints": true
},
{
"idx": 10,
"version": "7",
"when": 1740950531468,
"tag": "0010_studios",
"breakpoints": true
},
{
"idx": 11,
"version": "7",
"when": 1741014917375,
"tag": "0011_join_rename",
"breakpoints": true
},
{
"idx": 12,
"version": "7",
"when": 1741360992371,
"tag": "0012_available_count",
"breakpoints": true
},
{
"idx": 13,
"version": "7",
"when": 1741444868735,
"tag": "0013_original",
"breakpoints": true
},
{
"idx": 14,
"version": "7",
"when": 1741601145901,
"tag": "0014_staff",
"breakpoints": true
},
{
"idx": 15,
"version": "7",
"when": 1741623934941,
"tag": "0015_news",
"breakpoints": true
},
{
"idx": 16,
"version": "7",
"when": 1742205790510,
"tag": "0016_mqueue",
"breakpoints": true
},
{
"idx": 17,
"version": "7",
"when": 1743944773824,
"tag": "0017_watchlist",
"breakpoints": true
},
{
"idx": 18,
"version": "7",
"when": 1744053556621,
"tag": "0018_history",
"breakpoints": true
},
{
"idx": 19,
"version": "7",
"when": 1744120518941,
"tag": "0019_nextup",
"breakpoints": true
},
{
"idx": 20,
"version": "7",
"when": 1746198322219,
"tag": "0020_video_unique",
"breakpoints": true
},
{
"idx": 21,
"version": "7",
"when": 1747727831649,
"tag": "0021_crew",
"breakpoints": true
},
{
"idx": 22,
"version": "7",
"when": 1752446736231,
"tag": "0022_seasons-count",
"breakpoints": true
},
{
"idx": 23,
"version": "7",
"when": 1763924097229,
"tag": "0023_mqueue-priority",
"breakpoints": true
},
{
"idx": 24,
"version": "7",
"when": 1763932730557,
"tag": "0024_fix-season-count",
"breakpoints": true
}
]
}

34
api/package.json Normal file
View File

@@ -0,0 +1,34 @@
{
"name": "api",
"version": "5.0.0",
"scripts": {
"dev": "bun --watch src/index.ts",
"build": "bun build src/index.ts --target bun --outdir ./dist",
"start": "NODE_ENV=production bun dist/index.js",
"test": "bun test",
"format": "biome check --write ."
},
"dependencies": {
"@elysiajs/opentelemetry": "^1.4.8",
"@elysiajs/swagger": "zoriya/elysia-swagger#build",
"@kubiks/otel-drizzle": "zoriya/drizzle-otel#build",
"@types/bun": "^1.3.1",
"blurhash": "^2.0.5",
"drizzle-kit": "^0.31.5",
"drizzle-orm": "0.44.7",
"elysia": "^1.4.13",
"jose": "^6.1.0",
"node-addon-api": "^8.5.0",
"parjs": "^1.3.9",
"pg": "^8.16.3",
"sharp": "^0.34.4"
},
"devDependencies": {
"@biomejs/biome": "2.3.7",
"@types/pg": "^8.15.5"
},
"module": "src/index.js",
"patchedDependencies": {
"drizzle-orm@0.44.7": "patches/drizzle-orm@0.44.7.patch"
}
}

View File

@@ -0,0 +1,72 @@
diff --git a/pg-core/dialect.cjs b/pg-core/dialect.cjs
index d776a1fb503f35b5e53c6d3c1c086efa8230ea94..86541bf408e4955029c65be59d7b8ec98bb6e914 100644
--- a/pg-core/dialect.cjs
+++ b/pg-core/dialect.cjs
@@ -347,7 +347,14 @@ class PgDialect {
buildInsertQuery({ table, values: valuesOrSelect, onConflict, returning, withList, select, overridingSystemValue_ }) {
const valuesSqlList = [];
const columns = table[import_table2.Table.Symbol.Columns];
- const colEntries = Object.entries(columns).filter(([_, col]) => !col.shouldDisableInsert());
+ let colEntries = Object.entries(columns);
+ colEntries = select && !is(valuesOrSelect, SQL)
+ ? Object
+ .keys(valuesOrSelect._.selectedFields)
+ .map((key) => [key, columns[key]])
+ : overridingSystemValue_
+ ? colEntries
+ : colEntries.filter(([_, col]) => !col.shouldDisableInsert());
const insertOrder = colEntries.map(
([, column]) => import_sql2.sql.identifier(this.casing.getColumnCasing(column))
);
diff --git a/pg-core/dialect.js b/pg-core/dialect.js
index 74a16c9e86fe3a89ced32af44af0a72f1cf43cf6..08f820d46a040c315fed40b8b36d94d094174425 100644
--- a/pg-core/dialect.js
+++ b/pg-core/dialect.js
@@ -345,7 +345,14 @@ class PgDialect {
buildInsertQuery({ table, values: valuesOrSelect, onConflict, returning, withList, select, overridingSystemValue_ }) {
const valuesSqlList = [];
const columns = table[Table.Symbol.Columns];
- const colEntries = Object.entries(columns).filter(([_, col]) => !col.shouldDisableInsert());
+ let colEntries = Object.entries(columns);
+ colEntries = select && !is(valuesOrSelect, SQL)
+ ? Object
+ .keys(valuesOrSelect._.selectedFields)
+ .map((key) => [key, columns[key]])
+ : overridingSystemValue_
+ ? colEntries
+ : colEntries.filter(([_, col]) => !col.shouldDisableInsert());
const insertOrder = colEntries.map(
([, column]) => sql.identifier(this.casing.getColumnCasing(column))
);
diff --git a/pg-core/query-builders/insert.cjs b/pg-core/query-builders/insert.cjs
index 22e0a4b4ad7ac64b065fc540416c6ed15ff4336b..fd590a6a3feb48c9f1894a0619b09ca6a5d22a5c 100644
--- a/pg-core/query-builders/insert.cjs
+++ b/pg-core/query-builders/insert.cjs
@@ -76,11 +76,6 @@ class PgInsertBuilder {
}
select(selectQuery) {
const select = typeof selectQuery === "function" ? selectQuery(new import_query_builder.QueryBuilder()) : selectQuery;
- if (!(0, import_entity.is)(select, import_sql.SQL) && !(0, import_utils.haveSameKeys)(this.table[import_table.Columns], select._.selectedFields)) {
- throw new Error(
- "Insert select error: selected fields are not the same or are in a different order compared to the table definition"
- );
- }
return new PgInsertBase(this.table, select, this.session, this.dialect, this.withList, true);
}
}
diff --git a/pg-core/query-builders/insert.js b/pg-core/query-builders/insert.js
index 60a8bb0d1c22b890bd8fbf4c85d5df41ca42444c..8754d0f2923f905816016c42f339c3e9097b4128 100644
--- a/pg-core/query-builders/insert.js
+++ b/pg-core/query-builders/insert.js
@@ -52,11 +52,6 @@ class PgInsertBuilder {
}
select(selectQuery) {
const select = typeof selectQuery === "function" ? selectQuery(new QueryBuilder()) : selectQuery;
- if (!is(select, SQL) && !haveSameKeys(this.table[Columns], select._.selectedFields)) {
- throw new Error(
- "Insert select error: selected fields are not the same or are in a different order compared to the table definition"
- );
- }
return new PgInsertBase(this.table, select, this.session, this.dialect, this.withList, true);
}
}

16
api/shell.nix Normal file
View File

@@ -0,0 +1,16 @@
{pkgs ? import <nixpkgs> {}}:
pkgs.mkShell {
packages = with pkgs; [
bun
biome
# for psql to debug from the cli
postgresql_18
# to build libvips (for sharp)
nodejs
node-gyp
pkg-config
vips
];
SHARP_FORCE_GLOBAL_LIBVIPS = 1;
}

120
api/src/auth.ts Normal file
View File

@@ -0,0 +1,120 @@
import { TypeCompiler } from "@sinclair/typebox/compiler";
import { Value } from "@sinclair/typebox/value";
import Elysia, { t } from "elysia";
import { createRemoteJWKSet, jwtVerify } from "jose";
import { KError } from "./models/error";
import type { Prettify } from "./utils";
const jwtSecret = process.env.JWT_SECRET
? new TextEncoder().encode(process.env.JWT_SECRET)
: null;
const jwks = createRemoteJWKSet(
new URL(
".well-known/jwks.json",
process.env.AUTH_SERVER ?? "http://auth:4568",
),
);
const Settings = t.Object(
{
preferOriginal: t.Boolean({ default: true }),
},
{ additionalProperties: true },
);
type Settings = typeof Settings.static;
const Jwt = t.Object({
sub: t.String({ description: "User id" }),
sid: t.String({ description: "Session id" }),
username: t.String(),
permissions: t.Array(t.String()),
settings: t.Optional(t.Partial(Settings, { default: {} })),
});
type Jwt = typeof Jwt.static;
const validator = TypeCompiler.Compile(Jwt);
export const auth = new Elysia({ name: "auth" })
.guard({
headers: t.Object(
{
authorization: t.Optional(t.TemplateLiteral("Bearer ${string}")),
},
{ additionalProperties: true },
),
})
.resolve(async ({ headers: { authorization }, status }) => {
const bearer = authorization?.slice(7);
if (!bearer) {
return status(403, {
status: 403,
message: "No authorization header was found.",
});
}
try {
// @ts-expect-error ts can't understand that there's two overload idk why
const { payload } = await jwtVerify(bearer, jwtSecret ?? jwks, {
issuer: process.env.JWT_ISSUER,
});
const raw = validator.Decode(payload);
const jwt = Value.Default(Jwt, raw) as Prettify<
Jwt & { settings: Settings }
>;
return { jwt };
} catch (err) {
return status(403, {
status: 403,
message: "Invalid jwt. Verification vailed",
details: err,
});
}
})
.macro({
permissions(perms: string[]) {
return {
beforeHandle: function permissionCheck({ jwt, status }) {
for (const perm of perms) {
if (!jwt!.permissions.includes(perm)) {
return status(403, {
status: 403,
message: `Missing permission: '${perm}'.`,
details: { current: jwt!.permissions, required: perms },
});
}
}
},
};
},
})
.as("scoped");
const User = t.Object({
id: t.String({ format: "uuid" }),
username: t.String(),
email: t.String({ format: "email" }),
createdDate: t.String({ format: "date-time" }),
lastSeen: t.String({ format: "date-time" }),
claims: t.Record(t.String(), t.Any()),
oidc: t.Record(
t.String(),
t.Object({
id: t.String({ format: "uuid" }),
username: t.String(),
profileUrl: t.Nullable(t.String({ format: "url" })),
}),
),
});
const UserC = TypeCompiler.Compile(t.Union([User, KError]));
export async function getUserInfo(
id: string,
headers: { authorization: string },
) {
const resp = await fetch(
new URL(`/auth/users/${id}`, process.env.AUTH_SERVER ?? "http://auth:4568"),
{ headers },
);
return UserC.Decode(await resp.json());
}

139
api/src/base.ts Normal file
View File

@@ -0,0 +1,139 @@
import { Elysia, t } from "elysia";
import { auth } from "./auth";
import { entriesH } from "./controllers/entries";
import { imagesH } from "./controllers/images";
import { historyH } from "./controllers/profiles/history";
import { nextup } from "./controllers/profiles/nextup";
import { watchlistH } from "./controllers/profiles/watchlist";
import { seasonsH } from "./controllers/seasons";
import { seed } from "./controllers/seed";
import { collections } from "./controllers/shows/collections";
import { movies } from "./controllers/shows/movies";
import { series } from "./controllers/shows/series";
import { showsH } from "./controllers/shows/shows";
import { staffH } from "./controllers/staff";
import { studiosH } from "./controllers/studios";
import { videosReadH, videosWriteH } from "./controllers/videos";
import { db } from "./db";
import type { KError } from "./models/error";
import { otel } from "./otel";
export const base = new Elysia({ name: "base" })
.onError(({ code, error }) => {
// sometimes elysia as an unknown code when throwing errors
if (code === "UNKNOWN") {
try {
const details = JSON.parse(error.message);
if (details?.code === "KError") {
const { code, ...ret } = details;
return ret;
}
} catch {}
}
if (code === "VALIDATION") {
const details = JSON.parse(error.message);
if (details.code === "KError") {
const { code, ...ret } = details;
return ret;
}
details.errors = details.errors.map((x: any) => {
const { schema, ...err } = x;
return err;
});
return {
status: error.status,
message: `Validation error on ${details.on}.`,
details: details,
} as KError;
}
if (code === "NOT_FOUND") {
return error;
}
console.error(code, error);
return {
status: 500,
message: "message" in error ? (error?.message ?? code) : code,
details: error,
} as KError;
})
.get("/health", () => ({ status: "healthy" }) as const, {
detail: { description: "Check if the api is healthy." },
response: { 200: t.Object({ status: t.Literal("healthy") }) },
})
.get(
"/ready",
async ({ status }) => {
try {
await db.execute("select 1");
return { status: "healthy", database: "healthy" } as const;
} catch (e) {
return status(500, {
status: "unhealthy",
database: e,
});
}
},
{
detail: { description: "Check if the api is healthy." },
response: {
200: t.Object({
status: t.Literal("healthy"),
database: t.Literal("healthy"),
}),
500: t.Object({
status: t.Literal("unhealthy"),
database: t.Any(),
}),
},
},
)
.as("global");
export const prefix = "/api";
export const handlers = new Elysia({ prefix })
.use(base)
.use(auth)
.use(otel)
.guard(
{
// Those are not applied for now. See https://github.com/elysiajs/elysia/issues/1139
detail: {
security: [{ bearer: ["core.read"] }, { api: ["core.read"] }],
},
// See https://github.com/elysiajs/elysia/issues/1158
// response: {
// 401: { ...KError, description: "" },
// 403: { ...KError, description: "" },
// },
permissions: ["core.read"],
},
(app) =>
app
.use(showsH)
.use(movies)
.use(series)
.use(collections)
.use(entriesH)
.use(seasonsH)
.use(studiosH)
.use(staffH)
.use(imagesH)
.use(watchlistH)
.use(historyH)
.use(nextup)
.use(videosReadH),
)
.guard(
{
detail: {
security: [{ bearer: ["core.write"] }, { api: ["core.write"] }],
},
// See https://github.com/elysiajs/elysia/issues/1158
// response: {
// 401: { ...KError, description: "" },
// 403: { ...KError, description: "" },
// },
permissions: ["core.write"],
},
(app) => app.use(videosWriteH).use(seed),
);

View File

@@ -0,0 +1,453 @@
import { and, desc, eq, isNotNull, ne, type SQL, sql } from "drizzle-orm";
import { Elysia, t } from "elysia";
import { auth } from "~/auth";
import { db } from "~/db";
import {
entries,
entryTranslations,
entryVideoJoin,
history,
profiles,
shows,
videos,
} from "~/db/schema";
import {
coalesce,
getColumns,
jsonbAgg,
jsonbBuildObject,
sqlarr,
} from "~/db/utils";
import {
Entry,
type EntryKind,
Episode,
Extra,
ExtraType,
MovieEntry,
Special,
} from "~/models/entry";
import { KError } from "~/models/error";
import { madeInAbyss } from "~/models/examples";
import {
AcceptLanguage,
createPage,
Filter,
type FilterDef,
isUuid,
keysetPaginate,
Page,
processLanguages,
Sort,
sortToSql,
} from "~/models/utils";
import { desc as description } from "~/models/utils/descriptions";
import type { EmbeddedVideo } from "~/models/video";
export const entryProgressQ = db
.selectDistinctOn([history.entryPk], {
percent: history.percent,
time: history.time,
entryPk: history.entryPk,
playedDate: history.playedDate,
videoId: videos.id,
})
.from(history)
.leftJoin(videos, eq(history.videoPk, videos.pk))
.innerJoin(profiles, eq(history.profilePk, profiles.pk))
.where(eq(profiles.id, sql.placeholder("userId")))
.orderBy(history.entryPk, desc(history.playedDate))
.as("progress");
export const entryFilters: FilterDef = {
kind: {
column: entries.kind,
type: "enum",
values: ["episode", "movie", "special"],
},
seasonNumber: { column: entries.seasonNumber, type: "int" },
episodeNumber: { column: entries.episodeNumber, type: "int" },
number: { column: entries.episodeNumber, type: "int" },
order: { column: entries.order, type: "float" },
runtime: { column: entries.runtime, type: "float" },
airDate: { column: entries.airDate, type: "date" },
playedDate: { column: entryProgressQ.playedDate, type: "date" },
isAvailable: { column: isNotNull(entries.availableSince), type: "bool" },
};
const extraFilters: FilterDef = {
kind: { column: entries.extraKind, type: "enum", values: ExtraType.enum },
runtime: { column: entries.runtime, type: "float" },
playedDate: { column: entryProgressQ.playedDate, type: "date" },
};
export const entrySort = Sort(
{
order: entries.order,
seasonNumber: entries.seasonNumber,
episodeNumber: entries.episodeNumber,
number: entries.episodeNumber,
airDate: entries.airDate,
nextRefresh: entries.nextRefresh,
playedDate: entryProgressQ.playedDate,
},
{
default: ["order"],
tablePk: entries.pk,
},
);
const extraSort = Sort(
{
slug: entries.slug,
name: entryTranslations.name,
runtime: entries.runtime,
createdAt: entries.createdAt,
playedDate: entryProgressQ.playedDate,
},
{
default: ["slug"],
tablePk: entries.pk,
},
);
const newsSort: Sort = {
tablePk: entries.pk,
sort: [
{
sql: entries.availableSince,
// in the news query we already filter nulls out
isNullable: false,
accessor: (x) => x.availableSince,
desc: false,
},
],
};
const { guess, createdAt, updatedAt, ...videosCol } = getColumns(videos);
export const entryVideosQ = db
.select({
videos: coalesce(
jsonbAgg(
jsonbBuildObject<EmbeddedVideo>({
slug: entryVideoJoin.slug,
...videosCol,
}),
),
sql`'[]'::jsonb`,
).as("videos"),
})
.from(entryVideoJoin)
.where(eq(entryVideoJoin.entryPk, entries.pk))
.leftJoin(videos, eq(videos.pk, entryVideoJoin.videoPk))
.as("videos");
export const getEntryTransQ = (languages: string[]) => {
return db
.selectDistinctOn([entryTranslations.pk])
.from(entryTranslations)
.orderBy(
entryTranslations.pk,
sql`array_position(${sqlarr(languages)}, ${entryTranslations.language})`,
)
.as("entry_t");
};
export const mapProgress = ({ aliased }: { aliased: boolean }) => {
const { time, percent, playedDate, videoId } = getColumns(entryProgressQ);
const ret = {
time: coalesce(time, sql<number>`0`),
percent: coalesce(percent, sql<number>`0`),
playedDate: sql<string>`to_char(${playedDate}, 'YYYY-MM-DD"T"HH24:MI:SS"Z"')`,
videoId: sql<string>`${videoId}`,
};
if (!aliased) return ret;
return Object.fromEntries(
Object.entries(ret).map(([k, v]) => [k, v.as(k)]),
) as unknown as typeof ret;
};
export async function getEntries({
after,
limit,
query,
sort,
filter,
languages,
userId,
progressQ = entryProgressQ,
}: {
after: string | undefined;
limit: number;
query: string | undefined;
sort: Sort;
filter: SQL | undefined;
languages: string[];
userId: string;
progressQ?: typeof entryProgressQ;
}): Promise<(Entry | Extra)[]> {
const transQ = getEntryTransQ(languages);
const {
kind,
externalId,
order,
seasonNumber,
episodeNumber,
extraKind,
...entryCol
} = getColumns(entries);
return await db
.select({
...entryCol,
...getColumns(transQ),
videos: entryVideosQ.videos,
progress: mapProgress({ aliased: true }),
// specials don't have an `episodeNumber` but a `number` field.
number: sql<number>`${episodeNumber}`,
// merge `extraKind` into `kind`
kind: sql<EntryKind>`case when ${kind} = 'extra' then ${extraKind} else ${kind}::text end`.as(
"kind",
),
// assign more restrained types to make typescript happy.
externalId: sql<any>`${externalId}`,
order: sql<number>`${order}`,
seasonNumber: sql<number>`${seasonNumber}`,
episodeNumber: sql<number>`${episodeNumber}`,
name: sql<string>`${transQ.name}`,
})
.from(entries)
.innerJoin(transQ, eq(entries.pk, transQ.pk))
.crossJoinLateral(entryVideosQ)
.leftJoin(progressQ, eq(entries.pk, progressQ.entryPk))
.where(
and(
filter,
query ? sql`${transQ.name} %> ${query}::text` : undefined,
keysetPaginate({ after, sort }),
),
)
.orderBy(
...(query
? [sql`word_similarity(${query}::text, ${transQ.name})`]
: sortToSql(sort)),
entries.pk,
)
.limit(limit)
.execute({ userId });
}
export const entriesH = new Elysia({ tags: ["series"] })
.model({
episode: Episode,
movie_entry: MovieEntry,
special: Special,
extra: Extra,
error: t.Object({}),
})
.model((models) => ({
...models,
entry: t.Union([models.episode, models.movie_entry, models.special]),
}))
.use(auth)
.get(
"/series/:id/entries",
async ({
params: { id },
query: { limit, after, query, sort, filter },
headers: { "accept-language": languages, ...headers },
request: { url },
jwt: { sub },
status,
}) => {
const [serie] = await db
.select({ pk: shows.pk })
.from(shows)
.where(
and(
eq(shows.kind, "serie"),
isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id),
),
)
.limit(1);
if (!serie) {
return status(404, {
status: 404,
message: `No serie with the id or slug: '${id}'.`,
});
}
const langs = processLanguages(languages);
const items = (await getEntries({
limit,
after,
query,
sort,
filter: and(
eq(entries.showPk, serie.pk),
ne(entries.kind, "extra"),
filter,
),
languages: langs,
userId: sub,
})) as Entry[];
return createPage(items, { url, sort, limit, headers });
},
{
detail: { description: "Get entries of a serie" },
params: t.Object({
id: t.String({
description: "The id or slug of the serie.",
example: madeInAbyss.slug,
}),
}),
query: t.Object({
sort: entrySort,
filter: t.Optional(Filter({ def: entryFilters })),
query: t.Optional(t.String({ description: description.query })),
limit: t.Integer({
minimum: 1,
maximum: 250,
default: 50,
description: "Max page size.",
}),
after: t.Optional(t.String({ description: description.after })),
}),
headers: t.Object(
{
"accept-language": AcceptLanguage({ autoFallback: true }),
},
{ additionalProperties: true },
),
response: {
200: Page(Entry),
404: {
...KError,
description: "No serie found with the given id or slug.",
},
422: KError,
},
},
)
.get(
"/series/:id/extras",
async ({
params: { id },
query: { limit, after, query, sort, filter },
request: { url },
headers,
jwt: { sub },
status,
}) => {
const [serie] = await db
.select({ pk: shows.pk })
.from(shows)
.where(
and(
eq(shows.kind, "serie"),
isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id),
),
)
.limit(1);
if (!serie) {
return status(404, {
status: 404,
message: `No serie with the id or slug: '${id}'.`,
});
}
const items = (await getEntries({
limit,
after,
query,
sort: sort,
filter: and(
eq(entries.showPk, serie.pk),
eq(entries.kind, "extra"),
filter,
),
languages: ["extra"],
userId: sub,
})) as Extra[];
return createPage(items, { url, sort, limit, headers });
},
{
detail: { description: "Get extras of a serie" },
params: t.Object({
id: t.String({
description: "The id or slug of the serie.",
example: madeInAbyss.slug,
}),
}),
query: t.Object({
sort: extraSort,
filter: t.Optional(Filter({ def: extraFilters })),
query: t.Optional(t.String({ description: description.query })),
limit: t.Integer({
minimum: 1,
maximum: 250,
default: 50,
description: "Max page size.",
}),
after: t.Optional(t.String({ description: description.after })),
}),
response: {
200: Page(Extra),
404: {
...KError,
description: "No serie found with the given id or slug.",
},
422: KError,
},
},
)
.get(
"/news",
async ({
query: { limit, after, query, filter },
request: { url },
headers,
jwt: { sub },
}) => {
const sort = newsSort;
const items = (await getEntries({
limit,
after,
query,
sort,
filter: and(
isNotNull(entries.availableSince),
ne(entries.kind, "extra"),
filter,
),
languages: ["extra"],
userId: sub,
})) as Entry[];
return createPage(items, { url, sort, limit, headers });
},
{
detail: { description: "Get new movies/episodes added recently." },
query: t.Object({
filter: t.Optional(Filter({ def: entryFilters })),
query: t.Optional(t.String({ description: description.query })),
limit: t.Integer({
minimum: 1,
maximum: 250,
default: 50,
description: "Max page size.",
}),
after: t.Optional(t.String({ description: description.after })),
}),
response: {
200: Page(Entry),
422: KError,
},
tags: ["shows"],
},
);

View File

@@ -0,0 +1,404 @@
import type { Stats } from "node:fs";
import type { S3Stats } from "bun";
import { and, eq, type SQL, sql } from "drizzle-orm";
import Elysia, { type Context, t } from "elysia";
import { prefix } from "~/base";
import { db } from "~/db";
import {
shows,
showTranslations,
staff,
studios,
studioTranslations,
} from "~/db/schema";
import { sqlarr } from "~/db/utils";
import { KError } from "~/models/error";
import { bubble } from "~/models/examples";
import { AcceptLanguage, isUuid, processLanguages } from "~/models/utils";
import { comment, getFile } from "~/utils";
import { imageDir } from "./seed/images";
function getRedirectToImageHandler({ filter }: { filter?: SQL }) {
return async function Handler({
params: { id, image },
headers: { "accept-language": languages },
query: { quality },
set,
status,
redirect,
}: {
params: { id?: string; image: "poster" | "thumbnail" | "banner" | "logo" };
headers: { "accept-language": string };
query: { quality?: "high" | "medium" | "low" };
set: Context["set"];
status: Context["status"];
redirect: Context["redirect"];
}) {
id ??= "random";
const lang = processLanguages(languages);
const item = db.$with("item").as(
db
.select({ pk: shows.pk })
.from(shows)
.where(
and(
filter,
id !== "random"
? isUuid(id)
? eq(shows.id, id)
: eq(shows.slug, id)
: undefined,
),
)
.orderBy(sql`random()`)
.limit(1),
);
const [ret] = await db
.with(item)
.select({
image: showTranslations[image],
language: showTranslations.language,
})
.from(item)
.leftJoin(showTranslations, eq(item.pk, showTranslations.pk))
.where(
!lang.includes("*")
? eq(showTranslations.language, sql`any(${sqlarr(lang)})`)
: undefined,
)
.orderBy(
sql`array_position(${sqlarr(lang)}, ${showTranslations.language})`,
)
.limit(1);
if (!ret) {
return status(404, {
status: 404,
message: `No item found with id or slug: '${id}'.`,
});
}
if (!ret.language) {
return status(422, {
status: 422,
message: "Accept-Language header could not be satisfied.",
});
}
set.headers["content-language"] = ret.language;
return quality
? redirect(`${prefix}/images/${ret.image!.id}?quality=${quality}`)
: redirect(`${prefix}/images/${ret.image!.id}`);
};
}
export const imagesH = new Elysia({ tags: ["images"] })
.get(
"/images/:id",
async ({
params: { id },
query: { quality },
headers: reqHeaders,
status,
}) => {
const path = `${imageDir}/${id}.${quality}.jpg`;
const file = getFile(path);
const stat = await file.stat().catch(() => undefined);
if (!stat) {
return status(404, {
status: 404,
message: comment`
No image available with this ID.
Either the id is invalid or the image has not been downloaded yet.
`,
});
}
const etag =
"etag" in stat
? stat.etag
: Buffer.from(stat.mtime.toISOString(), "utf8").toString("base64");
if (await isCached(reqHeaders, etag, path))
return new Response(null, { status: 304 });
const [start = 0, end = Number.POSITIVE_INFINITY] =
reqHeaders.range?.split("-").map(Number) ?? [];
return new Response(file.slice(start, end), {
headers: {
Etag: etag,
"Cache-Control": `public, max-age=${3 * 60 * 60}`,
},
}) as any;
},
{
detail: { description: "Access an image by id." },
params: t.Object({
id: t.String({
desription: "Id of the image to retrive.",
format: "regex",
pattern: "^[0-9a-fA-F]*$",
}),
}),
query: t.Object({
quality: t.Optional(
t.UnionEnum(["high", "medium", "low"], {
default: "high",
description: "The quality you want your image to be in.",
}),
),
}),
response: {
200: t.File({ description: "The whole image" }),
206: t.File({ description: "Only the range of the image requested" }),
304: t.Void({ description: "Cached image already up-to-date" }),
404: { ...KError, description: "No image found with this id." },
},
},
)
.guard({
query: t.Object({
quality: t.Optional(
t.UnionEnum(["high", "medium", "low"], {
default: "high",
description: "The quality you want your image to be in.",
}),
),
}),
response: {
302: t.Void({
description:
"Redirected to the [/images/{id}](#tag/images/get/api/images/{id}) route.",
}),
404: {
...KError,
description: "No item found with the given id or slug.",
},
422: KError,
},
})
.get(
"/staff/:id/image",
async ({ params: { id }, query: { quality }, status, redirect }) => {
const [ret] = await db
.select({ image: staff.image })
.from(staff)
.where(
id !== "random"
? isUuid(id)
? eq(shows.id, id)
: eq(shows.slug, id)
: undefined,
)
.orderBy(sql`random()`)
.limit(1);
if (!ret) {
return status(404, {
status: 404,
message: `No staff member found with id or slug: '${id}'.`,
});
}
return quality
? redirect(`${prefix}/images/${ret.image!.id}?quality=${quality}`)
: redirect(`${prefix}/images/${ret.image!.id}`);
},
{
detail: { description: "Get the image of a staff member." },
params: t.Object({
id: t.String({
description: "The id or slug of the staff member.",
example: bubble.slug,
}),
}),
},
)
.guard({
headers: t.Object({
"accept-language": AcceptLanguage(),
}),
})
.get(
"/studios/:id/logo",
async ({
params: { id },
headers: { "accept-language": languages },
query: { quality },
set,
status,
redirect,
}) => {
const lang = processLanguages(languages);
const item = db.$with("item").as(
db
.select({ pk: studios.pk })
.from(studios)
.where(
id !== "random"
? isUuid(id)
? eq(studios.id, id)
: eq(studios.slug, id)
: undefined,
)
.orderBy(sql`random()`)
.limit(1),
);
const [ret] = await db
.with(item)
.select({
image: studioTranslations.logo,
language: studioTranslations.language,
})
.from(item)
.leftJoin(studioTranslations, eq(item.pk, studioTranslations.pk))
.where(
!lang.includes("*")
? eq(studioTranslations.language, sql`any(${sqlarr(lang)})`)
: undefined,
)
.orderBy(
sql`array_position(${sqlarr(lang)}, ${studioTranslations.language})`,
)
.limit(1);
if (!ret) {
return status(404, {
status: 404,
message: `No studio found with id or slug: '${id}'.`,
});
}
if (!ret.language) {
return status(422, {
status: 422,
message: "Accept-Language header could not be satisfied.",
});
}
set.headers["content-language"] = ret.language;
return quality
? redirect(`${prefix}/images/${ret.image!.id}?quality=${quality}`)
: redirect(`${prefix}/images/${ret.image!.id}`);
},
{
detail: { description: "Get the logo of a studio." },
params: t.Object({
id: t.String({
description: "The id or slug of the studio.",
example: bubble.slug,
}),
}),
},
)
.get("/shows/random/:image", getRedirectToImageHandler({}), {
detail: { description: "Get the specified image of a random show." },
params: t.Object({
image: t.UnionEnum(["poster", "thumbnail", "logo", "banner"], {
description: "The type of image to retrive.",
}),
}),
})
.guard({
params: t.Object({
id: t.String({
description: "The id or slug of the item to retrieve.",
example: bubble.slug,
}),
image: t.UnionEnum(["poster", "thumbnail", "logo", "banner"], {
description: "The type of image to retrive.",
}),
}),
headers: t.Object({
"accept-language": AcceptLanguage(),
}),
})
.get(
"/movies/:id/:image",
getRedirectToImageHandler({
filter: eq(shows.kind, "movie"),
}),
{
detail: { description: "Get the specified image of a movie" },
},
)
.get(
"/series/:id/:image",
getRedirectToImageHandler({
filter: eq(shows.kind, "serie"),
}),
{
detail: { description: "Get the specified image of a serie" },
},
)
.get(
"/collections/:id/:image",
getRedirectToImageHandler({
filter: eq(shows.kind, "collection"),
}),
{
detail: { description: "Get the specified image of a collection" },
},
);
// stolen from https://github.com/elysiajs/elysia-static/blob/main/src/cache.ts
export async function isCached(
headers: Record<string, string | undefined>,
etag: string,
filePath: string,
) {
// Always return stale when Cache-Control: no-cache
// to support end-to-end reload requests
// https://tools.ietf.org/html/rfc2616#section-14.9.4
if (
headers["cache-control"] &&
headers["cache-control"].indexOf("no-cache") !== -1
)
return false;
// if-none-match
if ("if-none-match" in headers) {
const ifNoneMatch = headers["if-none-match"];
if (ifNoneMatch === "*") return true;
if (ifNoneMatch === null) return false;
if (typeof etag !== "string") return false;
const isMatching = ifNoneMatch === etag;
if (isMatching) return true;
/**
* A recipient MUST ignore If-Modified-Since if the request contains an
* If-None-Match header field; the condition in If-None-Match is considered
* to be a more accurate replacement for the condition in If-Modified-Since,
* and the two are only combined for the sake of interoperating with older
* intermediaries that might not implement If-None-Match.
*
* @see RFC 9110 section 13.1.3
*/
return false;
}
// if-modified-since
if (headers["if-modified-since"]) {
const ifModifiedSince = headers["if-modified-since"];
let lastModified: Date | undefined;
const stat = await getFile(filePath).stat();
try {
if ((stat as S3Stats).lastModified) {
lastModified = (stat as S3Stats).lastModified;
} else if ((stat as Stats).mtime) {
lastModified = (stat as Stats).mtime;
}
} catch {
/* empty */
}
if (
lastModified !== undefined &&
lastModified.getTime() <= Date.parse(ifModifiedSince)
)
return true;
}
return false;
}

View File

@@ -0,0 +1,344 @@
import { and, count, eq, exists, gt, isNotNull, ne, sql } from "drizzle-orm";
import { alias } from "drizzle-orm/pg-core";
import Elysia, { t } from "elysia";
import { auth, getUserInfo } from "~/auth";
import { db } from "~/db";
import { entries, history, profiles, shows, videos } from "~/db/schema";
import { watchlist } from "~/db/schema/watchlist";
import { coalesce, values } from "~/db/utils";
import { Entry } from "~/models/entry";
import { KError } from "~/models/error";
import { SeedHistory } from "~/models/history";
import {
AcceptLanguage,
createPage,
Filter,
isUuid,
Page,
processLanguages,
} from "~/models/utils";
import { desc } from "~/models/utils/descriptions";
import type { WatchlistStatus } from "~/models/watchlist";
import {
entryFilters,
entryProgressQ,
entrySort,
getEntries,
} from "../entries";
import { getOrCreateProfile } from "./profile";
const historyProgressQ: typeof entryProgressQ = db
.select({
percent: history.percent,
time: history.time,
entryPk: history.entryPk,
playedDate: history.playedDate,
videoId: videos.id,
})
.from(history)
.leftJoin(videos, eq(history.videoPk, videos.pk))
.leftJoin(profiles, eq(history.profilePk, profiles.pk))
.where(eq(profiles.id, sql.placeholder("userId")))
.as("progress");
export const historyH = new Elysia({ tags: ["profiles"] })
.use(auth)
.guard(
{
query: t.Object({
sort: {
...entrySort,
default: ["-playedDate"],
},
filter: t.Optional(Filter({ def: entryFilters })),
query: t.Optional(t.String({ description: desc.query })),
limit: t.Integer({
minimum: 1,
maximum: 250,
default: 50,
description: "Max page size.",
}),
after: t.Optional(t.String({ description: desc.after })),
}),
},
(app) =>
app
.get(
"/profiles/me/history",
async ({
query: { sort, filter, query, limit, after },
headers: { "accept-language": languages, ...headers },
request: { url },
jwt: { sub },
}) => {
const langs = processLanguages(languages);
const items = (await getEntries({
limit,
after,
query,
sort,
filter: and(
isNotNull(entryProgressQ.playedDate),
ne(entries.kind, "extra"),
filter,
),
languages: langs,
userId: sub,
progressQ: historyProgressQ,
})) as Entry[];
return createPage(items, { url, sort, limit, headers });
},
{
detail: {
description: "List your watch history (episodes/movies seen)",
},
headers: t.Object(
{
"accept-language": AcceptLanguage({ autoFallback: true }),
},
{ additionalProperties: true },
),
response: {
200: Page(Entry),
},
},
)
.get(
"/profiles/:id/history",
async ({
params: { id },
query: { sort, filter, query, limit, after },
headers: {
"accept-language": languages,
authorization,
...headers
},
request: { url },
status,
}) => {
const uInfo = await getUserInfo(id, { authorization });
if ("status" in uInfo) return status(uInfo.status as 404, uInfo);
const langs = processLanguages(languages);
const items = (await getEntries({
limit,
after,
query,
sort,
filter: and(
isNotNull(entryProgressQ.playedDate),
ne(entries.kind, "extra"),
filter,
),
languages: langs,
userId: uInfo.id,
progressQ: historyProgressQ,
})) as Entry[];
return createPage(items, { url, sort, limit, headers });
},
{
detail: {
description: "List your watch history (episodes/movies seen)",
},
params: t.Object({
id: t.String({
description:
"The id or username of the user to read the watchlist of",
example: "zoriya",
}),
}),
headers: t.Object({
authorization: t.TemplateLiteral("Bearer ${string}"),
"accept-language": AcceptLanguage({ autoFallback: true }),
}),
response: {
200: Page(Entry),
403: KError,
404: {
...KError,
description: "No user found with the specified id/username.",
},
422: KError,
},
},
),
)
.post(
"/profiles/me/history",
async ({ body, jwt: { sub }, status }) => {
const profilePk = await getOrCreateProfile(sub);
const hist = values(
body.map((x) => ({ ...x, entryUseId: isUuid(x.entry) })),
{
percent: "integer",
time: "integer",
playedDate: "timestamptz",
videoId: "uuid",
},
).as("hist");
const valEqEntries = sql`
case
when hist.entryUseId::boolean then ${entries.id} = hist.entry::uuid
else ${entries.slug} = hist.entry
end
`;
const rows = await db
.insert(history)
.select(
db
.select({
profilePk: sql`${profilePk}`.as("profilePk"),
entryPk: entries.pk,
videoPk: videos.pk,
percent: sql`hist.percent`.as("percent"),
time: sql`hist.time`.as("time"),
playedDate: sql`hist.playedDate`.as("playedDate"),
})
.from(hist)
.innerJoin(entries, valEqEntries)
.leftJoin(videos, eq(videos.id, sql`hist.videoId`)),
)
.returning({ pk: history.pk });
// automatically update watchlist with this new info
const nextEntry = alias(entries, "next_entry");
const nextEntryQ = db
.select({
pk: nextEntry.pk,
})
.from(nextEntry)
.where(
and(
eq(nextEntry.showPk, entries.showPk),
ne(nextEntry.kind, "extra"),
gt(nextEntry.order, entries.order),
),
)
.orderBy(nextEntry.order)
.limit(1)
.as("nextEntryQ");
const seenCountQ = db
.select({ c: count() })
.from(entries)
.where(
and(
eq(entries.showPk, sql`excluded.show_pk`),
exists(
db
.select()
.from(history)
.where(
and(
eq(history.profilePk, profilePk),
eq(history.entryPk, entries.pk),
),
),
),
),
);
const showKindQ = db
.select({ k: shows.kind })
.from(shows)
.where(eq(shows.pk, sql`excluded.show_pk`));
await db
.insert(watchlist)
.select(
db
.select({
profilePk: sql`${profilePk}`.as("profilePk"),
showPk: entries.showPk,
status: sql<WatchlistStatus>`
case
when
hist.percent >= 95
and ${nextEntryQ.pk} is null
then 'completed'::watchlist_status
else 'watching'::watchlist_status
end
`.as("status"),
seenCount: sql`
case
when ${entries.kind} = 'movie' then hist.percent
when hist.percent >= 95 then 1
else 0
end
`.as("seen_count"),
nextEntry: sql`
case
when hist.percent >= 95 then ${nextEntryQ.pk}
else ${entries.pk}
end
`.as("next_entry"),
score: sql`null`.as("score"),
startedAt: sql`hist.playedDate`.as("startedAt"),
lastPlayedAt: sql`hist.playedDate`.as("lastPlayedAt"),
completedAt: sql`
case
when ${nextEntryQ.pk} is null then hist.playedDate
else null
end
`.as("completedAt"),
// see https://github.com/drizzle-team/drizzle-orm/issues/3608
updatedAt: sql`now()`.as("updatedAt"),
})
.from(hist)
.leftJoin(entries, valEqEntries)
.leftJoinLateral(nextEntryQ, sql`true`),
)
.onConflictDoUpdate({
target: [watchlist.profilePk, watchlist.showPk],
set: {
status: sql`
case
when excluded.status = 'completed' then excluded.status
when
${watchlist.status} != 'completed'
and ${watchlist.status} != 'rewatching'
then excluded.status
else ${watchlist.status}
end
`,
seenCount: sql`
case
when ${showKindQ} = 'movie' then excluded.seen_count
else ${seenCountQ}
end`,
nextEntry: sql`
case
when ${watchlist.status} = 'completed' then null
else excluded.next_entry
end
`,
lastPlayedAt: sql`excluded.last_played_at`,
completedAt: coalesce(
watchlist.completedAt,
sql`excluded.completed_at`,
),
},
});
return status(201, { status: 201, inserted: rows.length });
},
{
detail: { description: "Bulk add entries/movies to your watch history." },
body: t.Array(SeedHistory),
permissions: ["core.read"],
response: {
201: t.Object({
status: t.Literal(201),
inserted: t.Integer({
description: "The number of history entry inserted",
}),
}),
422: KError,
},
},
);

View File

@@ -0,0 +1,143 @@
import { and, eq, sql } from "drizzle-orm";
import Elysia, { t } from "elysia";
import { auth } from "~/auth";
import { db } from "~/db";
import { entries } from "~/db/schema";
import { watchlist } from "~/db/schema/watchlist";
import { getColumns } from "~/db/utils";
import { Entry } from "~/models/entry";
import {
AcceptLanguage,
createPage,
Filter,
type FilterDef,
keysetPaginate,
Page,
processLanguages,
Sort,
sortToSql,
} from "~/models/utils";
import { desc } from "~/models/utils/descriptions";
import {
entryFilters,
entryProgressQ,
entryVideosQ,
getEntryTransQ,
mapProgress,
} from "../entries";
const nextupSort = Sort(
// copy pasted from entrySort + adding new stuff
{
order: entries.order,
seasonNumber: entries.seasonNumber,
episodeNumber: entries.episodeNumber,
number: entries.episodeNumber,
airDate: entries.airDate,
started: watchlist.startedAt,
added: watchlist.createdAt,
lastPlayed: watchlist.lastPlayedAt,
},
{
default: ["-lastPlayed"],
tablePk: entries.pk,
},
);
const nextupFilters: FilterDef = {
...entryFilters,
};
export const nextup = new Elysia({ tags: ["profiles"] })
.use(auth)
.guard({
query: t.Object({
sort: nextupSort,
filter: t.Optional(Filter({ def: nextupFilters })),
query: t.Optional(t.String({ description: desc.query })),
limit: t.Integer({
minimum: 1,
maximum: 250,
default: 50,
description: "Max page size.",
}),
after: t.Optional(t.String({ description: desc.after })),
}),
})
.get(
"/profiles/me/nextup",
async ({
query: { sort, filter, query, limit, after },
headers: { "accept-language": languages, ...headers },
request: { url },
jwt: { sub },
}) => {
const langs = processLanguages(languages);
const transQ = getEntryTransQ(langs);
const {
externalId,
order,
seasonNumber,
episodeNumber,
extraKind,
kind,
...entryCol
} = getColumns(entries);
const items = await db
.select({
...entryCol,
...getColumns(transQ),
videos: entryVideosQ.videos,
progress: mapProgress({ aliased: true }),
// specials don't have an `episodeNumber` but a `number` field.
number: sql<number>`${episodeNumber}`,
// assign more restrained types to make typescript happy.
kind: sql<Entry["kind"]>`${kind}`,
externalId: sql<any>`${externalId}`,
order: sql<number>`${order}`,
seasonNumber: sql<number>`${seasonNumber}`,
episodeNumber: sql<number>`${episodeNumber}`,
name: sql<string>`${transQ.name}`,
})
.from(entries)
.innerJoin(watchlist, eq(watchlist.nextEntry, entries.pk))
.innerJoin(transQ, eq(entries.pk, transQ.pk))
.crossJoinLateral(entryVideosQ)
.leftJoin(entryProgressQ, eq(entries.pk, entryProgressQ.entryPk))
.where(
and(
filter,
query ? sql`${transQ.name} %> ${query}::text` : undefined,
keysetPaginate({ after, sort }),
),
)
.orderBy(
...(query
? [sql`word_similarity(${query}::text, ${transQ.name})`]
: sortToSql(sort)),
entries.pk,
)
.limit(limit)
.execute({ userId: sub });
return createPage(items, { url, sort, limit, headers });
},
{
detail: {
description: "",
},
headers: t.Object(
{
"accept-language": AcceptLanguage({ autoFallback: true }),
},
{ additionalProperties: true },
),
response: {
200: Page(Entry),
},
},
);

View File

@@ -0,0 +1,24 @@
import { eq, sql } from "drizzle-orm";
import { db } from "~/db";
import { profiles } from "~/db/schema";
export async function getOrCreateProfile(userId: string) {
let [profile] = await db
.select({ pk: profiles.pk })
.from(profiles)
.where(eq(profiles.id, userId))
.limit(1);
if (profile) return profile.pk;
[profile] = await db
.insert(profiles)
.values({ id: userId })
.onConflictDoUpdate({
// we can't do `onConflictDoNothing` because on race conditions
// we still want the profile to be returned.
target: [profiles.id],
set: { id: sql`excluded.id` },
})
.returning({ pk: profiles.pk });
return profile.pk;
}

View File

@@ -0,0 +1,351 @@
import { and, eq, isNotNull, isNull, sql } from "drizzle-orm";
import Elysia, { t } from "elysia";
import { auth, getUserInfo } from "~/auth";
import {
getShows,
showFilters,
showSort,
watchStatusQ,
} from "~/controllers/shows/logic";
import { db } from "~/db";
import { entries, shows } from "~/db/schema";
import { watchlist } from "~/db/schema/watchlist";
import { conflictUpdateAllExcept, getColumns } from "~/db/utils";
import { Entry } from "~/models/entry";
import { KError } from "~/models/error";
import { bubble, madeInAbyss } from "~/models/examples";
import { Movie } from "~/models/movie";
import { Serie } from "~/models/serie";
import {
AcceptLanguage,
createPage,
DbMetadata,
Filter,
isUuid,
Page,
processLanguages,
} from "~/models/utils";
import { desc } from "~/models/utils/descriptions";
import { MovieWatchStatus, SerieWatchStatus } from "~/models/watchlist";
import { getOrCreateProfile } from "./profile";
async function setWatchStatus({
show,
status,
userId,
}: {
show:
| { pk: number; kind: "movie" }
| { pk: number; kind: "serie"; entriesCount: number };
status: Omit<SerieWatchStatus, "seenCount">;
userId: string;
}) {
const profilePk = await getOrCreateProfile(userId);
const firstEntryQ = db
.select({ pk: entries.pk })
.from(entries)
.where(eq(entries.showPk, show.pk))
.orderBy(entries.order)
.limit(1);
const [ret] = await db
.insert(watchlist)
.values({
...status,
profilePk: profilePk,
seenCount:
status.status === "completed"
? show.kind === "movie"
? 100
: show.entriesCount
: 0,
showPk: show.pk,
nextEntry:
status.status === "watching" || status.status === "rewatching"
? sql`${firstEntryQ}`
: sql`null`,
lastPlayedAt: status.startedAt,
})
.onConflictDoUpdate({
target: [watchlist.profilePk, watchlist.showPk],
set: {
...conflictUpdateAllExcept(watchlist, [
"profilePk",
"showPk",
"createdAt",
"seenCount",
"nextEntry",
"lastPlayedAt",
]),
...(status.status === "completed"
? {
seenCount: sql`excluded.seen_count`,
nextEntry: sql`null`,
}
: {}),
// only set seenCount & nextEntry when marking as "rewatching"
// if it's already rewatching, the history updates are more up-dated.
...(status.status === "rewatching"
? {
seenCount: sql`
case when ${watchlist.status} != 'rewatching'
then excluded.seen_count
else
${watchlist.seenCount}
end`,
nextEntry: sql`
case when ${watchlist.status} != 'rewatching'
then excluded.next_entry
else
${watchlist.nextEntry}
end`,
}
: {}),
},
})
.returning({
...getColumns(watchlist),
percent: sql<number>`${watchlist.seenCount}`.as("percent"),
});
return ret;
}
export const watchlistH = new Elysia({ tags: ["profiles"] })
.use(auth)
.guard(
{
query: t.Object({
sort: {
...showSort,
default: ["watchStatus", ...showSort.default],
},
filter: t.Optional(Filter({ def: showFilters })),
query: t.Optional(t.String({ description: desc.query })),
limit: t.Integer({
minimum: 1,
maximum: 250,
default: 50,
description: "Max page size.",
}),
after: t.Optional(t.String({ description: desc.after })),
preferOriginal: t.Optional(
t.Boolean({
description: desc.preferOriginal,
}),
),
}),
},
(app) =>
app
.get(
"/profiles/me/watchlist",
async ({
query: { limit, after, query, sort, filter, preferOriginal },
headers: { "accept-language": languages, ...headers },
request: { url },
jwt: { sub, settings },
}) => {
const langs = processLanguages(languages);
const items = await getShows({
limit,
after,
query,
sort,
filter: and(
isNotNull(watchStatusQ.status),
isNull(shows.collectionPk),
filter,
),
languages: langs,
preferOriginal: preferOriginal ?? settings.preferOriginal,
relations: ["nextEntry"],
userId: sub,
});
return createPage(items, { url, sort, limit, headers });
},
{
detail: { description: "Get all movies/series in your watchlist" },
headers: t.Object(
{
"accept-language": AcceptLanguage({ autoFallback: true }),
},
{ additionalProperties: true },
),
response: {
200: Page(
t.Union([
t.Intersect([Movie, t.Object({ kind: t.Literal("movie") })]),
t.Intersect([
Serie,
t.Object({
kind: t.Literal("serie"),
nextEntry: t.Optional(t.Nullable(Entry)),
}),
]),
]),
),
422: KError,
},
},
)
.get(
"/profiles/:id/watchlist",
async ({
params: { id },
query: { limit, after, query, sort, filter, preferOriginal },
jwt: { settings },
headers: {
"accept-language": languages,
authorization,
...headers
},
request: { url },
status,
}) => {
const uInfo = await getUserInfo(id, { authorization });
if ("status" in uInfo) return status(uInfo.status as 404, uInfo);
const langs = processLanguages(languages);
const items = await getShows({
limit,
after,
query,
sort,
filter: and(
isNotNull(watchStatusQ.status),
isNull(shows.collectionPk),
filter,
),
languages: langs,
preferOriginal: preferOriginal ?? settings.preferOriginal,
relations: ["nextEntry"],
userId: uInfo.id,
});
return createPage(items, { url, sort, limit, headers });
},
{
detail: {
description: "Get all movies/series in someone's watchlist",
},
params: t.Object({
id: t.String({
description:
"The id or username of the user to read the watchlist of",
example: "zoriya",
}),
}),
headers: t.Object({
authorization: t.TemplateLiteral("Bearer ${string}"),
"accept-language": AcceptLanguage({ autoFallback: true }),
}),
response: {
200: Page(
t.Union([
t.Intersect([Movie, t.Object({ kind: t.Literal("movie") })]),
t.Intersect([
Serie,
t.Object({
kind: t.Literal("serie"),
nextEntry: t.Optional(t.Nullable(Entry)),
}),
]),
]),
),
403: KError,
404: {
...KError,
description: "No user found with the specified id/username.",
},
422: KError,
},
permissions: ["users.read"],
},
),
)
.post(
"/series/:id/watchstatus",
async ({ params: { id }, body, jwt: { sub }, status }) => {
const [show] = await db
.select({ pk: shows.pk, entriesCount: shows.entriesCount })
.from(shows)
.where(
and(
eq(shows.kind, "serie"),
isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id),
),
);
if (!show) {
return status(404, {
status: 404,
message: `No serie found for the id/slug: '${id}'.`,
});
}
return await setWatchStatus({
show: { pk: show.pk, kind: "serie", entriesCount: show.entriesCount },
userId: sub,
status: body,
});
},
{
detail: { description: "Set watchstatus of a series." },
params: t.Object({
id: t.String({
description: "The id or slug of the serie.",
example: madeInAbyss.slug,
}),
}),
body: t.Omit(SerieWatchStatus, ["seenCount"]),
response: {
200: t.Intersect([SerieWatchStatus, DbMetadata]),
404: KError,
},
permissions: ["core.read"],
},
)
.post(
"/movies/:id/watchstatus",
async ({ params: { id }, body, jwt: { sub }, status }) => {
const [show] = await db
.select({ pk: shows.pk })
.from(shows)
.where(
and(
eq(shows.kind, "movie"),
isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id),
),
);
if (!show) {
return status(404, {
status: 404,
message: `No movie found for the id/slug: '${id}'.`,
});
}
return await setWatchStatus({
show: { pk: show.pk, kind: "movie" },
userId: sub,
status: {
...body,
startedAt: body.completedAt,
},
});
},
{
detail: { description: "Set watchstatus of a movie." },
params: t.Object({
id: t.String({
description: "The id or slug of the movie.",
example: bubble.slug,
}),
}),
body: t.Omit(MovieWatchStatus, ["percent"]),
response: {
200: t.Intersect([MovieWatchStatus, DbMetadata]),
404: KError,
},
permissions: ["core.read"],
},
);

View File

@@ -0,0 +1,150 @@
import { and, eq, sql } from "drizzle-orm";
import { Elysia, t } from "elysia";
import { db } from "~/db";
import { seasons, seasonTranslations, shows } from "~/db/schema";
import { getColumns, sqlarr } from "~/db/utils";
import { KError } from "~/models/error";
import { madeInAbyss } from "~/models/examples";
import {
AcceptLanguage,
createPage,
Filter,
type FilterDef,
isUuid,
keysetPaginate,
Page,
processLanguages,
Sort,
sortToSql,
} from "~/models/utils";
import { desc } from "~/models/utils/descriptions";
import { Season, SeasonTranslation } from "../models/season";
const seasonFilters: FilterDef = {
seasonNumber: { column: seasons.seasonNumber, type: "int" },
startAir: { column: seasons.startAir, type: "date" },
endAir: { column: seasons.endAir, type: "date" },
entriesCount: { column: seasons.entriesCount, type: "int" },
availableCount: { column: seasons.availableCount, type: "int" },
};
const seasonSort = Sort(
{
seasonNumber: seasons.seasonNumber,
startAir: seasons.startAir,
endAir: seasons.endAir,
entriesCount: seasons.entriesCount,
availableCount: seasons.availableCount,
nextRefresh: seasons.nextRefresh,
},
{
default: ["seasonNumber"],
tablePk: seasons.pk,
},
);
export const seasonsH = new Elysia({ tags: ["series"] })
.model({
season: Season,
"season-translation": SeasonTranslation,
})
.get(
"/series/:id/seasons",
async ({
params: { id },
query: { limit, after, query, sort, filter },
headers: { "accept-language": languages, ...headers },
request: { url },
status,
}) => {
const langs = processLanguages(languages);
const [serie] = await db
.select({ pk: shows.pk })
.from(shows)
.where(
and(
eq(shows.kind, "serie"),
isUuid(id) ? eq(shows.id, id) : eq(shows.slug, id),
),
)
.limit(1);
if (!serie) {
return status(404, {
status: 404,
message: `No serie with the id or slug: '${id}'.`,
});
}
const transQ = db
.selectDistinctOn([seasonTranslations.pk])
.from(seasonTranslations)
.orderBy(
seasonTranslations.pk,
sql`array_position(${sqlarr(langs)}, ${seasonTranslations.language})`,
)
.as("t");
const { pk, ...transCol } = getColumns(transQ);
const items = await db
.select({
...getColumns(seasons),
...transCol,
})
.from(seasons)
.innerJoin(transQ, eq(seasons.pk, transQ.pk))
.where(
and(
eq(seasons.showPk, serie.pk),
filter,
query ? sql`${transQ.name} %> ${query}::text` : undefined,
keysetPaginate({ after, sort }),
),
)
.orderBy(
...(query
? [sql`word_similarity(${query}::text, ${transQ.name})`]
: sortToSql(sort)),
seasons.pk,
)
.limit(limit);
return createPage(items, { url, sort, limit, headers });
},
{
detail: { description: "Get seasons of a serie" },
params: t.Object({
id: t.String({
description: "The id or slug of the serie.",
example: madeInAbyss.slug,
}),
}),
query: t.Object({
sort: seasonSort,
filter: t.Optional(Filter({ def: seasonFilters })),
query: t.Optional(t.String({ description: desc.query })),
limit: t.Integer({
minimum: 1,
maximum: 250,
default: 50,
description: "Max page size.",
}),
after: t.Optional(t.String({ description: desc.after })),
}),
headers: t.Object(
{
"accept-language": AcceptLanguage({ autoFallback: true }),
},
{ additionalProperties: true },
),
response: {
200: Page(Season),
404: {
...KError,
description: "No serie found with the given id or slug.",
},
422: KError,
},
},
);

View File

@@ -0,0 +1,209 @@
import path from "node:path";
import { getCurrentSpan, setAttributes } from "@elysiajs/opentelemetry";
import { SpanStatusCode } from "@opentelemetry/api";
import { encode } from "blurhash";
import { and, eq, is, lt, type SQL, sql } from "drizzle-orm";
import { PgColumn, type PgTable } from "drizzle-orm/pg-core";
import { version } from "package.json";
import type { PoolClient } from "pg";
import sharp from "sharp";
import { db, type Transaction } from "~/db";
import { mqueue } from "~/db/schema/mqueue";
import { unnestValues } from "~/db/utils";
import type { Image } from "~/models/utils";
import { record } from "~/otel";
import { getFile } from "~/utils";
export const imageDir = process.env.IMAGES_PATH ?? "/images";
export const defaultBlurhash = "000000";
export type ImageTask = {
id: string;
url: string;
table: string;
column: string;
};
// this will only push a task to the image downloader service and not download it instantly.
// this is both done to prevent too many requests to be sent at once and to make sure POST
// requests are not blocked by image downloading or blurhash calculation
export const enqueueOptImage = (
imgQueue: ImageTask[],
img:
| { url: string | null; column: PgColumn }
| { url: string | null; table: PgTable; column: SQL },
): Image | null => {
if (!img.url) return null;
const hasher = new Bun.CryptoHasher("sha256");
hasher.update(img.url);
const id = hasher.digest().toString("hex");
const cleanupColumn = (column: SQL) =>
// @ts-expect-error dialect is private
db.dialect.sqlToQuery(
sql.join(
column.queryChunks.map((x) => {
if (is(x, PgColumn)) {
return sql.identifier(x.name);
}
return x;
}),
),
).sql;
const message: ImageTask =
"table" in img
? {
id,
url: img.url,
// @ts-expect-error dialect is private
table: db.dialect.sqlToQuery(sql`${img.table}`).sql,
column: cleanupColumn(img.column),
}
: {
id,
url: img.url,
// @ts-expect-error dialect is private
table: db.dialect.sqlToQuery(sql`${img.column.table}`).sql,
column: sql.identifier(img.column.name).value,
};
imgQueue.push(message);
return {
id,
source: img.url,
blurhash: defaultBlurhash,
};
};
export const flushImageQueue = record(
"enqueueImages",
async (tx: Transaction, imgQueue: ImageTask[], priority: number) => {
if (!imgQueue.length) return;
await tx.insert(mqueue).select(
unnestValues(
imgQueue.map((x) => ({ kind: "image", message: x, priority })),
mqueue,
),
);
await tx.execute(sql`notify kyoo_image`);
},
);
export const processImages = record("processImages", async () => {
let running = false;
async function processAll() {
if (running) return;
running = true;
let found = true;
while (found) {
found = await processOne();
}
running = false;
}
const client = (await db.$client.connect()) as PoolClient;
client.on("notification", (evt) => {
if (evt.channel !== "kyoo_image") return;
processAll();
});
await client.query("listen kyoo_image");
// start processing old tasks
await processAll();
return () => client.release(true);
});
const processOne = record("download", async () => {
return await db.transaction(async (tx) => {
const [item] = await tx
.select()
.from(mqueue)
.for("update", { skipLocked: true })
.where(and(eq(mqueue.kind, "image"), lt(mqueue.attempt, 5)))
.orderBy(mqueue.priority, mqueue.attempt, mqueue.createdAt)
.limit(1);
if (!item) return false;
const img = item.message as ImageTask;
setAttributes({ "item.url": img.url });
try {
const blurhash = await downloadImage(img.id, img.url);
const ret: Image = { id: img.id, source: img.url, blurhash };
const table = sql.raw(img.table);
const column = sql.raw(img.column);
await tx.execute(sql`
update ${table} set ${column} = ${ret}
where ${column}->'id' = ${sql.raw(`'"${img.id}"'::jsonb`)}
`);
await tx.delete(mqueue).where(eq(mqueue.id, item.id));
} catch (err: any) {
const span = getCurrentSpan();
if (span) {
span.recordException(err);
span.setStatus({ code: SpanStatusCode.ERROR });
}
console.error("Failed to download image", img.url, err.message);
await tx
.update(mqueue)
.set({ attempt: sql`${mqueue.attempt}+1` })
.where(eq(mqueue.id, item.id));
}
return true;
});
});
async function downloadImage(id: string, url: string): Promise<string> {
const low = await getFile(path.join(imageDir, `${id}.low.jpg`))
.arrayBuffer()
.catch(() => false as const);
if (low) {
return await getBlurhash(sharp(low));
}
const resp = await fetch(url, {
headers: { "User-Agent": `Kyoo v${version}` },
});
if (!resp.ok) {
throw new Error(`Failed to fetch image: ${resp.status} ${resp.statusText}`);
}
const buf = Buffer.from(await resp.arrayBuffer());
const image = sharp(buf);
const metadata = await image.metadata();
if (!metadata.width || !metadata.height) {
throw new Error("Could not determine image dimensions");
}
const resolutions = {
low: { width: 320 },
medium: { width: 640 },
high: { width: 1280 },
};
await Promise.all(
Object.entries(resolutions).map(async ([resolution, dimensions]) => {
const buffer = await image.clone().resize(dimensions.width).toBuffer();
const file = getFile(path.join(imageDir, `${id}.${resolution}.jpg`));
await Bun.write(file, buffer, { mode: 0o660 });
}),
);
return await getBlurhash(image);
}
async function getBlurhash(image: sharp.Sharp): Promise<string> {
const { data, info } = await image
.resize(32, 32, { fit: "inside" })
.ensureAlpha()
.raw()
.toBuffer({ resolveWithObject: true });
return encode(new Uint8ClampedArray(data), info.width, info.height, 4, 3);
}

View File

@@ -0,0 +1,78 @@
import Elysia from "elysia";
import { KError } from "~/models/error";
import { SeedMovie } from "~/models/movie";
import { SeedSerie } from "~/models/serie";
import { Resource } from "~/models/utils";
import { comment } from "~/utils";
import { SeedMovieResponse, seedMovie } from "./movies";
import { SeedSerieResponse, seedSerie } from "./series";
export const seed = new Elysia()
.model({
"seed-movie": SeedMovie,
"seed-movie-response": SeedMovieResponse,
"seed-serie": SeedSerie,
"seed-serie-response": SeedSerieResponse,
})
.post(
"/movies",
async ({ body, status }) => {
const ret = await seedMovie(body);
if ("status" in ret) return status(ret.status, ret as any);
return status(ret.updated ? 200 : 201, ret);
},
{
detail: {
tags: ["movies"],
description:
"Create a movie & all related metadata. Can also link videos.",
},
body: SeedMovie,
response: {
200: {
...SeedMovieResponse,
description: "Existing movie edited/updated.",
},
201: { ...SeedMovieResponse, description: "Created a new movie." },
409: {
...Resource(),
description: comment`
A movie with the same slug but a different air date already exists.
Change the slug and re-run the request.
`,
},
422: KError,
},
},
)
.post(
"/series",
async ({ body, status }) => {
const ret = await seedSerie(body);
if ("status" in ret) return status(ret.status, ret as any);
return status(ret.updated ? 200 : 201, ret);
},
{
detail: {
tags: ["series"],
description:
"Create a series & all related metadata. Can also link videos.",
},
body: SeedSerie,
response: {
200: {
...SeedSerieResponse,
description: "Existing serie edited/updated.",
},
201: { ...SeedSerieResponse, description: "Created a new serie." },
409: {
...Resource(),
description: comment`
A serie with the same slug but a different air date already exists.
Change the slug and re-run the request.
`,
},
422: KError,
},
},
);

View File

@@ -0,0 +1,93 @@
import { sql } from "drizzle-orm";
import { db } from "~/db";
import { shows, showTranslations } from "~/db/schema";
import { conflictUpdateAllExcept } from "~/db/utils";
import type { SeedCollection } from "~/models/collections";
import type { SeedMovie } from "~/models/movie";
import type { SeedSerie } from "~/models/serie";
import { record } from "~/otel";
import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images";
type ShowTrans = typeof showTranslations.$inferInsert;
export const insertCollection = record(
"insertCollection",
async (
collection: SeedCollection | undefined,
show: (
| ({ kind: "movie" } & SeedMovie)
| ({ kind: "serie" } & SeedSerie)
) & {
nextRefresh: string;
},
) => {
if (!collection) return null;
const { translations, ...col } = collection;
return await db.transaction(async (tx) => {
const imgQueue: ImageTask[] = [];
const [ret] = await tx
.insert(shows)
.values({
kind: "collection",
status: "unknown",
startAir: show.kind === "movie" ? show.airDate : show.startAir,
endAir: show.kind === "movie" ? show.airDate : show.endAir,
nextRefresh: show.nextRefresh,
entriesCount: 0,
original: {} as any,
...col,
})
.onConflictDoUpdate({
target: shows.slug,
set: {
...conflictUpdateAllExcept(shows, [
"pk",
"id",
"slug",
"createdAt",
"startAir",
"endAir",
]),
startAir: sql`least(${shows.startAir}, excluded.start_air)`,
endAir: sql`greatest(${shows.endAir}, excluded.end_air)`,
},
})
.returning({ pk: shows.pk, id: shows.id, slug: shows.slug });
const trans: ShowTrans[] = Object.entries(translations).map(
([lang, tr]) => ({
pk: ret.pk,
language: lang,
...tr,
poster: enqueueOptImage(imgQueue, {
url: tr.poster,
column: showTranslations.poster,
}),
thumbnail: enqueueOptImage(imgQueue, {
url: tr.thumbnail,
column: showTranslations.thumbnail,
}),
logo: enqueueOptImage(imgQueue, {
url: tr.logo,
column: showTranslations.logo,
}),
banner: enqueueOptImage(imgQueue, {
url: tr.banner,
column: showTranslations.banner,
}),
}),
);
await flushImageQueue(tx, imgQueue, 100);
// we can't unnest values here because show translations contains arrays.
await tx
.insert(showTranslations)
.values(trans)
.onConflictDoUpdate({
target: [showTranslations.pk, showTranslations.language],
set: conflictUpdateAllExcept(showTranslations, ["pk", "language"]),
});
return ret;
});
},
);

View File

@@ -0,0 +1,214 @@
import { type Column, eq, type SQL, sql } from "drizzle-orm";
import { db } from "~/db";
import {
entries,
entryTranslations,
entryVideoJoin,
videos,
} from "~/db/schema";
import { conflictUpdateAllExcept, unnest, unnestValues } from "~/db/utils";
import type { SeedEntry as SEntry, SeedExtra as SExtra } from "~/models/entry";
import { record } from "~/otel";
import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images";
import { guessNextRefresh } from "../refresh";
import { updateAvailableCount, updateAvailableSince } from "./shows";
type SeedEntry = SEntry & {
video?: undefined;
};
type SeedExtra = Omit<SExtra, "kind"> & {
videos?: undefined;
translations?: undefined;
kind: "extra";
extraKind: SExtra["kind"];
};
type EntryI = typeof entries.$inferInsert;
type EntryTransI = typeof entryTranslations.$inferInsert;
const generateSlug = (
showSlug: string,
entry: SeedEntry | SeedExtra,
): string => {
switch (entry.kind) {
case "episode":
return `${showSlug}-s${entry.seasonNumber}e${entry.episodeNumber}`;
case "special":
return `${showSlug}-sp${entry.number}`;
case "movie":
if (entry.slug) return entry.slug;
return entry.order === 1 ? showSlug : `${showSlug}-${entry.order}`;
case "extra":
return entry.slug;
}
};
export const insertEntries = record(
"insertEntries",
async (
show: { pk: number; slug: string; kind: "movie" | "serie" | "collection" },
items: (SeedEntry | SeedExtra)[],
onlyExtras = false,
) => {
if (!items.length) return [];
const retEntries = await db.transaction(async (tx) => {
const imgQueue: ImageTask[] = [];
const vals: EntryI[] = items.map((seed) => {
const { translations, videos, video, ...entry } = seed;
return {
...entry,
showPk: show.pk,
slug: generateSlug(show.slug, seed),
thumbnail: enqueueOptImage(imgQueue, {
url: seed.thumbnail,
column: entries.thumbnail,
}),
nextRefresh:
entry.kind !== "extra"
? guessNextRefresh(entry.airDate ?? new Date())
: guessNextRefresh(new Date()),
episodeNumber:
entry.kind === "episode"
? entry.episodeNumber
: entry.kind === "special"
? entry.number
: undefined,
};
});
const ret = await tx
.insert(entries)
.select(unnestValues(vals, entries))
.onConflictDoUpdate({
target: entries.slug,
set: conflictUpdateAllExcept(entries, [
"pk",
"showPk",
"id",
"slug",
"createdAt",
]),
})
.returning({ pk: entries.pk, id: entries.id, slug: entries.slug });
const trans: EntryTransI[] = items.flatMap((seed, i) => {
if (seed.kind === "extra") {
return [
{
pk: ret[i].pk,
// yeah we hardcode the language to extra because if we want to support
// translations one day it won't be awkward
language: "extra",
name: seed.name,
description: null,
poster: undefined,
},
];
}
return Object.entries(seed.translations).map(([lang, tr]) => ({
// assumes ret is ordered like items.
pk: ret[i].pk,
language: lang,
...tr,
poster:
seed.kind === "movie"
? enqueueOptImage(imgQueue, {
url: (tr as any).poster,
column: entryTranslations.poster,
})
: undefined,
}));
});
await flushImageQueue(tx, imgQueue, 0);
await tx
.insert(entryTranslations)
.select(unnestValues(trans, entryTranslations))
.onConflictDoUpdate({
target: [entryTranslations.pk, entryTranslations.language],
set: conflictUpdateAllExcept(entryTranslations, ["pk", "language"]),
});
return ret;
});
const vids = items.flatMap((seed, i) => {
if (seed.kind === "extra") {
return {
videoId: seed.video,
entryPk: retEntries[i].pk,
entrySlug: retEntries[i].slug,
needRendering: false,
};
}
if (!seed.videos) return [];
return seed.videos.map((x, j) => ({
videoId: x,
entryPk: retEntries[i].pk,
entrySlug: retEntries[i].slug,
// The first video should not have a rendering.
needRendering: j !== 0 && seed.videos!.length > 1,
}));
});
if (vids.length === 0) {
// we have not added videos but we need to update the `entriesCount`
if (show.kind === "serie" && !onlyExtras)
await updateAvailableCount(db, [show.pk], true);
return retEntries.map((x) => ({ id: x.id, slug: x.slug, videos: [] }));
}
const retVideos = await db.transaction(async (tx) => {
const ret = await tx
.insert(entryVideoJoin)
.select(
db
.select({
entryPk: sql<number>`vids."entryPk"`.as("entry"),
videoPk: videos.pk,
slug: computeVideoSlug(
sql`vids."entrySlug"`,
sql`vids."needRendering"`,
),
})
.from(
unnest(vids, "vids", {
entryPk: "integer",
entrySlug: "varchar(255)",
needRendering: "boolean",
videoId: "uuid",
}),
)
.innerJoin(videos, eq(videos.id, sql`vids."videoId"`)),
)
.onConflictDoNothing()
.returning({
slug: entryVideoJoin.slug,
entryPk: entryVideoJoin.entryPk,
});
if (!onlyExtras)
await updateAvailableCount(tx, [show.pk], show.kind === "serie");
await updateAvailableSince(tx, [...new Set(vids.map((x) => x.entryPk))]);
return ret;
});
return retEntries.map((entry) => ({
id: entry.id,
slug: entry.slug,
videos: retVideos.filter((x) => x.entryPk === entry.pk),
}));
},
);
export function computeVideoSlug(entrySlug: SQL | Column, needsRendering: SQL) {
return sql<string>`
concat(
${entrySlug},
case when ${videos.part} is not null then ('-p' || ${videos.part}) else '' end,
case when ${videos.version} <> 1 then ('-v' || ${videos.version}) else '' end,
case when ${needsRendering} then concat('-', ${videos.rendering}) else '' end
)
`.as("slug");
}

View File

@@ -0,0 +1,78 @@
import { db } from "~/db";
import { seasons, seasonTranslations } from "~/db/schema";
import { conflictUpdateAllExcept, unnestValues } from "~/db/utils";
import type { SeedSeason } from "~/models/season";
import { record } from "~/otel";
import { enqueueOptImage, flushImageQueue, type ImageTask } from "../images";
import { guessNextRefresh } from "../refresh";
type SeasonI = typeof seasons.$inferInsert;
type SeasonTransI = typeof seasonTranslations.$inferInsert;
export const insertSeasons = record(
"insertSeasons",
async (show: { pk: number; slug: string }, items: SeedSeason[]) => {
if (!items.length) return [];
return db.transaction(async (tx) => {
const imgQueue: ImageTask[] = [];
const vals: SeasonI[] = items.map((x) => {
const { translations, ...season } = x;
return {
...season,
showPk: show.pk,
slug:
season.seasonNumber === 0
? `${show.slug}-specials`
: `${show.slug}-s${season.seasonNumber}`,
nextRefresh: guessNextRefresh(season.startAir ?? new Date()),
};
});
const ret = await tx
.insert(seasons)
.select(unnestValues(vals, seasons))
.onConflictDoUpdate({
target: seasons.slug,
set: conflictUpdateAllExcept(seasons, [
"pk",
"showPk",
"id",
"slug",
"createdAt",
]),
})
.returning({ pk: seasons.pk, id: seasons.id, slug: seasons.slug });
const trans: SeasonTransI[] = items.flatMap((seed, i) =>
Object.entries(seed.translations).map(([lang, tr]) => ({
// assumes ret is ordered like items.
pk: ret[i].pk,
language: lang,
...tr,
poster: enqueueOptImage(imgQueue, {
url: tr.poster,
column: seasonTranslations.poster,
}),
thumbnail: enqueueOptImage(imgQueue, {
url: tr.thumbnail,
column: seasonTranslations.thumbnail,
}),
banner: enqueueOptImage(imgQueue, {
url: tr.banner,
column: seasonTranslations.banner,
}),
})),
);
await flushImageQueue(tx, imgQueue, -10);
await tx
.insert(seasonTranslations)
.select(unnestValues(trans, seasonTranslations))
.onConflictDoUpdate({
target: [seasonTranslations.pk, seasonTranslations.language],
set: conflictUpdateAllExcept(seasonTranslations, ["pk", "language"]),
});
return ret;
});
},
);

Some files were not shown because too many files have changed in this diff Show More