mirror of
https://github.com/zoriya/Kyoo.git
synced 2025-12-06 06:36:25 +00:00
Delete v4 backend + docker fixes (#1116)
This commit is contained in:
@@ -1,3 +0,0 @@
|
||||
7e6e56a366babe17e7891a5897180efbf93c00c5
|
||||
a5638203a6ecb9f372a5a61e1c8fd443bf3a17fe
|
||||
18e301f26acd7f2e97eac26c5f48377fa13956f5
|
||||
1
.gitattributes
vendored
1
.gitattributes
vendored
@@ -1 +0,0 @@
|
||||
*.Designer.cs linguist-generated=true
|
||||
14
.github/workflows/coding-style.yml
vendored
14
.github/workflows/coding-style.yml
vendored
@@ -2,20 +2,6 @@ name: Coding Style
|
||||
on: [pull_request, workflow_dispatch]
|
||||
|
||||
jobs:
|
||||
back:
|
||||
name: "Lint Back"
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: ./back
|
||||
steps:
|
||||
- uses: actions/checkout@v5
|
||||
|
||||
- name: Check coding style
|
||||
run: |
|
||||
dotnet tool restore
|
||||
dotnet csharpier . --check
|
||||
|
||||
api:
|
||||
name: "Lint api"
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
10
.github/workflows/docker.yml
vendored
10
.github/workflows/docker.yml
vendored
@@ -19,16 +19,6 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- context: ./back
|
||||
dockerfile: Dockerfile
|
||||
label: back
|
||||
image: ${{ github.repository_owner }}/kyoo_back
|
||||
|
||||
- context: ./back
|
||||
dockerfile: Dockerfile.migrations
|
||||
label: migrations
|
||||
image: ${{ github.repository_owner }}/kyoo_migrations
|
||||
|
||||
- context: ./api
|
||||
dockerfile: Dockerfile
|
||||
label: api
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
# Authors
|
||||
Ordered by the date of the first commit.
|
||||
|
||||
* Zoe Roux ([@zoriya](http://github.com/zoriya))
|
||||
@@ -39,10 +39,7 @@ Kyoo does not have a plugin system and aim to have every features built-in (see
|
||||
|
||||
## 📺 Clients
|
||||
|
||||
Kyoo currently supports Web and Android clients, with additional platforms being thought about. Rough estimates:
|
||||
* Today: Web & Android
|
||||
* Spring 2025: Chromecast
|
||||
* Summer 2025: Android-TV
|
||||
Kyoo currently supports Web and Android clients, with additional platforms being thought about.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM oven/bun AS builder
|
||||
FROM oven/bun:debian AS builder
|
||||
WORKDIR /app
|
||||
|
||||
COPY package.json bun.lock .
|
||||
@@ -18,11 +18,13 @@ RUN bun build \
|
||||
--outfile server \
|
||||
./src/index.ts
|
||||
|
||||
FROM gcr.io/distroless/base
|
||||
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 ["./server"]
|
||||
CMD ["/app/server"]
|
||||
|
||||
216
api/bun.lock
216
api/bun.lock
@@ -5,146 +5,152 @@
|
||||
"name": "api",
|
||||
"dependencies": {
|
||||
"@elysiajs/swagger": "zoriya/elysia-swagger#build",
|
||||
"@types/bun": "^1.3.1",
|
||||
"blurhash": "^2.0.5",
|
||||
"drizzle-kit": "^0.31.1",
|
||||
"drizzle-orm": "0.43.1",
|
||||
"elysia": "^1.3.1",
|
||||
"jose": "^6.0.11",
|
||||
"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.0",
|
||||
"sharp": "^0.34.2",
|
||||
"pg": "^8.16.3",
|
||||
"sharp": "^0.34.4",
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.1.1",
|
||||
"@types/pg": "^8.15.2",
|
||||
"bun-types": "^1.2.14",
|
||||
"node-addon-api": "^8.3.1",
|
||||
"@biomejs/biome": "2.3.0",
|
||||
"@types/pg": "^8.15.5",
|
||||
},
|
||||
},
|
||||
},
|
||||
"patchedDependencies": {
|
||||
"drizzle-orm@0.43.1": "patches/drizzle-orm@0.43.1.patch",
|
||||
"drizzle-orm@0.44.7": "patches/drizzle-orm@0.44.7.patch",
|
||||
},
|
||||
"packages": {
|
||||
"@biomejs/biome": ["@biomejs/biome@2.1.1", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.1.1", "@biomejs/cli-darwin-x64": "2.1.1", "@biomejs/cli-linux-arm64": "2.1.1", "@biomejs/cli-linux-arm64-musl": "2.1.1", "@biomejs/cli-linux-x64": "2.1.1", "@biomejs/cli-linux-x64-musl": "2.1.1", "@biomejs/cli-win32-arm64": "2.1.1", "@biomejs/cli-win32-x64": "2.1.1" }, "bin": { "biome": "bin/biome" } }, "sha512-HFGYkxG714KzG+8tvtXCJ1t1qXQMzgWzfvQaUjxN6UeKv+KvMEuliInnbZLJm6DXFXwqVi6446EGI0sGBLIYng=="],
|
||||
"@biomejs/biome": ["@biomejs/biome@2.3.0", "", { "optionalDependencies": { "@biomejs/cli-darwin-arm64": "2.3.0", "@biomejs/cli-darwin-x64": "2.3.0", "@biomejs/cli-linux-arm64": "2.3.0", "@biomejs/cli-linux-arm64-musl": "2.3.0", "@biomejs/cli-linux-x64": "2.3.0", "@biomejs/cli-linux-x64-musl": "2.3.0", "@biomejs/cli-win32-arm64": "2.3.0", "@biomejs/cli-win32-x64": "2.3.0" }, "bin": { "biome": "bin/biome" } }, "sha512-shdUY5H3S3tJVUWoVWo5ua+GdPW5lRHf+b0IwZ4OC1o2zOKQECZ6l2KbU6t89FNhtd3Qx5eg5N7/UsQWGQbAFw=="],
|
||||
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.1.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-2Muinu5ok4tWxq4nu5l19el48cwCY/vzvI7Vjbkf3CYIQkjxZLyj0Ad37Jv2OtlXYaLvv+Sfu1hFeXt/JwRRXQ=="],
|
||||
"@biomejs/cli-darwin-arm64": ["@biomejs/cli-darwin-arm64@2.3.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-3cJVT0Z5pbTkoBmbjmDZTDFYxIkRcrs9sYVJbIBHU8E6qQxgXAaBfSVjjCreG56rfDuQBr43GzwzmaHPcu4vlw=="],
|
||||
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.1.1", "", { "os": "darwin", "cpu": "x64" }, "sha512-cC8HM5lrgKQXLAK+6Iz2FrYW5A62pAAX6KAnRlEyLb+Q3+Kr6ur/sSuoIacqlp1yvmjHJqjYfZjPvHWnqxoEIA=="],
|
||||
"@biomejs/cli-darwin-x64": ["@biomejs/cli-darwin-x64@2.3.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-6LIkhglh3UGjuDqJXsK42qCA0XkD1Ke4K/raFOii7QQPbM8Pia7Qj2Hji4XuF2/R78hRmEx7uKJH3t/Y9UahtQ=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-tw4BEbhAUkWPe4WBr6IX04DJo+2jz5qpPzpW/SWvqMjb9QuHY8+J0M23V8EPY/zWU4IG8Ui0XESapR1CB49Q7g=="],
|
||||
"@biomejs/cli-linux-arm64": ["@biomejs/cli-linux-arm64@2.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-uhAsbXySX7xsXahegDg5h3CDgfMcRsJvWLFPG0pjkylgBb9lErbK2C0UINW52zhwg0cPISB09lxHPxCau4e2xA=="],
|
||||
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.1.1", "", { "os": "linux", "cpu": "arm64" }, "sha512-/7FBLnTswu4jgV9ttI3AMIdDGqVEPIZd8I5u2D4tfCoj8rl9dnjrEQbAIDlWhUXdyWlFSz8JypH3swU9h9P+2A=="],
|
||||
"@biomejs/cli-linux-arm64-musl": ["@biomejs/cli-linux-arm64-musl@2.3.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-nDksoFdwZ2YrE7NiYDhtMhL2UgFn8Kb7Y0bYvnTAakHnqEdb4lKindtBc1f+xg2Snz0JQhJUYO7r9CDBosRU5w=="],
|
||||
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-3WJ1GKjU7NzZb6RTbwLB59v9cTIlzjbiFLDB0z4376TkDqoNYilJaC37IomCr/aXwuU8QKkrYoHrgpSq5ffJ4Q=="],
|
||||
"@biomejs/cli-linux-x64": ["@biomejs/cli-linux-x64@2.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-uxa8reA2s1VgoH8MhbGlCmMOt3JuSE1vJBifkh1ulaPiuk0SPx8cCdpnm9NWnTe2x/LfWInWx4sZ7muaXTPGGw=="],
|
||||
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.1.1", "", { "os": "linux", "cpu": "x64" }, "sha512-kUu+loNI3OCD2c12cUt7M5yaaSjDnGIksZwKnueubX6c/HWUyi/0mPbTBHR49Me3F0KKjWiKM+ZOjsmC+lUt9g=="],
|
||||
"@biomejs/cli-linux-x64-musl": ["@biomejs/cli-linux-x64-musl@2.3.0", "", { "os": "linux", "cpu": "x64" }, "sha512-+i9UcJwl99uAhtRQDz9jUAh+Xkb097eekxs/D9j4deWDg5/yB/jPWzISe1nBHvlzTXsdUSj0VvB4Go2DSpKIMw=="],
|
||||
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.1.1", "", { "os": "win32", "cpu": "arm64" }, "sha512-vEHK0v0oW+E6RUWLoxb2isI3rZo57OX9ZNyyGH701fZPj6Il0Rn1f5DMNyCmyflMwTnIQstEbs7n2BxYSqQx4Q=="],
|
||||
"@biomejs/cli-win32-arm64": ["@biomejs/cli-win32-arm64@2.3.0", "", { "os": "win32", "cpu": "arm64" }, "sha512-ynjmsJLIKrAjC3CCnKMMhzcnNy8dbQWjKfSU5YA0mIruTxBNMbkAJp+Pr2iV7/hFou+66ZSD/WV8hmLEmhUaXA=="],
|
||||
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.1.1", "", { "os": "win32", "cpu": "x64" }, "sha512-i2PKdn70kY++KEF/zkQFvQfX1e8SkA8hq4BgC+yE9dZqyLzB/XStY2MvwI3qswlRgnGpgncgqe0QYKVS1blksg=="],
|
||||
"@biomejs/cli-win32-x64": ["@biomejs/cli-win32-x64@2.3.0", "", { "os": "win32", "cpu": "x64" }, "sha512-zOCYmCRVkWXc9v8P7OLbLlGGMxQTKMvi+5IC4v7O8DkjLCOHRzRVK/Lno2pGZNo0lzKM60pcQOhH8HVkXMQdFg=="],
|
||||
|
||||
"@drizzle-team/brocli": ["@drizzle-team/brocli@0.10.2", "", {}, "sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w=="],
|
||||
|
||||
"@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.4.3", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ=="],
|
||||
"@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.3", "", { "os": "aix", "cpu": "ppc64" }, "sha512-W8bFfPA8DowP8l//sxjJLSLkD8iEjMc7cBVyP+u4cEv9sM7mdUCkgsj+t0n/BWPFtv7WWCN5Yzj0N6FJNUUqBQ=="],
|
||||
"@esbuild/aix-ppc64": ["@esbuild/aix-ppc64@0.25.11", "", { "os": "aix", "cpu": "ppc64" }, "sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg=="],
|
||||
|
||||
"@esbuild/android-arm": ["@esbuild/android-arm@0.25.3", "", { "os": "android", "cpu": "arm" }, "sha512-PuwVXbnP87Tcff5I9ngV0lmiSu40xw1At6i3GsU77U7cjDDB4s0X2cyFuBiDa1SBk9DnvWwnGvVaGBqoFWPb7A=="],
|
||||
"@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.3", "", { "os": "android", "cpu": "arm64" }, "sha512-XelR6MzjlZuBM4f5z2IQHK6LkK34Cvv6Rj2EntER3lwCBFdg6h2lKbtRjpTTsdEjD/WSe1q8UyPBXP1x3i/wYQ=="],
|
||||
"@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.3", "", { "os": "android", "cpu": "x64" }, "sha512-ogtTpYHT/g1GWS/zKM0cc/tIebFjm1F9Aw1boQ2Y0eUQ+J89d0jFY//s9ei9jVIlkYi8AfOjiixcLJSGNSOAdQ=="],
|
||||
"@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.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-eESK5yfPNTqpAmDfFWNsOhmIOaQA59tAcF/EfYvo5/QWQCzXn5iUSOnqt3ra3UdzBv073ykTtmeLJZGt3HhA+w=="],
|
||||
"@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.3", "", { "os": "darwin", "cpu": "x64" }, "sha512-Kd8glo7sIZtwOLcPbW0yLpKmBNWMANZhrC1r6K++uDR2zyzb6AeOYtI6udbtabmQpFaxJ8uduXMAo1gs5ozz8A=="],
|
||||
"@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.3", "", { "os": "freebsd", "cpu": "arm64" }, "sha512-EJiyS70BYybOBpJth3M0KLOus0n+RRMKTYzhYhFeMwp7e/RaajXvP+BWlmEXNk6uk+KAu46j/kaQzr6au+JcIw=="],
|
||||
"@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.3", "", { "os": "freebsd", "cpu": "x64" }, "sha512-Q+wSjaLpGxYf7zC0kL0nDlhsfuFkoN+EXrx2KSB33RhinWzejOd6AvgmP5JbkgXKmjhmpfgKZq24pneodYqE8Q=="],
|
||||
"@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.3", "", { "os": "linux", "cpu": "arm" }, "sha512-dUOVmAUzuHy2ZOKIHIKHCm58HKzFqd+puLaS424h6I85GlSDRZIA5ycBixb3mFgM0Jdh+ZOSB6KptX30DD8YOQ=="],
|
||||
"@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.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-xCUgnNYhRD5bb1C1nqrDV1PfkwgbswTTBRbAd8aH5PhYzikdf/ddtsYyMXFfGSsb/6t6QaPSzxtbfAZr9uox4A=="],
|
||||
"@esbuild/linux-arm64": ["@esbuild/linux-arm64@0.25.11", "", { "os": "linux", "cpu": "arm64" }, "sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA=="],
|
||||
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.3", "", { "os": "linux", "cpu": "ia32" }, "sha512-yplPOpczHOO4jTYKmuYuANI3WhvIPSVANGcNUeMlxH4twz/TeXuzEP41tGKNGWJjuMhotpGabeFYGAOU2ummBw=="],
|
||||
"@esbuild/linux-ia32": ["@esbuild/linux-ia32@0.25.11", "", { "os": "linux", "cpu": "ia32" }, "sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw=="],
|
||||
|
||||
"@esbuild/linux-loong64": ["@esbuild/linux-loong64@0.25.3", "", { "os": "linux", "cpu": "none" }, "sha512-P4BLP5/fjyihmXCELRGrLd793q/lBtKMQl8ARGpDxgzgIKJDRJ/u4r1A/HgpBpKpKZelGct2PGI4T+axcedf6g=="],
|
||||
"@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.3", "", { "os": "linux", "cpu": "none" }, "sha512-eRAOV2ODpu6P5divMEMa26RRqb2yUoYsuQQOuFUexUoQndm4MdpXXDBbUoKIc0iPa4aCO7gIhtnYomkn2x+bag=="],
|
||||
"@esbuild/linux-mips64el": ["@esbuild/linux-mips64el@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ=="],
|
||||
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-ZC4jV2p7VbzTlnl8nZKLcBkfzIf4Yad1SJM4ZMKYnJqZFD4rTI+pBG65u8ev4jk3/MPwY9DvGn50wi3uhdaghg=="],
|
||||
"@esbuild/linux-ppc64": ["@esbuild/linux-ppc64@0.25.11", "", { "os": "linux", "cpu": "ppc64" }, "sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw=="],
|
||||
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.3", "", { "os": "linux", "cpu": "none" }, "sha512-LDDODcFzNtECTrUUbVCs6j9/bDVqy7DDRsuIXJg6so+mFksgwG7ZVnTruYi5V+z3eE5y+BJZw7VvUadkbfg7QA=="],
|
||||
"@esbuild/linux-riscv64": ["@esbuild/linux-riscv64@0.25.11", "", { "os": "linux", "cpu": "none" }, "sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww=="],
|
||||
|
||||
"@esbuild/linux-s390x": ["@esbuild/linux-s390x@0.25.3", "", { "os": "linux", "cpu": "s390x" }, "sha512-s+w/NOY2k0yC2p9SLen+ymflgcpRkvwwa02fqmAwhBRI3SC12uiS10edHHXlVWwfAagYSY5UpmT/zISXPMW3tQ=="],
|
||||
"@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.3", "", { "os": "linux", "cpu": "x64" }, "sha512-nQHDz4pXjSDC6UfOE1Fw9Q8d6GCAd9KdvMZpfVGWSJztYCarRgSDfOVBY5xwhQXseiyxapkiSJi/5/ja8mRFFA=="],
|
||||
"@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.3", "", { "os": "none", "cpu": "arm64" }, "sha512-1QaLtOWq0mzK6tzzp0jRN3eccmN3hezey7mhLnzC6oNlJoUJz4nym5ZD7mDnS/LZQgkrhEbEiTn515lPeLpgWA=="],
|
||||
"@esbuild/netbsd-arm64": ["@esbuild/netbsd-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg=="],
|
||||
|
||||
"@esbuild/netbsd-x64": ["@esbuild/netbsd-x64@0.25.3", "", { "os": "none", "cpu": "x64" }, "sha512-i5Hm68HXHdgv8wkrt+10Bc50zM0/eonPb/a/OFVfB6Qvpiirco5gBA5bz7S2SHuU+Y4LWn/zehzNX14Sp4r27g=="],
|
||||
"@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.3", "", { "os": "openbsd", "cpu": "arm64" }, "sha512-zGAVApJEYTbOC6H/3QBr2mq3upG/LBEXr85/pTtKiv2IXcgKV0RT0QA/hSXZqSvLEpXeIxah7LczB4lkiYhTAQ=="],
|
||||
"@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.3", "", { "os": "openbsd", "cpu": "x64" }, "sha512-fpqctI45NnCIDKBH5AXQBsD0NDPbEFczK98hk/aa6HJxbl+UtLkJV2+Bvy5hLSLk3LHmqt0NTkKNso1A9y1a4w=="],
|
||||
"@esbuild/openbsd-x64": ["@esbuild/openbsd-x64@0.25.11", "", { "os": "openbsd", "cpu": "x64" }, "sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw=="],
|
||||
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.3", "", { "os": "sunos", "cpu": "x64" }, "sha512-ROJhm7d8bk9dMCUZjkS8fgzsPAZEjtRJqCAmVgB0gMrvG7hfmPmz9k1rwO4jSiblFjYmNvbECL9uhaPzONMfgA=="],
|
||||
"@esbuild/openharmony-arm64": ["@esbuild/openharmony-arm64@0.25.11", "", { "os": "none", "cpu": "arm64" }, "sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ=="],
|
||||
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.3", "", { "os": "win32", "cpu": "arm64" }, "sha512-YWcow8peiHpNBiIXHwaswPnAXLsLVygFwCB3A7Bh5jRkIBFWHGmNQ48AlX4xDvQNoMZlPYzjVOQDYEzWCqufMQ=="],
|
||||
"@esbuild/sunos-x64": ["@esbuild/sunos-x64@0.25.11", "", { "os": "sunos", "cpu": "x64" }, "sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA=="],
|
||||
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.3", "", { "os": "win32", "cpu": "ia32" }, "sha512-qspTZOIGoXVS4DpNqUYUs9UxVb04khS1Degaw/MnfMe7goQ3lTfQ13Vw4qY/Nj0979BGvMRpAYbs/BAxEvU8ew=="],
|
||||
"@esbuild/win32-arm64": ["@esbuild/win32-arm64@0.25.11", "", { "os": "win32", "cpu": "arm64" }, "sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q=="],
|
||||
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.3", "", { "os": "win32", "cpu": "x64" }, "sha512-ICgUR+kPimx0vvRzf+N/7L7tVSQeE3BYY+NhHRHXS1kBuPO7z2+7ea2HbhDyZdTephgvNvKrlDDKUexuCVBVvg=="],
|
||||
"@esbuild/win32-ia32": ["@esbuild/win32-ia32@0.25.11", "", { "os": "win32", "cpu": "ia32" }, "sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA=="],
|
||||
|
||||
"@img/sharp-darwin-arm64": ["@img/sharp-darwin-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-arm64": "1.1.0" }, "os": "darwin", "cpu": "arm64" }, "sha512-OfXHZPppddivUJnqyKoi5YVeHRkkNE2zUFT2gbpKxp/JZCFYEYubnMg+gOp6lWfasPrTS+KPosKqdI+ELYVDtg=="],
|
||||
"@esbuild/win32-x64": ["@esbuild/win32-x64@0.25.11", "", { "os": "win32", "cpu": "x64" }, "sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA=="],
|
||||
|
||||
"@img/sharp-darwin-x64": ["@img/sharp-darwin-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-darwin-x64": "1.1.0" }, "os": "darwin", "cpu": "x64" }, "sha512-dYvWqmjU9VxqXmjEtjmvHnGqF8GrVjM2Epj9rJ6BUIXvk8slvNDJbhGFvIoXzkDhrJC2jUxNLz/GUjjvSzfw+g=="],
|
||||
"@img/colour": ["@img/colour@1.0.0", "", {}, "sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw=="],
|
||||
|
||||
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.1.0", "", { "os": "darwin", "cpu": "arm64" }, "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA=="],
|
||||
"@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-libvips-darwin-x64": ["@img/sharp-libvips-darwin-x64@1.1.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ=="],
|
||||
"@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-linux-arm": ["@img/sharp-libvips-linux-arm@1.1.0", "", { "os": "linux", "cpu": "arm" }, "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA=="],
|
||||
"@img/sharp-libvips-darwin-arm64": ["@img/sharp-libvips-darwin-arm64@1.2.3", "", { "os": "darwin", "cpu": "arm64" }, "sha512-QzWAKo7kpHxbuHqUC28DZ9pIKpSi2ts2OJnoIGI26+HMgq92ZZ4vk8iJd4XsxN+tYfNJxzH6W62X5eTcsBymHw=="],
|
||||
|
||||
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew=="],
|
||||
"@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-ppc64": ["@img/sharp-libvips-linux-ppc64@1.1.0", "", { "os": "linux", "cpu": "ppc64" }, "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ=="],
|
||||
"@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-s390x": ["@img/sharp-libvips-linux-s390x@1.1.0", "", { "os": "linux", "cpu": "s390x" }, "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA=="],
|
||||
"@img/sharp-libvips-linux-arm64": ["@img/sharp-libvips-linux-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ=="],
|
||||
|
||||
"@img/sharp-libvips-linux-x64": ["@img/sharp-libvips-linux-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q=="],
|
||||
"@img/sharp-libvips-linux-ppc64": ["@img/sharp-libvips-linux-ppc64@1.2.3", "", { "os": "linux", "cpu": "ppc64" }, "sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg=="],
|
||||
|
||||
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.1.0", "", { "os": "linux", "cpu": "arm64" }, "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w=="],
|
||||
"@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-linuxmusl-x64": ["@img/sharp-libvips-linuxmusl-x64@1.1.0", "", { "os": "linux", "cpu": "x64" }, "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A=="],
|
||||
"@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-linux-arm": ["@img/sharp-linux-arm@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm": "1.1.0" }, "os": "linux", "cpu": "arm" }, "sha512-0DZzkvuEOqQUP9mo2kjjKNok5AmnOr1jB2XYjkaoNRwpAYMDzRmAqUIa1nRi58S2WswqSfPOWLNOr0FDT3H5RQ=="],
|
||||
"@img/sharp-libvips-linuxmusl-arm64": ["@img/sharp-libvips-linuxmusl-arm64@1.2.3", "", { "os": "linux", "cpu": "arm64" }, "sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw=="],
|
||||
|
||||
"@img/sharp-linux-arm64": ["@img/sharp-linux-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-D8n8wgWmPDakc83LORcfJepdOSN6MvWNzzz2ux0MnIbOqdieRZwVYY32zxVx+IFUT8er5KPcyU3XXsn+GzG/0Q=="],
|
||||
"@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-s390x": ["@img/sharp-linux-s390x@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-s390x": "1.1.0" }, "os": "linux", "cpu": "s390x" }, "sha512-EGZ1xwhBI7dNISwxjChqBGELCWMGDvmxZXKjQRuqMrakhO8QoMgqCrdjnAqJq/CScxfRn+Bb7suXBElKQpPDiw=="],
|
||||
"@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-x64": ["@img/sharp-linux-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linux-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-sD7J+h5nFLMMmOXYH4DD9UtSNBD05tWSSdWAcEyzqW8Cn5UxXvsHAxmxSesYUsTOBmUnjtxghKDl15EvfqLFbQ=="],
|
||||
"@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-linuxmusl-arm64": ["@img/sharp-linuxmusl-arm64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" }, "os": "linux", "cpu": "arm64" }, "sha512-NEE2vQ6wcxYav1/A22OOxoSOGiKnNmDzCYFOZ949xFmrWZOVII1Bp3NqVVpvj+3UeHMFyN5eP/V5hzViQ5CZNA=="],
|
||||
"@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-linuxmusl-x64": ["@img/sharp-linuxmusl-x64@0.34.2", "", { "optionalDependencies": { "@img/sharp-libvips-linuxmusl-x64": "1.1.0" }, "os": "linux", "cpu": "x64" }, "sha512-DOYMrDm5E6/8bm/yQLCWyuDJwUnlevR8xtF8bs+gjZ7cyUNYXiSf/E8Kp0Ss5xasIaXSHzb888V1BE4i1hFhAA=="],
|
||||
"@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-wasm32": ["@img/sharp-wasm32@0.34.2", "", { "dependencies": { "@emnapi/runtime": "^1.4.3" }, "cpu": "none" }, "sha512-/VI4mdlJ9zkaq53MbIG6rZY+QRN3MLbR6usYlgITEzi4Rpx5S6LFKsycOQjkOGmqTNmkIdLjEvooFKwww6OpdQ=="],
|
||||
"@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-win32-arm64": ["@img/sharp-win32-arm64@0.34.2", "", { "os": "win32", "cpu": "arm64" }, "sha512-cfP/r9FdS63VA5k0xiqaNaEoGxBg9k7uE+RQGzuK9fHt7jib4zAVVseR9LsE4gJcNWgT6APKMNnCcnyOtmSEUQ=="],
|
||||
"@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-win32-ia32": ["@img/sharp-win32-ia32@0.34.2", "", { "os": "win32", "cpu": "ia32" }, "sha512-QLjGGvAbj0X/FXl8n1WbtQ6iVBpWU7JO94u/P2M4a8CFYsvQi4GW2mRy/JqkRx0qpBzaOdKJKw8uc930EX2AHw=="],
|
||||
"@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-win32-x64": ["@img/sharp-win32-x64@0.34.2", "", { "os": "win32", "cpu": "x64" }, "sha512-aUdT6zEYtDKCaxkofmmJDJYGCf0+pJg3eU9/oBuqvEeoB9dKI6ZLc/1iLJCTuJQDO4ptntAlkUmHgGjyuobZbw=="],
|
||||
"@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=="],
|
||||
|
||||
"@scalar/openapi-types": ["@scalar/openapi-types@0.1.9", "", {}, "sha512-HQQudOSQBU7ewzfnBW9LhDmBE2XOJgSfwrh5PlUB7zJup/kaRkBGNgV2wMjNz9Af/uztiU/xNrO179FysmUT+g=="],
|
||||
|
||||
@@ -158,9 +164,13 @@
|
||||
|
||||
"@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.2", "", { "dependencies": { "@types/node": "*", "pg-protocol": "*", "pg-types": "^4.0.1" } }, "sha512-+BKxo5mM6+/A1soSHBI7ufUglqYXntChLDyTbvcAn1Lawi9J7J9Ok3jt6w7I0+T/UDJ4CyhHk66+GZbwmkYxSg=="],
|
||||
"@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=="],
|
||||
|
||||
"@unhead/schema": ["@unhead/schema@1.11.20", "", { "dependencies": { "hookable": "^5.5.3", "zhead": "^2.2.4" } }, "sha512-0zWykKAaJdm+/Y7yi/Yds20PrUK7XabLe9c3IRcjnwYmSWY6z0Cr19VIs3ozCj8P+GhR+/TI2mwtGlueCEYouA=="],
|
||||
|
||||
@@ -168,35 +178,29 @@
|
||||
|
||||
"buffer-from": ["buffer-from@1.1.2", "", {}, "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ=="],
|
||||
|
||||
"bun-types": ["bun-types@1.2.14", "", { "dependencies": { "@types/node": "*" } }, "sha512-Kuh4Ub28ucMRWeiUUWMHsT9Wcbr4H3kLIO72RZZElSDxSu7vpetRvxIUDUaW6QtaIeixIpm7OXtNnZPf82EzwA=="],
|
||||
"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=="],
|
||||
|
||||
"color": ["color@4.2.3", "", { "dependencies": { "color-convert": "^2.0.1", "color-string": "^1.9.0" } }, "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A=="],
|
||||
|
||||
"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=="],
|
||||
|
||||
"color-string": ["color-string@1.9.1", "", { "dependencies": { "color-name": "^1.0.0", "simple-swizzle": "^0.2.2" } }, "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg=="],
|
||||
|
||||
"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.0.4", "", {}, "sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA=="],
|
||||
"detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="],
|
||||
|
||||
"drizzle-kit": ["drizzle-kit@0.31.1", "", { "dependencies": { "@drizzle-team/brocli": "^0.10.2", "@esbuild-kit/esm-loader": "^2.5.5", "esbuild": "^0.25.2", "esbuild-register": "^3.5.0" }, "bin": { "drizzle-kit": "bin.cjs" } }, "sha512-PUjYKWtzOzPtdtQlTHQG3qfv4Y0XT8+Eas6UbxCmxTj7qgMf+39dDujf1BP1I+qqZtw9uzwTh8jYtkMuCq+B0Q=="],
|
||||
"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.43.1", "", { "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": "*", "@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", "@vercel/postgres", "@xata.io/client", "better-sqlite3", "bun-types", "expo-sqlite", "gel", "knex", "kysely", "mysql2", "pg", "postgres", "sql.js", "sqlite3"] }, "sha512-dUcDaZtE/zN4RV/xqGrVSMpnEczxd5cIaoDeor7Zst9wOe/HzC/7eAaulywWGYXdDEc9oBPMjayVEDg0ziTLJA=="],
|
||||
"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.3.1", "", { "dependencies": { "cookie": "^1.0.2", "exact-mirror": "0.1.2", "fast-decode-uri-component": "^1.0.1" }, "optionalDependencies": { "@sinclair/typebox": "^0.34.33", "openapi-types": "^12.1.3" }, "peerDependencies": { "file-type": ">= 20.0.0", "typescript": ">= 5.0.0" } }, "sha512-En41P6cDHcHtQ0nvfsn9ayB+8ahQJqG1nzvPX8FVZjOriFK/RtZPQBtXMfZDq/AsVIk7JFZGFEtAVEmztNJVhQ=="],
|
||||
"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=="],
|
||||
|
||||
"esbuild": ["esbuild@0.25.3", "", { "optionalDependencies": { "@esbuild/aix-ppc64": "0.25.3", "@esbuild/android-arm": "0.25.3", "@esbuild/android-arm64": "0.25.3", "@esbuild/android-x64": "0.25.3", "@esbuild/darwin-arm64": "0.25.3", "@esbuild/darwin-x64": "0.25.3", "@esbuild/freebsd-arm64": "0.25.3", "@esbuild/freebsd-x64": "0.25.3", "@esbuild/linux-arm": "0.25.3", "@esbuild/linux-arm64": "0.25.3", "@esbuild/linux-ia32": "0.25.3", "@esbuild/linux-loong64": "0.25.3", "@esbuild/linux-mips64el": "0.25.3", "@esbuild/linux-ppc64": "0.25.3", "@esbuild/linux-riscv64": "0.25.3", "@esbuild/linux-s390x": "0.25.3", "@esbuild/linux-x64": "0.25.3", "@esbuild/netbsd-arm64": "0.25.3", "@esbuild/netbsd-x64": "0.25.3", "@esbuild/openbsd-arm64": "0.25.3", "@esbuild/openbsd-x64": "0.25.3", "@esbuild/sunos-x64": "0.25.3", "@esbuild/win32-arm64": "0.25.3", "@esbuild/win32-ia32": "0.25.3", "@esbuild/win32-x64": "0.25.3" }, "bin": { "esbuild": "bin/esbuild" } }, "sha512-qKA6Pvai73+M2FtftpNKRxJ78GIjmFXFxd/1DVBqGo/qNhLSfv+G12n9pNoWdytJC8U00TrViOwpjT0zgqQS8Q=="],
|
||||
"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=="],
|
||||
|
||||
"exact-mirror": ["exact-mirror@0.1.2", "", { "peerDependencies": { "@sinclair/typebox": "^0.34.15" }, "optionalPeers": ["@sinclair/typebox"] }, "sha512-wFCPCDLmHbKGUb8TOi/IS7jLsgR8WVDGtDK3CzcB4Guf/weq7G+I+DkXiRSZfbemBFOxOINKpraM6ml78vo8Zw=="],
|
||||
"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=="],
|
||||
|
||||
@@ -210,18 +214,16 @@
|
||||
|
||||
"ieee754": ["ieee754@1.2.1", "", {}, "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA=="],
|
||||
|
||||
"is-arrayish": ["is-arrayish@0.3.2", "", {}, "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ=="],
|
||||
"jose": ["jose@6.1.0", "", {}, "sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA=="],
|
||||
|
||||
"jose": ["jose@6.0.11", "", {}, "sha512-QxG7EaliDARm1O1S8BGakqncGT9s25bKL1WSf6/oa17Tkqwi8D2ZNglqCF+DsYF88/rV66Q/Q2mFAy697E1DUg=="],
|
||||
"memoirist": ["memoirist@0.4.0", "", {}, "sha512-zxTgA0mSYELa66DimuNQDvyLq36AwDlTuVRbnQtB+VuTcKWm5Qc4z3WkSpgsFWHNhexqkIooqpv4hdcqrX5Nmg=="],
|
||||
|
||||
"ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="],
|
||||
|
||||
"node-addon-api": ["node-addon-api@8.3.1", "", {}, "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA=="],
|
||||
"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=="],
|
||||
|
||||
"obuf": ["obuf@1.1.2", "", {}, "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg=="],
|
||||
|
||||
"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=="],
|
||||
@@ -230,33 +232,29 @@
|
||||
|
||||
"peek-readable": ["peek-readable@7.0.0", "", {}, "sha512-nri2TO5JE3/mRryik9LlHFT53cgHfRK0Lt0BAZQXku/AW3E6XLt2GaY8siWi7dvW/m1z0ecn+J+bpDa9ZN3IsQ=="],
|
||||
|
||||
"pg": ["pg@8.16.0", "", { "dependencies": { "pg-connection-string": "^2.9.0", "pg-pool": "^3.10.0", "pg-protocol": "^1.10.0", "pg-types": "2.2.0", "pgpass": "1.0.5" }, "optionalDependencies": { "pg-cloudflare": "^1.2.5" }, "peerDependencies": { "pg-native": ">=3.0.1" }, "optionalPeers": ["pg-native"] }, "sha512-7SKfdvP8CTNXjMUzfcVTaI+TDzBEeaUnVwiVGZQD1Hh33Kpev7liQba9uLd4CfN8r9mCVsD0JIpq03+Unpz+kg=="],
|
||||
"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.5", "", {}, "sha512-OOX22Vt0vOSRrdoUPKJ8Wi2OpE/o/h9T8X1s4qSkCedbNah9ei2W2765be8iMVxQUsvgT7zIAT2eIa9fs5+vtg=="],
|
||||
"pg-cloudflare": ["pg-cloudflare@1.2.7", "", {}, "sha512-YgCtzMH0ptvZJslLM1ffsY4EuGaU0cx4XSdXLRFae8bPP4dS5xL1tNB3k2o/N64cHJpwU7dxKli/nZ2lUa5fLg=="],
|
||||
|
||||
"pg-connection-string": ["pg-connection-string@2.9.0", "", {}, "sha512-P2DEBKuvh5RClafLngkAuGe9OUlFV7ebu8w1kmaaOgPcpJd1RIFh7otETfI6hAR8YupOLFTY7nuvvIn7PLciUQ=="],
|
||||
"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-numeric": ["pg-numeric@1.0.2", "", {}, "sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw=="],
|
||||
|
||||
"pg-pool": ["pg-pool@3.10.0", "", { "peerDependencies": { "pg": ">=8.0" } }, "sha512-DzZ26On4sQ0KmqnO34muPcmKbhrjmyiO4lCCR0VwEd7MjmiKf5NTg/6+apUEu0NF7ESa37CGzFxH513CoUmWnA=="],
|
||||
"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@4.0.2", "", { "dependencies": { "pg-int8": "1.0.1", "pg-numeric": "1.0.2", "postgres-array": "~3.0.1", "postgres-bytea": "~3.0.0", "postgres-date": "~2.1.0", "postgres-interval": "^3.0.0", "postgres-range": "^1.1.1" } }, "sha512-cRL3JpS3lKMGsKaWndugWQoLOCoP+Cic8oseVcbr0qhPzYD5DWXK+RZ9LY9wxRf7RQia4SCwQlXk0q6FCPrVng=="],
|
||||
"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@3.0.4", "", {}, "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ=="],
|
||||
"postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
|
||||
|
||||
"postgres-bytea": ["postgres-bytea@3.0.0", "", { "dependencies": { "obuf": "~1.1.2" } }, "sha512-CNd4jim9RFPkObHSjVHlVrxoVQXz7quwNFpz7RY1okNNme49+sVyiTvTRobiLV548Hx/hb1BG+iE7h9493WzFw=="],
|
||||
"postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="],
|
||||
|
||||
"postgres-date": ["postgres-date@2.1.0", "", {}, "sha512-K7Juri8gtgXVcDfZttFKVmhglp7epKb1K4pgrkLxehjqkrgPhfG6OO8LHLkfaqkbpjNRnra018XwAr1yQFWGcA=="],
|
||||
"postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
|
||||
|
||||
"postgres-interval": ["postgres-interval@3.0.0", "", {}, "sha512-BSNDnbyZCXSxgA+1f5UU2GmwhoI0aU5yMxRGO8CdFEcY2BQF9xm/7MqKnYoM1nJDk8nONNWDk9WeSmePFhQdlw=="],
|
||||
|
||||
"postgres-range": ["postgres-range@1.1.4", "", {}, "sha512-i/hbxIE9803Alj/6ytL7UHQxRvZkI9O4Sy+J3HGc4F4oo/2eQAjTSNJ0bfxyse3bH0nuVesCk+3IRLaMtG3H6w=="],
|
||||
"postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
|
||||
|
||||
"resolve-pkg-maps": ["resolve-pkg-maps@1.0.0", "", {}, "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw=="],
|
||||
|
||||
@@ -264,9 +262,7 @@
|
||||
|
||||
"shallowequal": ["shallowequal@1.1.0", "", {}, "sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ=="],
|
||||
|
||||
"sharp": ["sharp@0.34.2", "", { "dependencies": { "color": "^4.2.3", "detect-libc": "^2.0.4", "semver": "^7.7.2" }, "optionalDependencies": { "@img/sharp-darwin-arm64": "0.34.2", "@img/sharp-darwin-x64": "0.34.2", "@img/sharp-libvips-darwin-arm64": "1.1.0", "@img/sharp-libvips-darwin-x64": "1.1.0", "@img/sharp-libvips-linux-arm": "1.1.0", "@img/sharp-libvips-linux-arm64": "1.1.0", "@img/sharp-libvips-linux-ppc64": "1.1.0", "@img/sharp-libvips-linux-s390x": "1.1.0", "@img/sharp-libvips-linux-x64": "1.1.0", "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", "@img/sharp-libvips-linuxmusl-x64": "1.1.0", "@img/sharp-linux-arm": "0.34.2", "@img/sharp-linux-arm64": "0.34.2", "@img/sharp-linux-s390x": "0.34.2", "@img/sharp-linux-x64": "0.34.2", "@img/sharp-linuxmusl-arm64": "0.34.2", "@img/sharp-linuxmusl-x64": "0.34.2", "@img/sharp-wasm32": "0.34.2", "@img/sharp-win32-arm64": "0.34.2", "@img/sharp-win32-ia32": "0.34.2", "@img/sharp-win32-x64": "0.34.2" } }, "sha512-lszvBmB9QURERtyKT2bNmsgxXK0ShJrL/fvqlonCo7e6xBF8nT8xU6pW+PMIbLsz0RxQk3rgH9kd8UmvOzlMJg=="],
|
||||
|
||||
"simple-swizzle": ["simple-swizzle@0.2.2", "", { "dependencies": { "is-arrayish": "^0.3.1" } }, "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg=="],
|
||||
"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=="],
|
||||
|
||||
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
||||
|
||||
@@ -280,8 +276,6 @@
|
||||
|
||||
"tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="],
|
||||
|
||||
"typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="],
|
||||
|
||||
"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=="],
|
||||
@@ -294,7 +288,7 @@
|
||||
|
||||
"@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-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=="],
|
||||
"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=="],
|
||||
|
||||
@@ -339,13 +333,5 @@
|
||||
"@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=="],
|
||||
|
||||
"pg/pg-types/postgres-array": ["postgres-array@2.0.0", "", {}, "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA=="],
|
||||
|
||||
"pg/pg-types/postgres-bytea": ["postgres-bytea@1.0.0", "", {}, "sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w=="],
|
||||
|
||||
"pg/pg-types/postgres-date": ["postgres-date@1.0.7", "", {}, "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q=="],
|
||||
|
||||
"pg/pg-types/postgres-interval": ["postgres-interval@1.2.0", "", { "dependencies": { "xtend": "^4.0.0" } }, "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ=="],
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,23 +10,23 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@elysiajs/swagger": "zoriya/elysia-swagger#build",
|
||||
"@types/bun": "^1.3.1",
|
||||
"blurhash": "^2.0.5",
|
||||
"drizzle-kit": "^0.31.1",
|
||||
"drizzle-orm": "0.43.1",
|
||||
"elysia": "^1.3.1",
|
||||
"jose": "^6.0.11",
|
||||
"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.0",
|
||||
"sharp": "^0.34.2"
|
||||
"pg": "^8.16.3",
|
||||
"sharp": "^0.34.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@biomejs/biome": "2.1.1",
|
||||
"@types/pg": "^8.15.2",
|
||||
"bun-types": "^1.2.14",
|
||||
"node-addon-api": "^8.3.1"
|
||||
"@biomejs/biome": "2.3.0",
|
||||
"@types/pg": "^8.15.5"
|
||||
},
|
||||
"module": "src/index.js",
|
||||
"patchedDependencies": {
|
||||
"drizzle-orm@0.43.1": "patches/drizzle-orm@0.43.1.patch"
|
||||
"drizzle-orm@0.44.7": "patches/drizzle-orm@0.44.7.patch"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
diff --git a/pg-core/dialect.cjs b/pg-core/dialect.cjs
|
||||
index a0ef03142f21d319376bc50070ff7fdcd4d18132..45fc94e5a7c3fa4c201e636dd227122164e1bd02 100644
|
||||
index d776a1fb503f35b5e53c6d3c1c086efa8230ea94..86541bf408e4955029c65be59d7b8ec98bb6e914 100644
|
||||
--- a/pg-core/dialect.cjs
|
||||
+++ b/pg-core/dialect.cjs
|
||||
@@ -348,7 +348,14 @@ class PgDialect {
|
||||
@@ -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];
|
||||
@@ -19,30 +19,30 @@ index a0ef03142f21d319376bc50070ff7fdcd4d18132..45fc94e5a7c3fa4c201e636dd2271221
|
||||
([, column]) => import_sql2.sql.identifier(this.casing.getColumnCasing(column))
|
||||
);
|
||||
diff --git a/pg-core/dialect.js b/pg-core/dialect.js
|
||||
index 120aaed9c3e4ae0a24653893379b98506c866f6f..48df463c0a6d5864fe2c324c8f86432860e50e00 100644
|
||||
index 74a16c9e86fe3a89ced32af44af0a72f1cf43cf6..08f820d46a040c315fed40b8b36d94d094174425 100644
|
||||
--- a/pg-core/dialect.js
|
||||
+++ b/pg-core/dialect.js
|
||||
@@ -346,7 +346,14 @@ class PgDialect {
|
||||
@@ -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());
|
||||
+ 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 08bb0d7485ebf997e3f081e2254ea8fd8bc20f65..20c8036374a1f25f7c5880c40e8d3c42c05f3eee 100644
|
||||
index 22e0a4b4ad7ac64b065fc540416c6ed15ff4336b..fd590a6a3feb48c9f1894a0619b09ca6a5d22a5c 100644
|
||||
--- a/pg-core/query-builders/insert.cjs
|
||||
+++ b/pg-core/query-builders/insert.cjs
|
||||
@@ -75,11 +75,6 @@ class PgInsertBuilder {
|
||||
@@ -76,11 +76,6 @@ class PgInsertBuilder {
|
||||
}
|
||||
select(selectQuery) {
|
||||
const select = typeof selectQuery === "function" ? selectQuery(new import_query_builder.QueryBuilder()) : selectQuery;
|
||||
@@ -55,10 +55,10 @@ index 08bb0d7485ebf997e3f081e2254ea8fd8bc20f65..20c8036374a1f25f7c5880c40e8d3c42
|
||||
}
|
||||
}
|
||||
diff --git a/pg-core/query-builders/insert.js b/pg-core/query-builders/insert.js
|
||||
index 0fc8eeb80f4a5512f6c84f3d596832623a33b748..998e2ab0bfe3f322bf268a01f71ebd06c57d4d07 100644
|
||||
index 60a8bb0d1c22b890bd8fbf4c85d5df41ca42444c..8754d0f2923f905816016c42f339c3e9097b4128 100644
|
||||
--- a/pg-core/query-builders/insert.js
|
||||
+++ b/pg-core/query-builders/insert.js
|
||||
@@ -51,11 +51,6 @@ class PgInsertBuilder {
|
||||
@@ -52,11 +52,6 @@ class PgInsertBuilder {
|
||||
}
|
||||
select(selectQuery) {
|
||||
const select = typeof selectQuery === "function" ? selectQuery(new QueryBuilder()) : selectQuery;
|
||||
@@ -18,6 +18,16 @@ import type { KError } from "./models/error";
|
||||
|
||||
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") {
|
||||
@@ -34,25 +44,21 @@ export const base = new Elysia({ name: "base" })
|
||||
details: details,
|
||||
} as KError;
|
||||
}
|
||||
if (code === "INTERNAL_SERVER_ERROR") {
|
||||
console.error(error);
|
||||
return {
|
||||
status: 500,
|
||||
message: error.message,
|
||||
details: error,
|
||||
} as KError;
|
||||
}
|
||||
if (code === "NOT_FOUND") {
|
||||
return error;
|
||||
}
|
||||
console.error(code, error);
|
||||
return 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") }) },
|
||||
})
|
||||
.as("scoped");
|
||||
.as("global");
|
||||
|
||||
export const prefix = "/api";
|
||||
export const handlers = new Elysia({ prefix })
|
||||
|
||||
@@ -148,8 +148,13 @@ export const jsonbBuildObject = <T>(select: JsonFields) => {
|
||||
};
|
||||
|
||||
export const isUniqueConstraint = (e: unknown): boolean => {
|
||||
if (typeof e !== "object" || !e || !("cause" in e)) return false;
|
||||
const cause = e.cause;
|
||||
return (
|
||||
typeof e === "object" && e != null && "code" in e && e.code === "23505"
|
||||
typeof cause === "object" &&
|
||||
cause != null &&
|
||||
"code" in cause &&
|
||||
cause.code === "23505"
|
||||
);
|
||||
};
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ export const Sort = (
|
||||
),
|
||||
)
|
||||
.Decode((sort: string[]): Sort => {
|
||||
if (!Array.isArray(sort)) sort = [sort];
|
||||
const random = sort.find((x) => x.startsWith("random"));
|
||||
if (random) {
|
||||
const seed = random.includes(":")
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
{
|
||||
"version": 1,
|
||||
"isRoot": true,
|
||||
"tools": {
|
||||
"dotnet-ef": {
|
||||
"version": "8.0.21",
|
||||
"commands": [
|
||||
"dotnet-ef"
|
||||
]
|
||||
},
|
||||
"csharpier": {
|
||||
"version": "0.28.2",
|
||||
"commands": [
|
||||
"dotnet-csharpier"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
Dockerfile
|
||||
Dockerfile.dev
|
||||
Dockerfile.*
|
||||
.dockerignore
|
||||
.gitignore
|
||||
docker-compose.yml
|
||||
README.md
|
||||
**/build
|
||||
**/dist
|
||||
**/bin
|
||||
**/obj
|
||||
out
|
||||
docs
|
||||
tests
|
||||
front
|
||||
video
|
||||
nginx.conf.template
|
||||
@@ -1,99 +0,0 @@
|
||||
root = false
|
||||
|
||||
[*]
|
||||
charset = utf-8
|
||||
end_of_line = lf
|
||||
trim_trailing_whitespace = true
|
||||
insert_final_newline = true
|
||||
indent_style = tab
|
||||
indent_size = tab
|
||||
smart_tab = true
|
||||
|
||||
[*.cs]
|
||||
csharp_prefer_braces = false
|
||||
dotnet_diagnostic.IDE0046.severity = none
|
||||
dotnet_diagnostic.IDE0055.severity = none
|
||||
dotnet_diagnostic.IDE0058.severity = none
|
||||
dotnet_diagnostic.IDE0130.severity = none
|
||||
|
||||
# Convert to file-scoped namespace
|
||||
csharp_style_namespace_declarations = file_scoped:warning
|
||||
# Sort using and Import directives with System.* appearing first
|
||||
dotnet_sort_system_directives_first = true
|
||||
csharp_using_directive_placement = outside_namespace:warning
|
||||
# Avoid "this." if not necessary
|
||||
dotnet_style_qualification_for_field = false:suggestion
|
||||
dotnet_style_qualification_for_property = false:suggestion
|
||||
dotnet_style_qualification_for_method = false:suggestion
|
||||
dotnet_style_qualification_for_event = false:suggestion
|
||||
# Use language keywords instead of framework type names for type references
|
||||
dotnet_style_predefined_type_for_locals_parameters_members = true:suggestion
|
||||
dotnet_style_predefined_type_for_member_access = true:suggestion
|
||||
# Suggest more modern language features when available
|
||||
dotnet_style_object_initializer = true:suggestion
|
||||
dotnet_style_collection_initializer = true:suggestion
|
||||
dotnet_style_coalesce_expression = true:suggestion
|
||||
dotnet_style_null_propagation = true:suggestion
|
||||
dotnet_style_explicit_tuple_names = true:suggestion
|
||||
csharp_style_pattern_matching_over_is_with_cast_check = true:suggestion
|
||||
csharp_style_pattern_matching_over_as_with_null_check = true:suggestion
|
||||
csharp_style_inlined_variable_declaration = true:suggestion
|
||||
csharp_style_conditional_delegate_call = true:suggestion
|
||||
dotnet_style_prefer_auto_properties = true
|
||||
dotnet_style_prefer_conditional_expression_over_assignment = true
|
||||
dotnet_style_prefer_conditional_expression_over_return = true
|
||||
# Disable strange throw.
|
||||
csharp_style_throw_expression = false:suggestion
|
||||
# Forbid "var" everywhere
|
||||
csharp_style_var_for_built_in_types = false:suggestion
|
||||
csharp_style_var_when_type_is_apparent = false:suggestion
|
||||
csharp_style_var_elsewhere = false:suggestion
|
||||
# Prefer method-like constructs to have a block body
|
||||
csharp_style_expression_bodied_methods = false:none
|
||||
csharp_style_expression_bodied_constructors = false:none
|
||||
csharp_style_expression_bodied_operators = false:none
|
||||
# Prefer property-like constructs to have an expression-body
|
||||
csharp_style_expression_bodied_properties = true:none
|
||||
csharp_style_expression_bodied_indexers = true:none
|
||||
csharp_style_expression_bodied_accessors = true:none
|
||||
# Newline settings
|
||||
csharp_new_line_before_open_brace = all
|
||||
csharp_new_line_before_else = true
|
||||
csharp_new_line_before_catch = true
|
||||
csharp_new_line_before_finally = true
|
||||
csharp_new_line_before_members_in_object_initializers = false
|
||||
csharp_new_line_before_members_in_anonymous_types = true
|
||||
# Indentation settings
|
||||
csharp_indent_case_contents = true
|
||||
csharp_indent_switch_labels = true
|
||||
# Modifiers
|
||||
dotnet_style_readonly_field = true:suggestion
|
||||
dotnet_style_require_accessibility_modifiers = for_non_interface_members:suggestion
|
||||
# Naming style
|
||||
dotnet_naming_symbols.privates.applicable_kinds = property,method,event,delegate
|
||||
dotnet_naming_symbols.privates.applicable_accessibilities = private
|
||||
dotnet_naming_style.underscore_pascal.capitalization = pascal_case
|
||||
dotnet_naming_style.underscore_pascal.required_prefix = _
|
||||
dotnet_naming_rule.privates_with_underscore.symbols = privates
|
||||
dotnet_naming_rule.privates_with_underscore.style = underscore_pascal
|
||||
dotnet_naming_rule.privates_with_underscore.severity = warning
|
||||
dotnet_diagnostic.IDE1006.severity = warning
|
||||
# ReSharper properties
|
||||
resharper_align_multiline_binary_expressions_chain = false
|
||||
resharper_csharp_empty_block_style = together_same_line
|
||||
resharper_indent_nested_foreach_stmt = true
|
||||
resharper_indent_nested_for_stmt = true
|
||||
resharper_indent_nested_while_stmt = true
|
||||
resharper_keep_existing_embedded_arrangement = false
|
||||
resharper_place_accessorholder_attribute_on_same_line = true
|
||||
resharper_place_simple_embedded_statement_on_same_line = false
|
||||
resharper_wrap_before_arrow_with_expressions = true
|
||||
resharper_xmldoc_attribute_indent = align_by_first_attribute
|
||||
resharper_xmldoc_indent_child_elements = RemoveIndent
|
||||
resharper_xmldoc_indent_text = RemoveIndent
|
||||
# Switch on enum
|
||||
dotnet_diagnostic.CS8509.severity=error # missing switch case for named enum value
|
||||
dotnet_diagnostic.CS8524.severity=none # missing switch case for unnamed enum value
|
||||
|
||||
# Waiting for https://github.com/dotnet/roslyn/issues/44596 to get fixed.
|
||||
# file_header_template = Kyoo - A portable and vast media library solution.\nCopyright (c) Kyoo.\n\nSee AUTHORS.md and LICENSE file in the project root for full license information.\n\nKyoo is free software: you can redistribute it and/or modify\nit under the terms of the GNU General Public License as published by\nthe Free Software Foundation, either version 3 of the License, or\nany later version.\n\nKyoo is distributed in the hope that it will be useful,\nbut WITHOUT ANY WARRANTY; without even the implied warranty of\nMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\nGNU General Public License for more details.\n\nYou should have received a copy of the GNU General Public License\nalong with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
@@ -1,37 +0,0 @@
|
||||
# vi: ft=sh
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
# http route prefix (will listen to $KYOO_PREFIX/movie for example)
|
||||
KYOO_PREFIX=""
|
||||
|
||||
|
||||
# Optional authentication settings
|
||||
# Set to true to disable login with password (OIDC auth must be configured)
|
||||
# AUTHENTICATION_DISABLE_PASSWORD_LOGIN=true
|
||||
# Set to true to disable the creation of new users (OIDC auth must be configured)
|
||||
# AUTHENTICATION_DISABLE_USER_REGISTRATION=true
|
||||
|
||||
# Postgres settings
|
||||
# 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
|
||||
PGDB=kyooDB
|
||||
PGSERVER=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
|
||||
|
||||
# RabbitMQ settings
|
||||
# Full list of options: https://www.rabbitmq.com/uri-spec.html, https://www.rabbitmq.com/docs/uri-query-parameters
|
||||
# RABBITMQ_URL=amqps://user:password@rabbitmq-server:1234/vhost?cacertfile=/path/to/cacert.pem&certfile=/path/to/cert.pem&keyfile=/path/to/key.pem&verify=verify_peer&auth_mechanism=EXTERNAL
|
||||
# These values override what is provided the the URL variable
|
||||
RABBITMQ_DEFAULT_USER=guest
|
||||
RABBITMQ_DEFAULT_PASS=guest
|
||||
RABBITMQ_HOST=rabbitmq
|
||||
RABBITMQ_PORT=5672
|
||||
352
back/.gitignore
vendored
352
back/.gitignore
vendored
@@ -1,352 +0,0 @@
|
||||
out
|
||||
libtranscoder.so
|
||||
libtranscoder.dylib
|
||||
transcoder.dll
|
||||
kyoo_datadir
|
||||
|
||||
video
|
||||
.env
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.rsuser
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
[Aa][Rr][Mm]/
|
||||
[Aa][Rr][Mm]64/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015/2017 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# Visual Studio 2017 auto generated files
|
||||
Generated\ Files/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
|
||||
# StyleCop
|
||||
StyleCopReport.xml
|
||||
|
||||
# Files built by Visual Studio
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_h.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.iobj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.ipdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*_wpftmp.csproj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# Visual Studio Trace Files
|
||||
*.e2e
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/[Pp]ackages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/[Pp]ackages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/[Pp]ackages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!?*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Including strong name files can present a security risk
|
||||
# (https://github.com/github/gitignore/pull/2483#issue-259490424)
|
||||
#*.snk
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
ServiceFabricBackup/
|
||||
*.rptproj.bak
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
*.rptproj.rsuser
|
||||
*- Backup*.rdl
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush personal settings
|
||||
.cr/personal
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# OpenCover UI analysis results
|
||||
OpenCover/
|
||||
|
||||
# Azure Stream Analytics local run output
|
||||
ASALocalRun/
|
||||
|
||||
# MSBuild Binary and Structured Log
|
||||
*.binlog
|
||||
|
||||
# NVidia Nsight GPU debugger configuration file
|
||||
*.nvuser
|
||||
|
||||
# MFractors (Xamarin productivity tool) working folder
|
||||
.mfractor/
|
||||
|
||||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
# BeatPulse healthcheck temp database
|
||||
healthchecksdb
|
||||
/Kyoo/TheTVDB-Credentials.json
|
||||
|
||||
.vscode
|
||||
.netcoredbg_hist
|
||||
@@ -1,29 +0,0 @@
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 as builder
|
||||
ARG TARGETARCH
|
||||
WORKDIR /kyoo
|
||||
|
||||
COPY Kyoo.sln ./Kyoo.sln
|
||||
COPY nuget.config ./nuget.config
|
||||
COPY src/Directory.Build.props src/Directory.Build.props
|
||||
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
|
||||
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
|
||||
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
|
||||
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
|
||||
COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
|
||||
RUN dotnet restore -a $TARGETARCH
|
||||
|
||||
COPY . .
|
||||
ARG VERSION
|
||||
RUN dotnet publish -a $TARGETARCH --no-restore -c Release -o /app "-p:Version=${VERSION:-"0.0.0-dev"}" src/Kyoo.Core
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/aspnet:8.0
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
COPY --from=builder /app /app
|
||||
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
# The back can take a long time to start if meilisearch is initializing
|
||||
HEALTHCHECK --interval=30s --retries=15 CMD curl --fail http://localhost:5000/health || exit
|
||||
ENTRYPOINT ["/app/kyoo"]
|
||||
@@ -1,22 +0,0 @@
|
||||
FROM mcr.microsoft.com/dotnet/sdk:8.0
|
||||
RUN apt-get update && apt-get install -y curl
|
||||
WORKDIR /app
|
||||
|
||||
COPY Kyoo.sln ./Kyoo.sln
|
||||
COPY nuget.config ./nuget.config
|
||||
COPY src/Directory.Build.props src/Directory.Build.props
|
||||
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
|
||||
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
|
||||
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
|
||||
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
|
||||
COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
|
||||
RUN dotnet restore
|
||||
|
||||
WORKDIR /app
|
||||
EXPOSE 5000
|
||||
ENV DOTNET_USE_POLLING_FILE_WATCHER 1
|
||||
# HEALTHCHECK --interval=30s CMD curl --fail http://localhost:5000/health || exit
|
||||
HEALTHCHECK CMD true
|
||||
ENTRYPOINT ["dotnet", "watch", "--non-interactive", "run", "--no-restore", "--project", "/app/src/Kyoo.Core"]
|
||||
@@ -1,30 +0,0 @@
|
||||
FROM --platform=$BUILDPLATFORM mcr.microsoft.com/dotnet/sdk:8.0 as builder
|
||||
ARG TARGETARCH
|
||||
WORKDIR /kyoo
|
||||
|
||||
COPY .config/dotnet-tools.json .config/dotnet-tools.json
|
||||
RUN dotnet tool restore
|
||||
|
||||
COPY Kyoo.sln ./Kyoo.sln
|
||||
COPY nuget.config ./nuget.config
|
||||
COPY src/Directory.Build.props src/Directory.Build.props
|
||||
COPY src/Kyoo.Authentication/Kyoo.Authentication.csproj src/Kyoo.Authentication/Kyoo.Authentication.csproj
|
||||
COPY src/Kyoo.Abstractions/Kyoo.Abstractions.csproj src/Kyoo.Abstractions/Kyoo.Abstractions.csproj
|
||||
COPY src/Kyoo.Core/Kyoo.Core.csproj src/Kyoo.Core/Kyoo.Core.csproj
|
||||
COPY src/Kyoo.Postgresql/Kyoo.Postgresql.csproj src/Kyoo.Postgresql/Kyoo.Postgresql.csproj
|
||||
COPY src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj src/Kyoo.Meilisearch/Kyoo.Meilisearch.csproj
|
||||
COPY src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj src/Kyoo.RabbitMq/Kyoo.RabbitMq.csproj
|
||||
COPY src/Kyoo.Swagger/Kyoo.Swagger.csproj src/Kyoo.Swagger/Kyoo.Swagger.csproj
|
||||
RUN dotnet restore -a $TARGETARCH
|
||||
|
||||
COPY . .
|
||||
RUN dotnet build
|
||||
RUN dotnet ef migrations bundle \
|
||||
--msbuildprojectextensionspath out/obj/Kyoo.Postgresql \
|
||||
--no-build --self-contained -r linux-${TARGETARCH} -f \
|
||||
-o /app/migrate -p src/Kyoo.Postgresql --verbose
|
||||
|
||||
FROM mcr.microsoft.com/dotnet/runtime-deps:8.0
|
||||
COPY --from=builder /app/migrate /app/migrate
|
||||
|
||||
ENTRYPOINT ["/app/migrate"]
|
||||
@@ -1,47 +0,0 @@
|
||||
<RuleSet Name="Kyoo" ToolsVersion="10.0">
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.MaintainabilityRules">
|
||||
<Rule Id="SA1413" Action="None" /> <!-- UseTrailingCommasInMultiLineInitializers -->
|
||||
<Rule Id="SA1414" Action="None" /> <!-- UseTrailingCommasInMultiLineInitializers -->
|
||||
<Rule Id="SA1114" Action="None" /> <!-- UseTrailingCommasInMultiLineInitializers -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.OrderingRules">
|
||||
<Rule Id="SA1201" Action="None" /> <!-- ElementsMustAppearInTheCorrectOrder -->
|
||||
<Rule Id="SA1202" Action="None" /> <!-- ElementsMustBeOrderedByAccess -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.NamingRules">
|
||||
<Rule Id="SA1309" Action="None" /> <!-- FieldNamesMustNotBeginWithUnderscore -->
|
||||
<Rule Id="SX1309" Action="Warning" /> <!-- FieldNamesMustBeginWithUnderscore -->
|
||||
<Rule Id="SA1300" Action="None" /> <!-- ElementMustBeginWithUpperCaseLetter (this conflict with the _ prefix for privates, enforced by an IDE rule) -->
|
||||
<Rule Id="SA1316" Action="None" /> <!-- TupleElementNamesShouldUseCorrectCasing (should be camels when deconstructing but pascal otherwise. -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.ReadabilityRules">
|
||||
<Rule Id="SA1101" Action="None" /> <!-- PrefixLocalCallsWithThis -->
|
||||
<Rule Id="SX1101" Action="Warning" /> <!-- DoNotPrefixLocalMembersWithThis -->
|
||||
<Rule Id="SA1134" Action="None" /> <!-- AttributesMustNotShareLine -->
|
||||
<Rule Id="SA1117" Action="None" /> <!-- ParametersMustBeOnSameLineOrSeparateLines -->
|
||||
<Rule Id="SA1116" Action="None" /> <!-- SplitParametersMustStartOnLineAfterDeclaration -->
|
||||
<Rule Id="SA1111" Action="None" /> <!-- ClosingParenthesisMustBeOnLineOfLastParameter -->
|
||||
<Rule Id="SA1009" Action="None" /> <!-- ClosingParenthesisMustBeSpacedCorrectly (bugged if the parenthesis is on a line by iteself) -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.SpacingRules">
|
||||
<Rule Id="SA1502" Action="None"/> <!-- DocumentationLinesMustBeginWithSingleSpace -->
|
||||
<Rule Id="SA1027" Action="None"/> <!-- UseTabsCorrectly (smarts tabs are broken). TODO find a way to enable smart tabs -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.LayoutRules">
|
||||
<Rule Id="SA1402" Action="None"/> <!-- SingleClassPerFile -->
|
||||
<Rule Id="SA1649" Action="None"/> <!-- Class name must be filename -->
|
||||
<Rule Id="SA1503" Action="None"/> <!-- BracesMustNotBeOmitted -->
|
||||
<Rule Id="SA1512" Action="None"/> <!-- Let me comment -->
|
||||
<Rule Id="SA1520" Action="None"/> <!-- UseBracesConsistently -->
|
||||
<Rule Id="SA1515" Action="None"/> <!-- SingleLineCommentMustBePrecededByBlankLine -->
|
||||
<Rule Id="SA1513" Action="None"/> <!-- ClosingBraceMustBeFollowedByBlankLine -->
|
||||
</Rules>
|
||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.CSharp.DocumentationRules">
|
||||
<Rule Id="SA1600" Action="None" /> <!-- Elements Shuld be Documented -->
|
||||
<Rule Id="SA1602" Action="None" /> <!-- Enums should be documented -->
|
||||
<Rule Id="SA1642" Action="None" /> <!-- ConstructorSummaryDocumentationMustBeginWithStandardText -->
|
||||
<Rule Id="SA1643" Action="None" /> <!-- DestructorSummaryDocumentationMustBeginWithStandardText -->
|
||||
<Rule Id="SA1623" Action="None" /> <!-- PropertySummaryDocumentationMustMatchAccessors -->
|
||||
<Rule Id="SA1629" Action="None" /> <!-- DocumentationTextMustEndWithAPeriod -->
|
||||
</Rules>
|
||||
</RuleSet>
|
||||
@@ -1,64 +0,0 @@
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
#
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kyoo.Core", "src\Kyoo.Core\Kyoo.Core.csproj", "{0F8275B6-C7DD-42DF-A168-755C81B1C329}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Abstractions", "src\Kyoo.Abstractions\Kyoo.Abstractions.csproj", "{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Postgresql", "src\Kyoo.Postgresql\Kyoo.Postgresql.csproj", "{3213C96D-0BF3-460B-A8B5-B9977229408A}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Authentication", "src\Kyoo.Authentication\Kyoo.Authentication.csproj", "{7A841335-6523-47DB-9717-80AA7BD943FD}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Swagger", "src\Kyoo.Swagger\Kyoo.Swagger.csproj", "{7D1A7596-73F6-4D35-842E-A5AD9C620596}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.Meilisearch", "src\Kyoo.Meilisearch\Kyoo.Meilisearch.csproj", "{F8E6018A-FD51-40EB-99FF-A26BA59F2762}"
|
||||
EndProject
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Kyoo.RabbitMq", "src\Kyoo.RabbitMq\Kyoo.RabbitMq.csproj", "{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0F8275B6-C7DD-42DF-A168-755C81B1C329}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0F8275B6-C7DD-42DF-A168-755C81B1C329}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0F8275B6-C7DD-42DF-A168-755C81B1C329}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0F8275B6-C7DD-42DF-A168-755C81B1C329}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{BAB2CAE1-AC28-4509-AA3E-8DC75BD59220}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{3213C96D-0BF3-460B-A8B5-B9977229408A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7A841335-6523-47DB-9717-80AA7BD943FD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7A841335-6523-47DB-9717-80AA7BD943FD}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7A841335-6523-47DB-9717-80AA7BD943FD}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7A841335-6523-47DB-9717-80AA7BD943FD}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{6515380E-1E57-42DA-B6E3-E1C8A848818A}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{2374D500-1ADB-4752-85DB-8BB0DDF5A8E8}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{4FF1ECD9-6EEF-4440-B037-A661D78FB04D}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{7D1A7596-73F6-4D35-842E-A5AD9C620596}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{F8E6018A-FD51-40EB-99FF-A26BA59F2762}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{B97AD4A8-E6E6-41CD-87DF-5F1326FD7198}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
@@ -1,4 +0,0 @@
|
||||
--project
|
||||
src/Kyoo.Postgresql
|
||||
--msbuildprojectextensionspath
|
||||
out/obj/Kyoo.Postgresql
|
||||
BIN
back/icon.ico
BIN
back/icon.ico
Binary file not shown.
|
Before Width: | Height: | Size: 105 KiB |
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<clear/>
|
||||
<add key="feedz" value="https://f.feedz.io/zoriya/entityframeworkcore-projectables/nuget/index.json"/>
|
||||
<add key="nuget" value="https://api.nuget.org/v3/index.json"/>
|
||||
</packageSources>
|
||||
<disabledPackageSources>
|
||||
<clear/>
|
||||
</disabledPackageSources>
|
||||
<fallbackPackageFolders>
|
||||
<clear/>
|
||||
</fallbackPackageFolders>
|
||||
</configuration>
|
||||
@@ -1,15 +0,0 @@
|
||||
{pkgs ? import <nixpkgs> {}}: let
|
||||
dotnet = with pkgs.dotnetCorePackages;
|
||||
combinePackages [
|
||||
sdk_8_0
|
||||
aspnetcore_8_0
|
||||
];
|
||||
in
|
||||
pkgs.mkShell {
|
||||
packages = with pkgs; [
|
||||
dotnet
|
||||
csharpier
|
||||
];
|
||||
|
||||
DOTNET_ROOT = "${dotnet}";
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<LangVersion>default</LangVersion>
|
||||
<Nullable>enable</Nullable>
|
||||
<Company>Kyoo</Company>
|
||||
<Authors>Kyoo</Authors>
|
||||
<Copyright>Copyright (c) Kyoo</Copyright>
|
||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance>
|
||||
<PackageLicenseExpression>GPL-3.0-or-later</PackageLicenseExpression>
|
||||
<RequireLicenseAcceptance>true</RequireLicenseAcceptance>
|
||||
|
||||
<RepositoryUrl>https://github.com/zoriya/Kyoo</RepositoryUrl>
|
||||
<RepositoryType>git</RepositoryType>
|
||||
<PublishRepositoryUrl>true</PublishRepositoryUrl>
|
||||
<PackageProjectUrl>https://github.com/zoriya/Kyoo</PackageProjectUrl>
|
||||
|
||||
<PackageVersion>1.0.0</PackageVersion>
|
||||
<IncludeSymbols>true</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
|
||||
<ApplicationIcon>$(MSBuildThisFileDirectory)../icon.ico</ApplicationIcon>
|
||||
|
||||
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<CheckCodingStyle Condition="$(CheckCodingStyle) == ''">true</CheckCodingStyle>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<BaseIntermediateOutputPath>$(MsBuildThisFileDirectory)/../out/obj/$(MSBuildProjectName)</BaseIntermediateOutputPath>
|
||||
<BaseOutputPath>$(MsBuildThisFileDirectory)/../out/bin/$(MSBuildProjectName)</BaseOutputPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup Condition="$(CheckCodingStyle) == true">
|
||||
<None Include="$(MSBuildThisFileDirectory)../.editorconfig" Link=".editorconfig" Visible="false" />
|
||||
</ItemGroup>
|
||||
|
||||
<PropertyGroup Condition="$(CheckCodingStyle) == true">
|
||||
<CodeAnalysisRuleSet>$(MSBuildThisFileDirectory)../Kyoo.ruleset</CodeAnalysisRuleSet>
|
||||
<NoWarn>1591;1305;8618;SYSLIB1045;CS1573</NoWarn>
|
||||
<!-- <AnalysisMode>All</AnalysisMode> -->
|
||||
</PropertyGroup>
|
||||
|
||||
<!-- vim: ft=xml -->
|
||||
</Project>
|
||||
232
back/src/Kyoo.Abstractions/.gitignore
vendored
232
back/src/Kyoo.Abstractions/.gitignore
vendored
@@ -1,232 +0,0 @@
|
||||
## PROJECT CUSTOM IGNORES
|
||||
|
||||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
bld/
|
||||
bin/
|
||||
Bin/
|
||||
obj/
|
||||
Obj/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Microsoft Azure ApplicationInsights config file
|
||||
ApplicationInsights.config
|
||||
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
/node_modules
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
@@ -1,35 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
public interface IIssueRepository
|
||||
{
|
||||
Task<ICollection<Issue>> GetAll(Filter<Issue>? filter = default);
|
||||
|
||||
Task<int> GetCount(Filter<Issue>? filter = default);
|
||||
|
||||
Task<Issue> Upsert(Issue issue);
|
||||
|
||||
Task DeleteAll(Filter<Issue>? filter = default);
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Models;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// An interface to interact with the database. Every repository is mapped through here.
|
||||
/// </summary>
|
||||
public interface ILibraryManager
|
||||
{
|
||||
IRepository<T> Repository<T>()
|
||||
where T : IResource, IQuery;
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle libraries items (a wrapper around shows and collections).
|
||||
/// </summary>
|
||||
IRepository<ILibraryItem> LibraryItems { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle new items.
|
||||
/// </summary>
|
||||
IRepository<INews> News { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle watched items.
|
||||
/// </summary>
|
||||
IWatchStatusRepository WatchStatus { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle collections.
|
||||
/// </summary>
|
||||
IRepository<Collection> Collections { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IRepository<Movie> Movies { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle shows.
|
||||
/// </summary>
|
||||
IRepository<Show> Shows { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle seasons.
|
||||
/// </summary>
|
||||
IRepository<Season> Seasons { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle episodes.
|
||||
/// </summary>
|
||||
IRepository<Episode> Episodes { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle studios.
|
||||
/// </summary>
|
||||
IRepository<Studio> Studios { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The repository that handle users.
|
||||
/// </summary>
|
||||
IRepository<User> Users { get; }
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Models.Permissions;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A service to validate permissions.
|
||||
/// </summary>
|
||||
public interface IPermissionValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// Create an IAuthorizationFilter that will be used to validate permissions.
|
||||
/// This can registered with any lifetime.
|
||||
/// </summary>
|
||||
/// <param name="attribute">The permission attribute to validate.</param>
|
||||
/// <returns>An authorization filter used to validate the permission.</returns>
|
||||
IFilterMetadata Create(PermissionAttribute attribute);
|
||||
|
||||
/// <summary>
|
||||
/// Create an IAuthorizationFilter that will be used to validate permissions.
|
||||
/// This can registered with any lifetime.
|
||||
/// </summary>
|
||||
/// <param name="attribute">
|
||||
/// A partial attribute to validate. See <see cref="PartialPermissionAttribute"/>.
|
||||
/// </param>
|
||||
/// <returns>An authorization filter used to validate the permission.</returns>
|
||||
IFilterMetadata Create(PartialPermissionAttribute attribute);
|
||||
}
|
||||
@@ -1,267 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A common repository for every resources.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The resource's type that this repository manage.</typeparam>
|
||||
public interface IRepository<T> : IBaseRepository
|
||||
where T : IResource, IQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// The event handler type for all events of this repository.
|
||||
/// </summary>
|
||||
/// <param name="resource">The resource created/modified/deleted</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
public delegate Task ResourceEventHandler(T resource);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's ID.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(Guid id, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(string slug, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get the first resource that match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="filter">A predicate to filter the resource.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <param name="reverse">Reverse the sort.</param>
|
||||
/// <param name="afterId">Select the first element after this id if it was in a list.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item could not be found.</exception>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T> Get(
|
||||
Filter<T> filter,
|
||||
Include<T>? include = default,
|
||||
Sort<T>? sortBy = default,
|
||||
bool reverse = false,
|
||||
Guid? afterId = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's ID or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(Guid id, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get a resource from it's slug or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(string slug, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get the first resource that match the predicate or null if it is not found.
|
||||
/// </summary>
|
||||
/// <param name="filter">A predicate to filter the resource.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <param name="sortBy">A custom sort method to handle cases where multiples items match the filters.</param>
|
||||
/// <param name="reverse">Reverse the sort.</param>
|
||||
/// <param name="afterId">Select the first element after this id if it was in a list.</param>
|
||||
/// <returns>The resource found</returns>
|
||||
Task<T?> GetOrDefault(
|
||||
Filter<T>? filter,
|
||||
Include<T>? include = default,
|
||||
Sort<T>? sortBy = default,
|
||||
bool reverse = false,
|
||||
Guid? afterId = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for resources with the database.
|
||||
/// </summary>
|
||||
/// <param name="query">The query string.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources found</returns>
|
||||
Task<ICollection<T>> Search(string query, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Get every resources that match all filters
|
||||
/// </summary>
|
||||
/// <param name="filter">A filter predicate</param>
|
||||
/// <param name="sort">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <param name="limit">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
Task<ICollection<T>> GetAll(
|
||||
Filter<T>? filter = null,
|
||||
Sort<T>? sort = default,
|
||||
Include<T>? include = default,
|
||||
Pagination? limit = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of resources that match the filter's predicate.
|
||||
/// </summary>
|
||||
/// <param name="filter">A filter predicate</param>
|
||||
/// <returns>How many resources matched that filter</returns>
|
||||
Task<int> GetCount(Filter<T>? filter = null);
|
||||
|
||||
/// <summary>
|
||||
/// Map a list of ids to a list of items (keep the order).
|
||||
/// </summary>
|
||||
/// <param name="ids">The list of items id.</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources mapped from ids.</returns>
|
||||
Task<ICollection<T>> FromIds(IList<Guid> ids, Include<T>? include = default);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource.
|
||||
/// </summary>
|
||||
/// <param name="obj">The item to register</param>
|
||||
/// <returns>The resource registers and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Create(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new resource if it does not exist already. If it does, the existing value is returned instead.
|
||||
/// </summary>
|
||||
/// <param name="obj">The object to create</param>
|
||||
/// <returns>The newly created item or the existing value if it existed.</returns>
|
||||
Task<T> CreateIfNotExists(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been created.
|
||||
/// </summary>
|
||||
static event ResourceEventHandler OnCreated;
|
||||
|
||||
/// <summary>
|
||||
/// Callback that should be called after a resource has been created.
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource newly created.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
protected static Task OnResourceCreated(T obj) => OnCreated?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Edit a resource and replace every property
|
||||
/// </summary>
|
||||
/// <param name="edited">The resource to edit, it's ID can't change.</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Edit(T edited);
|
||||
|
||||
/// <summary>
|
||||
/// Edit only specific properties of a resource
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource to edit</param>
|
||||
/// <param name="patch">
|
||||
/// A method that will be called when you need to update every properties that you want to
|
||||
/// persist.
|
||||
/// </param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>The resource edited and completed by database's information (related items and so on)</returns>
|
||||
Task<T> Patch(Guid id, Func<T, T> patch);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been edited.
|
||||
/// </summary>
|
||||
static event ResourceEventHandler OnEdited;
|
||||
|
||||
/// <summary>
|
||||
/// Callback that should be called after a resource has been edited.
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource newly edited.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
protected static Task OnResourceEdited(T obj) => OnEdited?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's ID
|
||||
/// </summary>
|
||||
/// <param name="id">The ID of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(Guid id);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource by it's slug
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(string slug);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a resource
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource to delete</param>
|
||||
/// <exception cref="ItemNotFoundException">If the item is not found</exception>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task Delete(T obj);
|
||||
|
||||
/// <summary>
|
||||
/// Delete all resources that match the predicate.
|
||||
/// </summary>
|
||||
/// <param name="filter">A predicate to filter resources to delete. Every resource that match this will be deleted.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
Task DeleteAll(Filter<T> filter);
|
||||
|
||||
/// <summary>
|
||||
/// Called when a resource has been edited.
|
||||
/// </summary>
|
||||
static event ResourceEventHandler OnDeleted;
|
||||
|
||||
/// <summary>
|
||||
/// Callback that should be called after a resource has been deleted.
|
||||
/// </summary>
|
||||
/// <param name="obj">The resource newly deleted.</param>
|
||||
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
|
||||
protected static Task OnResourceDeleted(T obj) => OnDeleted?.Invoke(obj) ?? Task.CompletedTask;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A base class for repositories. Every service implementing this will be handled by the <see cref="ILibraryManager"/>.
|
||||
/// </summary>
|
||||
public interface IBaseRepository
|
||||
{
|
||||
/// <summary>
|
||||
/// The type for witch this repository is responsible or null if non applicable.
|
||||
/// </summary>
|
||||
Type RepositoryType { get; }
|
||||
}
|
||||
|
||||
public interface IUserRepository : IRepository<User>
|
||||
{
|
||||
Task<User?> GetByExternalId(string provider, string id);
|
||||
Task<User> AddExternalToken(Guid userId, string provider, ExternalToken token);
|
||||
Task<User> DeleteExternalToken(Guid userId, string provider);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
public interface IScanner
|
||||
{
|
||||
Task SendRescanRequest();
|
||||
Task SendRefreshRequest(string kind, Guid id);
|
||||
}
|
||||
@@ -1,125 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// The service to search items.
|
||||
/// </summary>
|
||||
public interface ISearchManager
|
||||
{
|
||||
/// <summary>
|
||||
/// Search for items.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<ILibraryItem>.SearchResult> SearchItems(
|
||||
string? query,
|
||||
Sort<ILibraryItem> sortBy,
|
||||
Filter<ILibraryItem>? filter,
|
||||
SearchPagination pagination,
|
||||
Include<ILibraryItem>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for movies.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Movie>.SearchResult> SearchMovies(
|
||||
string? query,
|
||||
Sort<Movie> sortBy,
|
||||
Filter<ILibraryItem>? filter,
|
||||
SearchPagination pagination,
|
||||
Include<Movie>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for shows.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Show>.SearchResult> SearchShows(
|
||||
string? query,
|
||||
Sort<Show> sortBy,
|
||||
Filter<ILibraryItem>? filter,
|
||||
SearchPagination pagination,
|
||||
Include<Show>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for collections.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Collection>.SearchResult> SearchCollections(
|
||||
string? query,
|
||||
Sort<Collection> sortBy,
|
||||
Filter<ILibraryItem>? filter,
|
||||
SearchPagination pagination,
|
||||
Include<Collection>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for episodes.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Episode>.SearchResult> SearchEpisodes(
|
||||
string? query,
|
||||
Sort<Episode> sortBy,
|
||||
Filter<Episode>? filter,
|
||||
SearchPagination pagination,
|
||||
Include<Episode>? include = default
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// Search for studios.
|
||||
/// </summary>
|
||||
/// <param name="query">The seach query.</param>
|
||||
/// <param name="sortBy">Sort information about the query (sort by, sort order)</param>
|
||||
/// <param name="pagination">How pagination should be done (where to start and how many to return)</param>
|
||||
/// <param name="include">The related fields to include.</param>
|
||||
/// <returns>A list of resources that match every filters</returns>
|
||||
public Task<SearchPage<Studio>.SearchResult> SearchStudios(
|
||||
string? query,
|
||||
Sort<Studio> sortBy,
|
||||
Filter<Studio>? filter,
|
||||
SearchPagination pagination,
|
||||
Include<Studio>? include = default
|
||||
);
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
public interface IThumbnailsManager
|
||||
{
|
||||
Task DownloadImages<T>(T item)
|
||||
where T : IThumbnails;
|
||||
|
||||
Task DownloadImage(Image? image, string what);
|
||||
|
||||
Task<bool> IsImageSaved(Guid imageId, ImageQuality quality);
|
||||
|
||||
Task<Stream> GetImage(Guid imageId, ImageQuality quality);
|
||||
|
||||
Task DeleteImages<T>(T item)
|
||||
where T : IThumbnails;
|
||||
|
||||
Task<Stream> GetUserImage(Guid userId);
|
||||
|
||||
Task SetUserImage(Guid userId, Stream? image);
|
||||
}
|
||||
@@ -1,83 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// A local repository to handle watched items
|
||||
/// </summary>
|
||||
public interface IWatchStatusRepository
|
||||
{
|
||||
public delegate Task ResourceEventHandler<T>(T resource);
|
||||
|
||||
Task<ICollection<IWatchlist>> GetAll(
|
||||
Filter<IWatchlist>? filter = default,
|
||||
Include<IWatchlist>? include = default,
|
||||
Pagination? limit = default
|
||||
);
|
||||
|
||||
Task<MovieWatchStatus?> GetMovieStatus(Guid movieId, Guid userId);
|
||||
|
||||
Task<MovieWatchStatus?> SetMovieStatus(
|
||||
Guid movieId,
|
||||
Guid userId,
|
||||
WatchStatus status,
|
||||
int? watchedTime,
|
||||
int? percent
|
||||
);
|
||||
|
||||
static event ResourceEventHandler<WatchStatus<Movie>> OnMovieStatusChangedHandler;
|
||||
protected static Task OnMovieStatusChanged(WatchStatus<Movie> obj) =>
|
||||
OnMovieStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
Task DeleteMovieStatus(Guid movieId, Guid userId);
|
||||
|
||||
Task<ShowWatchStatus?> GetShowStatus(Guid showId, Guid userId);
|
||||
|
||||
Task<ShowWatchStatus?> SetShowStatus(Guid showId, Guid userId, WatchStatus status);
|
||||
|
||||
static event ResourceEventHandler<WatchStatus<Show>> OnShowStatusChangedHandler;
|
||||
protected static Task OnShowStatusChanged(WatchStatus<Show> obj) =>
|
||||
OnShowStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
Task DeleteShowStatus(Guid showId, Guid userId);
|
||||
|
||||
Task<EpisodeWatchStatus?> GetEpisodeStatus(Guid episodeId, Guid userId);
|
||||
|
||||
/// <param name="watchedTime">Where the user has stopped watching. Only usable if Status
|
||||
/// is <see cref="WatchStatus.Watching"/></param>
|
||||
Task<EpisodeWatchStatus?> SetEpisodeStatus(
|
||||
Guid episodeId,
|
||||
Guid userId,
|
||||
WatchStatus status,
|
||||
int? watchedTime,
|
||||
int? percent
|
||||
);
|
||||
|
||||
static event ResourceEventHandler<WatchStatus<Episode>> OnEpisodeStatusChangedHandler;
|
||||
protected static Task OnEpisodeStatusChanged(WatchStatus<Episode> obj) =>
|
||||
OnEpisodeStatusChangedHandler?.Invoke(obj) ?? Task.CompletedTask;
|
||||
|
||||
Task DeleteEpisodeStatus(Guid episodeId, Guid userId);
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using Kyoo.Abstractions.Models.Exceptions;
|
||||
using Kyoo.Authentication.Models;
|
||||
|
||||
namespace Kyoo.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// Extension methods.
|
||||
/// </summary>
|
||||
public static class Extensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Get the permissions of an user.
|
||||
/// </summary>
|
||||
/// <param name="user">The user</param>
|
||||
/// <returns>The list of permissions</returns>
|
||||
public static ICollection<string> GetPermissions(this ClaimsPrincipal user)
|
||||
{
|
||||
return user.Claims.FirstOrDefault(x => x.Type == Claims.Permissions)?.Value.Split(',')
|
||||
?? Array.Empty<string>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the id of the current user or null if unlogged or invalid.
|
||||
/// </summary>
|
||||
/// <param name="user">The user.</param>
|
||||
/// <returns>The id of the user or null.</returns>
|
||||
public static Guid? GetId(this ClaimsPrincipal user)
|
||||
{
|
||||
Claim? value = user.FindFirst(Claims.Id);
|
||||
if (Guid.TryParse(value?.Value, out Guid id))
|
||||
return id;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Guid GetIdOrThrow(this ClaimsPrincipal user)
|
||||
{
|
||||
Guid? ret = user.GetId();
|
||||
if (ret == null)
|
||||
throw new UnauthorizedException();
|
||||
return ret.Value;
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<Title>Kyoo.Abstractions</Title>
|
||||
<Description>Base package to create plugins for Kyoo.</Description>
|
||||
<RootNamespace>Kyoo.Abstractions</RootNamespace>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Dapper" Version="2.1.66" />
|
||||
<PackageReference Include="EntityFrameworkCore.Projectables" Version="4.1.4-prebeta" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Mvc.Abstractions" Version="2.3.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="8.0.0" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="8.0.2" />
|
||||
<PackageReference Include="Sprache" Version="2.3.1" />
|
||||
<PackageReference Include="System.ComponentModel.Composition" Version="9.0.10" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -1,51 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// An attribute to specify on apis to specify it's documentation's name and category.
|
||||
/// If this is applied on a method, the specified method will be exploded from the controller's page and be
|
||||
/// included on the specified tag page.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
|
||||
public class ApiDefinitionAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The public name of this api.
|
||||
/// </summary>
|
||||
public string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of the group in witch this API is. You can also specify a custom sort order using the following
|
||||
/// format: <code>order:name</code>. Everything before the first <c>:</c> will be removed but kept for
|
||||
/// th alphabetical ordering.
|
||||
/// </summary>
|
||||
public string? Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ApiDefinitionAttribute"/>.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the api that will be used on the documentation page.</param>
|
||||
public ApiDefinitionAttribute(string name)
|
||||
{
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// An attribute to inform that the property is computed automatically and can't be assigned manually.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class ComputedAttribute : NotMergeableAttribute { }
|
||||
@@ -1,53 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// The targeted relation can be loaded.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class LoadableRelationAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the field containing the related resource's ID.
|
||||
/// </summary>
|
||||
public string? RelationID { get; }
|
||||
|
||||
public string? Sql { get; set; }
|
||||
|
||||
public string? On { get; set; }
|
||||
|
||||
public string? Projected { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LoadableRelationAttribute"/>.
|
||||
/// </summary>
|
||||
public LoadableRelationAttribute() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="LoadableRelationAttribute"/> with a baking relationID field.
|
||||
/// </summary>
|
||||
/// <param name="relationID">The name of the RelationID field.</param>
|
||||
public LoadableRelationAttribute(string relationID)
|
||||
{
|
||||
RelationID = relationID;
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Specify that a property can't be merged.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class NotMergeableAttribute : Attribute { }
|
||||
|
||||
/// <summary>
|
||||
/// An interface with a method called when this object is merged.
|
||||
/// </summary>
|
||||
public interface IOnMerge
|
||||
{
|
||||
/// <summary>
|
||||
/// This function is called after the object has been merged.
|
||||
/// </summary>
|
||||
/// <param name="merged">The object that has been merged with this.</param>
|
||||
void OnMerge(object merged);
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// An attribute to inform that this interface is a type union
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Interface)]
|
||||
public class OneOfAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The types this union concist of.
|
||||
/// </summary>
|
||||
public Type[] Types { get; set; }
|
||||
}
|
||||
@@ -1,87 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Permissions;
|
||||
|
||||
/// <summary>
|
||||
/// Specify one part of a permissions needed for the API (the kind or the type).
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class PartialPermissionAttribute : Attribute, IFilterFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// The needed permission type.
|
||||
/// </summary>
|
||||
public string? Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The needed permission kind.
|
||||
/// </summary>
|
||||
public Kind? Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The group of this permission.
|
||||
/// </summary>
|
||||
public Group Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// With this attribute, you can only specify a type or a kind.
|
||||
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
|
||||
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
|
||||
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
|
||||
/// lead to unspecified behaviors.
|
||||
/// </remarks>
|
||||
/// <param name="type">The type of the action</param>
|
||||
public PartialPermissionAttribute(string type)
|
||||
{
|
||||
Type = type.ToLower();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// With this attribute, you can only specify a type or a kind.
|
||||
/// To have a valid permission attribute, you must specify the kind and the permission using two attributes.
|
||||
/// Those attributes can be dispatched at different places (one on the class, one on the method for example).
|
||||
/// If you don't put exactly two of those attributes, the permission attribute will be ill-formed and will
|
||||
/// lead to unspecified behaviors.
|
||||
/// </remarks>
|
||||
/// <param name="permission">The kind of permission needed.</param>
|
||||
public PartialPermissionAttribute(Kind permission)
|
||||
{
|
||||
Kind = permission;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReusable => true;
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Permissions;
|
||||
|
||||
/// <summary>
|
||||
/// The kind of permission needed.
|
||||
/// </summary>
|
||||
public enum Kind
|
||||
{
|
||||
/// <summary>
|
||||
/// Allow the user to read for this kind of data.
|
||||
/// </summary>
|
||||
Read,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to write for this kind of data.
|
||||
/// </summary>
|
||||
Write,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to create this kind of data.
|
||||
/// </summary>
|
||||
Create,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to delete this kind of data.
|
||||
/// </summary>
|
||||
Delete,
|
||||
|
||||
/// <summary>
|
||||
/// Allow the user to play this file.
|
||||
/// </summary>
|
||||
Play,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The group of the permission.
|
||||
/// </summary>
|
||||
public enum Group
|
||||
{
|
||||
/// <summary>
|
||||
/// Default group indicating no value.
|
||||
/// </summary>
|
||||
None,
|
||||
|
||||
/// <summary>
|
||||
/// Allow all operations on basic items types.
|
||||
/// </summary>
|
||||
Overall,
|
||||
|
||||
/// <summary>
|
||||
/// Allow operation on sensitive items like libraries path, configurations and so on.
|
||||
/// </summary>
|
||||
Admin
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Specify permissions needed for the API.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class PermissionAttribute : Attribute, IFilterFactory
|
||||
{
|
||||
/// <summary>
|
||||
/// The needed permission as string.
|
||||
/// </summary>
|
||||
public string Type { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The needed permission kind.
|
||||
/// </summary>
|
||||
public Kind Kind { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The group of this permission.
|
||||
/// </summary>
|
||||
public Group Group { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Ask a permission to run an action.
|
||||
/// </summary>
|
||||
/// <param name="type">
|
||||
/// The type of the action
|
||||
/// </param>
|
||||
/// <param name="permission">
|
||||
/// The kind of permission needed.
|
||||
/// </param>
|
||||
/// <param name="group">
|
||||
/// The group of this permission (allow grouped permission like overall.read
|
||||
/// for all read permissions of this group).
|
||||
/// </param>
|
||||
public PermissionAttribute(string type, Kind permission, Group group = Group.Overall)
|
||||
{
|
||||
Type = type.ToLower();
|
||||
Kind = permission;
|
||||
Group = group;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
|
||||
{
|
||||
return serviceProvider.GetRequiredService<IPermissionValidator>().Create(this);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public bool IsReusable => true;
|
||||
|
||||
/// <summary>
|
||||
/// Return this permission attribute as a string.
|
||||
/// </summary>
|
||||
/// <returns>The string representation.</returns>
|
||||
public string AsPermissionString()
|
||||
{
|
||||
return Type;
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Permissions;
|
||||
|
||||
/// <summary>
|
||||
/// The annotated route can only be accessed by a logged in user.
|
||||
/// </summary>
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true)]
|
||||
public class UserOnlyAttribute : Attribute
|
||||
{
|
||||
// TODO: Implement a Filter Attribute to make this work. For now, this attribute is only useful as documentation.
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class SqlFirstColumnAttribute : Attribute
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of the first column of the element. Used to split multiples
|
||||
/// items on a single sql query. If not specified, it defaults to "Id".
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
public SqlFirstColumnAttribute(string name)
|
||||
{
|
||||
Name = name.ToSnakeCase();
|
||||
}
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// An exception raised when an item already exists in the database.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class DuplicatedItemException(object? existing = null)
|
||||
: Exception("Already exists in the database.")
|
||||
{
|
||||
/// <summary>
|
||||
/// The existing object.
|
||||
/// </summary>
|
||||
public object? Existing { get; } = existing;
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
/// <summary>
|
||||
/// An exception raised when an item could not be found.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class ItemNotFoundException : Exception
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a default <see cref="ItemNotFoundException"/> with no message.
|
||||
/// </summary>
|
||||
public ItemNotFoundException()
|
||||
: base("Item not found") { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="ItemNotFoundException"/> with a message
|
||||
/// </summary>
|
||||
/// <param name="message">The message of the exception</param>
|
||||
public ItemNotFoundException(string message)
|
||||
: base(message) { }
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Exceptions;
|
||||
|
||||
[Serializable]
|
||||
public class UnauthorizedException : Exception
|
||||
{
|
||||
public UnauthorizedException()
|
||||
: base("User not authenticated or token invalid.") { }
|
||||
|
||||
public UnauthorizedException(string message)
|
||||
: base(message) { }
|
||||
}
|
||||
@@ -1,50 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A genre that allow one to specify categories for shows.
|
||||
/// </summary>
|
||||
public enum Genre
|
||||
{
|
||||
Action,
|
||||
Adventure,
|
||||
Animation,
|
||||
Comedy,
|
||||
Crime,
|
||||
Documentary,
|
||||
Drama,
|
||||
Family,
|
||||
Fantasy,
|
||||
History,
|
||||
Horror,
|
||||
Music,
|
||||
Mystery,
|
||||
Romance,
|
||||
ScienceFiction,
|
||||
Thriller,
|
||||
War,
|
||||
Western,
|
||||
Kids,
|
||||
News,
|
||||
Reality,
|
||||
Soap,
|
||||
Talk,
|
||||
Politics,
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A show, a movie or a collection.
|
||||
/// </summary>
|
||||
[OneOf(Types = new[] { typeof(Show), typeof(Movie), typeof(Collection) })]
|
||||
public interface ILibraryItem : IResource, IThumbnails, IMetadata, IAddedDate, IQuery
|
||||
{
|
||||
static Sort IQuery.DefaultSort => new Sort<ILibraryItem>.By(nameof(Movie.Name));
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A show, a movie or a collection.
|
||||
/// </summary>
|
||||
[OneOf(Types = [typeof(Episode), typeof(Movie)])]
|
||||
public interface INews : IResource, IThumbnails, IAddedDate, IQuery
|
||||
{
|
||||
static Sort IQuery.DefaultSort => new Sort<INews>.By(nameof(AddedDate), true);
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A watch list item.
|
||||
/// </summary>
|
||||
[OneOf(Types = new[] { typeof(Show), typeof(Movie) })]
|
||||
public interface IWatchlist : IResource, IThumbnails, IMetadata, IAddedDate { }
|
||||
@@ -1,52 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// An issue that occured on kyoo.
|
||||
/// </summary>
|
||||
public class Issue : IAddedDate
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of issue (for example, "Scanner" if this issue was created due to scanning error).
|
||||
/// </summary>
|
||||
public string Domain { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Why this issue was caused? An unique cause that can be used to identify this issue.
|
||||
/// For the scanner, a cause should be a video path.
|
||||
/// </summary>
|
||||
public string Cause { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A human readable string explaining why this issue occured.
|
||||
/// </summary>
|
||||
public string Reason { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Some extra data that could store domain-specific info.
|
||||
/// </summary>
|
||||
public Dictionary<string, object> Extra { get; set; } = new();
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime AddedDate { get; set; }
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// ID and link of an item on an external provider.
|
||||
/// </summary>
|
||||
public class MetadataId
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the resource on the external provider.
|
||||
/// </summary>
|
||||
public string DataId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The URL of the resource on the external provider.
|
||||
/// </summary>
|
||||
public string? Link { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// ID informations about an episode.
|
||||
/// </summary>
|
||||
public class EpisodeId
|
||||
{
|
||||
/// <summary>
|
||||
/// The Id of the show on the metadata database.
|
||||
/// </summary>
|
||||
public string ShowId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The season number or null if absolute numbering is used in this database.
|
||||
/// </summary>
|
||||
public int? Season { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The episode number or absolute number if Season is null.
|
||||
/// </summary>
|
||||
public int Episode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The URL of the resource on the external provider.
|
||||
/// </summary>
|
||||
public string? Link { get; set; }
|
||||
}
|
||||
@@ -1,105 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A page of resource that contains information about the pagination of resources.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of resource contained in this page.</typeparam>
|
||||
public class Page<T>
|
||||
where T : IResource
|
||||
{
|
||||
/// <summary>
|
||||
/// The link of the current page.
|
||||
/// </summary>
|
||||
public string This { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The link of the first page.
|
||||
/// </summary>
|
||||
public string First { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The link of the previous page.
|
||||
/// </summary>
|
||||
public string? Previous { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The link of the next page.
|
||||
/// </summary>
|
||||
public string? Next { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of items in the current page.
|
||||
/// </summary>
|
||||
public int Count => Items.Count;
|
||||
|
||||
/// <summary>
|
||||
/// The list of items in the page.
|
||||
/// </summary>
|
||||
public ICollection<T> Items { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Page{T}"/>.
|
||||
/// </summary>
|
||||
/// <param name="items">The list of items in the page.</param>
|
||||
/// <param name="this">The link of the current page.</param>
|
||||
/// <param name="previous">The link of the previous page.</param>
|
||||
/// <param name="next">The link of the next page.</param>
|
||||
/// <param name="first">The link of the first page.</param>
|
||||
public Page(ICollection<T> items, string @this, string? previous, string? next, string first)
|
||||
{
|
||||
Items = items;
|
||||
This = @this;
|
||||
Previous = previous;
|
||||
Next = next;
|
||||
First = first;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Page{T}"/> and compute the urls.
|
||||
/// </summary>
|
||||
/// <param name="items">The list of items in the page.</param>
|
||||
/// <param name="url">The base url of the resources available from this page.</param>
|
||||
/// <param name="query">The list of query strings of the current page</param>
|
||||
/// <param name="limit">The number of items requested for the current page.</param>
|
||||
public Page(ICollection<T> items, string url, Dictionary<string, string> query, int limit)
|
||||
{
|
||||
Items = items;
|
||||
This = url + query.ToQueryString();
|
||||
if (items.Count > 0 && query.ContainsKey("afterID"))
|
||||
{
|
||||
query["afterID"] = items.First().Id.ToString();
|
||||
query["reverse"] = "true";
|
||||
Previous = url + query.ToQueryString();
|
||||
}
|
||||
query.Remove("reverse");
|
||||
if (items.Count == limit && limit > 0)
|
||||
{
|
||||
query["afterID"] = items.Last().Id.ToString();
|
||||
Next = url + query.ToQueryString();
|
||||
}
|
||||
query.Remove("afterID");
|
||||
First = url + query.ToQueryString();
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using Kyoo.Abstractions.Models;
|
||||
|
||||
namespace Kyoo.Models;
|
||||
|
||||
public class Patch<T> : Dictionary<string, JsonDocument>
|
||||
where T : class, IResource
|
||||
{
|
||||
public Guid? Id => this.GetValueOrDefault(nameof(IResource.Id))?.Deserialize<Guid>();
|
||||
|
||||
public string? Slug => this.GetValueOrDefault(nameof(IResource.Slug))?.Deserialize<string>();
|
||||
|
||||
public T Apply(T current)
|
||||
{
|
||||
foreach ((string property, JsonDocument value) in this)
|
||||
{
|
||||
PropertyInfo prop = typeof(T).GetProperty(
|
||||
property,
|
||||
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance
|
||||
)!;
|
||||
prop.SetValue(current, value.Deserialize(prop.PropertyType));
|
||||
}
|
||||
return current;
|
||||
}
|
||||
}
|
||||
@@ -1,100 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A class representing collections of <see cref="Show"/>.
|
||||
/// </summary>
|
||||
public class Collection
|
||||
: IQuery,
|
||||
IResource,
|
||||
IMetadata,
|
||||
IThumbnails,
|
||||
IAddedDate,
|
||||
IRefreshable,
|
||||
ILibraryItem
|
||||
{
|
||||
public static Sort DefaultSort => new Sort<Collection>.By(nameof(Collection.Name));
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of this collection.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The description of this collection.
|
||||
/// </summary>
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of movies contained in this collection.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Movie>? Movies { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows contained in this collection.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Show>? Shows { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataId> ExternalId { get; set; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime? NextMetadataRefresh { get; set; }
|
||||
|
||||
public Collection() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public Collection(string name)
|
||||
{
|
||||
if (name != null)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,302 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using EntityFrameworkCore.Projectables;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A class to represent a single show's episode.
|
||||
/// </summary>
|
||||
public class Episode : IQuery, IResource, IThumbnails, IAddedDate, IRefreshable, INews
|
||||
{
|
||||
// Use absolute numbers by default and fallback to season/episodes if it does not exists.
|
||||
public static Sort DefaultSort =>
|
||||
new Sort<Episode>.Conglomerate(
|
||||
new Sort<Episode>.By(x => x.AbsoluteNumber),
|
||||
new Sort<Episode>.By(x => x.SeasonNumber),
|
||||
new Sort<Episode>.By(x => x.EpisodeNumber)
|
||||
);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Computed]
|
||||
[MaxLength(256)]
|
||||
public string Slug
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ShowSlug != null || Show?.Slug != null)
|
||||
return GetSlug(ShowSlug ?? Show!.Slug, SeasonNumber, EpisodeNumber, AbsoluteNumber);
|
||||
return GetSlug(ShowId.ToString(), SeasonNumber, EpisodeNumber, AbsoluteNumber);
|
||||
}
|
||||
private set
|
||||
{
|
||||
Match match = Regex.Match(value, @"(?<show>.+)-s(?<season>\d+)e(?<episode>\d+)");
|
||||
|
||||
if (match.Success)
|
||||
{
|
||||
ShowSlug = match.Groups["show"].Value;
|
||||
SeasonNumber = int.Parse(match.Groups["season"].Value);
|
||||
EpisodeNumber = int.Parse(match.Groups["episode"].Value);
|
||||
}
|
||||
else
|
||||
{
|
||||
match = Regex.Match(value, @"(?<show>.+)-(?<absolute>\d+)");
|
||||
if (match.Success)
|
||||
{
|
||||
ShowSlug = match.Groups["show"].Value;
|
||||
AbsoluteNumber = int.Parse(match.Groups["absolute"].Value);
|
||||
}
|
||||
else
|
||||
ShowSlug = value;
|
||||
SeasonNumber = null;
|
||||
EpisodeNumber = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The slug of the Show that contain this episode. If this is not set, this episode is ill-formed.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string? ShowSlug { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Show containing this episode.
|
||||
/// </summary>
|
||||
public Guid ShowId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The show that contains this episode.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(ShowId))]
|
||||
public Show? Show { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Season containing this episode.
|
||||
/// </summary>
|
||||
public Guid? SeasonId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The season that contains this episode.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This can be null if the season is unknown and the episode is only identified
|
||||
/// by it's <see cref="AbsoluteNumber"/>.
|
||||
/// </remarks>
|
||||
[LoadableRelation(nameof(SeasonId))]
|
||||
public Season? Season { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The season in witch this episode is in.
|
||||
/// </summary>
|
||||
public int? SeasonNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of this episode in it's season.
|
||||
/// </summary>
|
||||
public int? EpisodeNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The absolute number of this episode. It's an episode number that is not reset to 1 after a new season.
|
||||
/// </summary>
|
||||
public int? AbsoluteNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The path of the video file for this episode.
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of this episode.
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The overview of this episode.
|
||||
/// </summary>
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How long is this episode? (in minutes)
|
||||
/// </summary>
|
||||
public int? Runtime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The release date of this episode. It can be null if unknown.
|
||||
/// </summary>
|
||||
public DateOnly? ReleaseDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, EpisodeId> ExternalId { get; set; } = [];
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime? NextMetadataRefresh { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The previous episode that should be seen before viewing this one.
|
||||
/// </summary>
|
||||
[Projectable(UseMemberBody = nameof(_PreviousEpisode), OnlyOnInclude = true)]
|
||||
[LoadableRelation(
|
||||
// language=PostgreSQL
|
||||
Sql = """
|
||||
select
|
||||
pe.* -- Episode as pe
|
||||
from
|
||||
episodes as "pe"
|
||||
where
|
||||
pe.show_id = "this".show_id
|
||||
and (pe.absolute_number < "this".absolute_number
|
||||
or pe.season_number < "this".season_number
|
||||
or (pe.season_number = "this".season_number
|
||||
and e.episode_number < "this".episode_number))
|
||||
order by
|
||||
pe.absolute_number desc nulls last,
|
||||
pe.season_number desc,
|
||||
pe.episode_number desc
|
||||
limit 1
|
||||
"""
|
||||
)]
|
||||
public Episode? PreviousEpisode { get; set; }
|
||||
|
||||
private Episode? _PreviousEpisode =>
|
||||
Show!
|
||||
.Episodes!.OrderBy(x => x.AbsoluteNumber == null)
|
||||
.ThenByDescending(x => x.AbsoluteNumber)
|
||||
.ThenByDescending(x => x.SeasonNumber)
|
||||
.ThenByDescending(x => x.EpisodeNumber)
|
||||
.FirstOrDefault(x =>
|
||||
x.AbsoluteNumber < AbsoluteNumber
|
||||
|| x.SeasonNumber < SeasonNumber
|
||||
|| (x.SeasonNumber == SeasonNumber && x.EpisodeNumber < EpisodeNumber)
|
||||
);
|
||||
|
||||
/// <summary>
|
||||
/// The next episode to watch after this one.
|
||||
/// </summary>
|
||||
[Projectable(UseMemberBody = nameof(_NextEpisode), OnlyOnInclude = true)]
|
||||
[LoadableRelation(
|
||||
// language=PostgreSQL
|
||||
Sql = """
|
||||
select
|
||||
ne.* -- Episode as ne
|
||||
from
|
||||
episodes as "ne"
|
||||
where
|
||||
ne.show_id = "this".show_id
|
||||
and (ne.absolute_number > "this".absolute_number
|
||||
or ne.season_number > "this".season_number
|
||||
or (ne.season_number = "this".season_number
|
||||
and e.episode_number > "this".episode_number))
|
||||
order by
|
||||
ne.absolute_number,
|
||||
ne.season_number,
|
||||
ne.episode_number
|
||||
limit 1
|
||||
"""
|
||||
)]
|
||||
public Episode? NextEpisode { get; set; }
|
||||
|
||||
private Episode? _NextEpisode =>
|
||||
Show!
|
||||
.Episodes!.OrderBy(x => x.AbsoluteNumber)
|
||||
.ThenBy(x => x.SeasonNumber)
|
||||
.ThenBy(x => x.EpisodeNumber)
|
||||
.FirstOrDefault(x =>
|
||||
x.AbsoluteNumber > AbsoluteNumber
|
||||
|| x.SeasonNumber > SeasonNumber
|
||||
|| (x.SeasonNumber == SeasonNumber && x.EpisodeNumber > EpisodeNumber)
|
||||
);
|
||||
|
||||
[JsonIgnore]
|
||||
public ICollection<EpisodeWatchStatus>? Watched { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Metadata of what an user as started/planned to watch.
|
||||
/// </summary>
|
||||
[Projectable(UseMemberBody = nameof(_WatchStatus), OnlyOnInclude = true)]
|
||||
[LoadableRelation(
|
||||
Sql = "episode_watch_status",
|
||||
On = "episode_id = \"this\".id and \"relation\".user_id = [current_user]"
|
||||
)]
|
||||
public EpisodeWatchStatus? WatchStatus { get; set; }
|
||||
|
||||
// There is a global query filter to filter by user so we just need to do single.
|
||||
private EpisodeWatchStatus? _WatchStatus => Watched!.FirstOrDefault();
|
||||
|
||||
/// <summary>
|
||||
/// Links to watch this episode.
|
||||
/// </summary>
|
||||
public VideoLinks Links =>
|
||||
new() { Direct = $"/episode/{Slug}/direct", Hls = $"/episode/{Slug}/master.m3u8", };
|
||||
|
||||
/// <summary>
|
||||
/// Get the slug of an episode.
|
||||
/// </summary>
|
||||
/// <param name="showSlug">The slug of the show. It can't be null.</param>
|
||||
/// <param name="seasonNumber">
|
||||
/// The season in which the episode is.
|
||||
/// If this is a movie or if the episode should be referred by it's absolute number, set this to null.
|
||||
/// </param>
|
||||
/// <param name="episodeNumber">
|
||||
/// The number of the episode in it's season.
|
||||
/// If this is a movie or if the episode should be referred by it's absolute number, set this to null.
|
||||
/// </param>
|
||||
/// <param name="absoluteNumber">
|
||||
/// The absolute number of this show.
|
||||
/// If you don't know it or this is a movie, use null
|
||||
/// </param>
|
||||
/// <returns>The slug corresponding to the given arguments</returns>
|
||||
public static string GetSlug(
|
||||
string showSlug,
|
||||
int? seasonNumber,
|
||||
int? episodeNumber,
|
||||
int? absoluteNumber = null
|
||||
)
|
||||
{
|
||||
return seasonNumber switch
|
||||
{
|
||||
null when absoluteNumber == null => showSlug,
|
||||
null => $"{showSlug}-{absoluteNumber}",
|
||||
_ => $"{showSlug}-s{seasonNumber}e{episodeNumber}"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// An interface applied to resources.
|
||||
/// </summary>
|
||||
public interface IAddedDate
|
||||
{
|
||||
/// <summary>
|
||||
/// The date at which this resource was added to kyoo.
|
||||
/// </summary>
|
||||
public DateTime AddedDate { get; set; }
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// An interface applied to resources containing external metadata.
|
||||
/// </summary>
|
||||
public interface IMetadata
|
||||
{
|
||||
/// <summary>
|
||||
/// The link to metadata providers that this show has. See <see cref="MetadataId"/> for more information.
|
||||
/// </summary>
|
||||
public Dictionary<string, MetadataId> ExternalId { get; set; }
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
public interface IQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// The sorting that will be used when no user defined one is present.
|
||||
/// </summary>
|
||||
public static virtual Sort DefaultSort => throw new NotImplementedException();
|
||||
}
|
||||
@@ -1,40 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
public interface IRefreshable
|
||||
{
|
||||
/// <summary>
|
||||
/// The date of the next metadata refresh. Null if auto-refresh is disabled.
|
||||
/// </summary>
|
||||
public DateTime? NextMetadataRefresh { get; set; }
|
||||
|
||||
public static DateTime ComputeNextRefreshDate(DateOnly airDate)
|
||||
{
|
||||
int days = DateOnly.FromDateTime(DateTime.UtcNow).DayNumber - airDate.DayNumber;
|
||||
return days switch
|
||||
{
|
||||
<= 4 => DateTime.UtcNow.AddDays(1),
|
||||
<= 21 => DateTime.UtcNow.AddDays(14),
|
||||
_ => DateTime.UtcNow.AddMonths(2)
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,49 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// An interface to represent a resource that can be retrieved from the database.
|
||||
/// </summary>
|
||||
public interface IResource : IQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// A unique ID for this type of resource. This can't be changed and duplicates are not allowed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// You don't need to specify an ID manually when creating a new resource,
|
||||
/// this field is automatically assigned by the <see cref="IRepository{T}"/>.
|
||||
/// </remarks>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A human-readable identifier that can be used instead of an ID.
|
||||
/// A slug must be unique for a type of resource but it can be changed.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// There is no setter for a slug since it can be computed from other fields.
|
||||
/// For example, a season slug is {ShowSlug}-s{SeasonNumber}.
|
||||
/// </remarks>
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; }
|
||||
}
|
||||
@@ -1,147 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// An interface representing items that contains images (like posters, thumbnails, logo, banners...)
|
||||
/// </summary>
|
||||
public interface IThumbnails
|
||||
{
|
||||
/// <summary>
|
||||
/// A poster is a 2/3 format image with the cover of the resource.
|
||||
/// </summary>
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A thumbnail is a 16/9 format image, it could ether be used as a background or as a preview but it usually
|
||||
/// is not an official image.
|
||||
/// </summary>
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A logo is a small image representing the resource.
|
||||
/// </summary>
|
||||
public Image? Logo { get; set; }
|
||||
}
|
||||
|
||||
[JsonConverter(typeof(ImageConvertor))]
|
||||
public class Image
|
||||
{
|
||||
/// <summary>
|
||||
/// A unique identifier for the image. Used for proper http caches.
|
||||
/// </summary>
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The original image from another server.
|
||||
/// </summary>
|
||||
public string Source { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A hash to display as placeholder while the image is loading.
|
||||
/// </summary>
|
||||
[MaxLength(32)]
|
||||
public string Blurhash { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The url to access the image in low quality.
|
||||
/// </summary>
|
||||
public string Low => $"/thumbnails/{Id}?quality=low";
|
||||
|
||||
/// <summary>
|
||||
/// The url to access the image in medium quality.
|
||||
/// </summary>
|
||||
public string Medium => $"/thumbnails/{Id}?quality=medium";
|
||||
|
||||
/// <summary>
|
||||
/// The url to access the image in high quality.
|
||||
/// </summary>
|
||||
public string High => $"/thumbnails/{Id}?quality=high";
|
||||
|
||||
public Image() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public Image(string source, string? blurhash = null)
|
||||
{
|
||||
Source = source;
|
||||
Blurhash = blurhash ?? "000000";
|
||||
}
|
||||
|
||||
//
|
||||
public class ImageConvertor : JsonConverter<Image>
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override Image? Read(
|
||||
ref Utf8JsonReader reader,
|
||||
Type typeToConvert,
|
||||
JsonSerializerOptions options
|
||||
)
|
||||
{
|
||||
if (reader.TokenType == JsonTokenType.String && reader.GetString() is string source)
|
||||
return new Image(source);
|
||||
using JsonDocument document = JsonDocument.ParseValue(ref reader);
|
||||
string? src = document.RootElement.GetProperty("Source").GetString();
|
||||
string? blurhash = document.RootElement.GetProperty("Blurhash").GetString();
|
||||
Guid? id = document.RootElement.GetProperty("Id").GetGuid();
|
||||
return new Image(src ?? string.Empty, blurhash) { Id = id ?? Guid.Empty };
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Write(
|
||||
Utf8JsonWriter writer,
|
||||
Image value,
|
||||
JsonSerializerOptions options
|
||||
)
|
||||
{
|
||||
writer.WriteStartObject();
|
||||
writer.WriteString("source", value.Source);
|
||||
writer.WriteString("blurhash", value.Blurhash);
|
||||
writer.WriteString("low", value.Low);
|
||||
writer.WriteString("medium", value.Medium);
|
||||
writer.WriteString("high", value.High);
|
||||
writer.WriteEndObject();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The quality of an image
|
||||
/// </summary>
|
||||
public enum ImageQuality
|
||||
{
|
||||
/// <summary>
|
||||
/// Small
|
||||
/// </summary>
|
||||
Low,
|
||||
|
||||
/// <summary>
|
||||
/// Medium
|
||||
/// </summary>
|
||||
Medium,
|
||||
|
||||
/// <summary>
|
||||
/// Large
|
||||
/// </summary>
|
||||
High,
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A container representing the response of a login or token refresh.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Initializes a new instance of the <see cref="JwtToken"/> class.
|
||||
/// </remarks>
|
||||
/// <param name="accessToken">The access token used to authorize requests.</param>
|
||||
/// <param name="refreshToken">The refresh token to retrieve a new access token.</param>
|
||||
/// <param name="expireIn">When the access token will expire.</param>
|
||||
public class JwtToken(string accessToken, string refreshToken, TimeSpan expireIn)
|
||||
{
|
||||
/// <summary>
|
||||
/// The type of this token (always a Bearer).
|
||||
/// </summary>
|
||||
[JsonPropertyName("token_type")]
|
||||
public string TokenType => "Bearer";
|
||||
|
||||
/// <summary>
|
||||
/// The access token used to authorize requests.
|
||||
/// </summary>
|
||||
[JsonPropertyName("access_token")]
|
||||
public string AccessToken { get; set; } = accessToken;
|
||||
|
||||
/// <summary>
|
||||
/// The refresh token used to retrieve a new access/refresh token when the access token has expired.
|
||||
/// </summary>
|
||||
[JsonPropertyName("refresh_token")]
|
||||
public string RefreshToken { get; set; } = refreshToken;
|
||||
|
||||
/// <summary>
|
||||
/// When the access token will expire. After this time, the refresh token should be used to retrieve.
|
||||
/// a new token.cs
|
||||
/// </summary>
|
||||
[JsonPropertyName("expire_in")]
|
||||
public TimeSpan ExpireIn => ExpireAt.Subtract(DateTime.UtcNow);
|
||||
|
||||
/// <summary>
|
||||
/// The exact date at which the access token will expire.
|
||||
/// </summary>
|
||||
[JsonPropertyName("expire_at")]
|
||||
public DateTime ExpireAt { get; set; } = DateTime.UtcNow + expireIn;
|
||||
}
|
||||
@@ -1,192 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using EntityFrameworkCore.Projectables;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A series or a movie.
|
||||
/// </summary>
|
||||
public class Movie
|
||||
: IQuery,
|
||||
IResource,
|
||||
IMetadata,
|
||||
IThumbnails,
|
||||
IAddedDate,
|
||||
IRefreshable,
|
||||
ILibraryItem,
|
||||
INews,
|
||||
IWatchlist
|
||||
{
|
||||
public static Sort DefaultSort => new Sort<Movie>.By(x => x.Name);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of this show.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A catchphrase for this movie.
|
||||
/// </summary>
|
||||
public string? Tagline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of alternative titles of this show.
|
||||
/// </summary>
|
||||
public string[] Aliases { get; set; } = Array.Empty<string>();
|
||||
|
||||
/// <summary>
|
||||
/// The path of the movie video file.
|
||||
/// </summary>
|
||||
public string Path { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The summary of this show.
|
||||
/// </summary>
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of tags that match this movie.
|
||||
/// </summary>
|
||||
public string[] Tags { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// The list of genres (themes) this show has.
|
||||
/// </summary>
|
||||
public List<Genre> Genres { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Is this show airing, not aired yet or finished?
|
||||
/// </summary>
|
||||
public Status Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How well this item is rated? (from 0 to 100).
|
||||
/// </summary>
|
||||
public int Rating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How long is this movie? (in minutes)
|
||||
/// </summary>
|
||||
public int? Runtime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date this movie aired.
|
||||
/// </summary>
|
||||
public DateOnly? AirDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[Column("air_date")]
|
||||
public DateOnly? StartAir => AirDate;
|
||||
|
||||
[JsonIgnore]
|
||||
[Column("air_date")]
|
||||
public DateOnly? EndAir => AirDate;
|
||||
|
||||
/// <summary>
|
||||
/// A video of a few minutes that tease the content.
|
||||
/// </summary>
|
||||
public string? Trailer { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataId> ExternalId { get; set; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime? NextMetadataRefresh { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Studio that made this show.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Guid? StudioId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Studio that made this show.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(StudioId))]
|
||||
public Studio? Studio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of collections that contains this show.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Collection>? Collections { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Links to watch this movie.
|
||||
/// </summary>
|
||||
public VideoLinks Links =>
|
||||
new() { Direct = $"/movie/{Slug}/direct", Hls = $"/movie/{Slug}/master.m3u8", };
|
||||
|
||||
[JsonIgnore]
|
||||
public ICollection<MovieWatchStatus>? Watched { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Metadata of what an user as started/planned to watch.
|
||||
/// </summary>
|
||||
[Projectable(UseMemberBody = nameof(_WatchStatus), OnlyOnInclude = true)]
|
||||
[LoadableRelation(
|
||||
Sql = "movie_watch_status",
|
||||
On = "movie_id = \"this\".id and \"relation\".user_id = [current_user]"
|
||||
)]
|
||||
public MovieWatchStatus? WatchStatus { get; set; }
|
||||
|
||||
// There is a global query filter to filter by user so we just need to do single.
|
||||
private MovieWatchStatus? _WatchStatus => Watched!.FirstOrDefault();
|
||||
|
||||
public Movie() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public Movie(string name)
|
||||
{
|
||||
if (name != null)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,151 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
using EntityFrameworkCore.Projectables;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A season of a <see cref="Show"/>.
|
||||
/// </summary>
|
||||
public class Season : IQuery, IResource, IMetadata, IThumbnails, IAddedDate, IRefreshable
|
||||
{
|
||||
public static Sort DefaultSort => new Sort<Season>.By(x => x.SeasonNumber);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[Computed]
|
||||
[MaxLength(256)]
|
||||
public string Slug
|
||||
{
|
||||
get
|
||||
{
|
||||
if (ShowSlug == null && Show == null)
|
||||
return $"{ShowId}-s{SeasonNumber}";
|
||||
return $"{ShowSlug ?? Show?.Slug}-s{SeasonNumber}";
|
||||
}
|
||||
private set
|
||||
{
|
||||
Match match = Regex.Match(value, @"(?<show>.+)-s(?<season>\d+)");
|
||||
|
||||
if (!match.Success)
|
||||
throw new ArgumentException(
|
||||
"Invalid season slug. Format: {showSlug}-s{seasonNumber}"
|
||||
);
|
||||
ShowSlug = match.Groups["show"].Value;
|
||||
SeasonNumber = int.Parse(match.Groups["season"].Value);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The slug of the Show that contain this episode. If this is not set, this season is ill-formed.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string? ShowSlug { private get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Show containing this season.
|
||||
/// </summary>
|
||||
public Guid ShowId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The show that contains this season.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(ShowId))]
|
||||
public Show? Show { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of this season. This can be set to 0 to indicate specials.
|
||||
/// </summary>
|
||||
public int SeasonNumber { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of this season.
|
||||
/// </summary>
|
||||
public string? Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A quick overview of this season.
|
||||
/// </summary>
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The starting air date of this season.
|
||||
/// </summary>
|
||||
public DateOnly? StartDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ending date of this season.
|
||||
/// </summary>
|
||||
public DateOnly? EndDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataId> ExternalId { get; set; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime? NextMetadataRefresh { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of episodes that this season contains.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Episode>? Episodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of episodes in this season.
|
||||
/// </summary>
|
||||
[Projectable(UseMemberBody = nameof(_EpisodesCount), OnlyOnInclude = true)]
|
||||
[NotMapped]
|
||||
[LoadableRelation(
|
||||
// language=PostgreSQL
|
||||
Projected = """
|
||||
(
|
||||
select
|
||||
count(*)::int
|
||||
from
|
||||
episodes as e
|
||||
where
|
||||
e.season_id = id) as episodes_count
|
||||
"""
|
||||
)]
|
||||
public int EpisodesCount { get; set; }
|
||||
|
||||
private int _EpisodesCount => Episodes!.Count;
|
||||
}
|
||||
@@ -1,283 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
using System.Linq;
|
||||
using System.Text.Json.Serialization;
|
||||
using EntityFrameworkCore.Projectables;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A series or a movie.
|
||||
/// </summary>
|
||||
public class Show
|
||||
: IQuery,
|
||||
IResource,
|
||||
IMetadata,
|
||||
IOnMerge,
|
||||
IThumbnails,
|
||||
IAddedDate,
|
||||
IRefreshable,
|
||||
ILibraryItem,
|
||||
IWatchlist
|
||||
{
|
||||
public static Sort DefaultSort => new Sort<Show>.By(x => x.Name);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The title of this show.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A catchphrase for this show.
|
||||
/// </summary>
|
||||
public string? Tagline { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of alternative titles of this show.
|
||||
/// </summary>
|
||||
public List<string> Aliases { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The summary of this show.
|
||||
/// </summary>
|
||||
public string? Overview { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A list of tags that match this movie.
|
||||
/// </summary>
|
||||
public List<string> Tags { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// The list of genres (themes) this show has.
|
||||
/// </summary>
|
||||
public List<Genre> Genres { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Is this show airing, not aired yet or finished?
|
||||
/// </summary>
|
||||
public Status Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// How well this item is rated? (from 0 to 100).
|
||||
/// </summary>
|
||||
public int Rating { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date this show started airing. It can be null if this is unknown.
|
||||
/// </summary>
|
||||
public DateOnly? StartAir { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date this show finished airing.
|
||||
/// It can also be null if this is unknown.
|
||||
/// </summary>
|
||||
public DateOnly? EndAir { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Poster { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Thumbnail { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Image? Logo { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A video of a few minutes that tease the content.
|
||||
/// </summary>
|
||||
public string? Trailer { get; set; }
|
||||
|
||||
[JsonIgnore]
|
||||
[Column("start_air")]
|
||||
public DateOnly? AirDate => StartAir;
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataId> ExternalId { get; set; } = new();
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime? NextMetadataRefresh { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the Studio that made this show.
|
||||
/// </summary>
|
||||
public Guid? StudioId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The Studio that made this show.
|
||||
/// </summary>
|
||||
[LoadableRelation(nameof(StudioId))]
|
||||
public Studio? Studio { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The different seasons in this show. If this is a movie, this list is always null or empty.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Season>? Seasons { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of episodes in this show.
|
||||
/// If this is a movie, there will be a unique episode (with the seasonNumber and episodeNumber set to null).
|
||||
/// Having an episode is necessary to store metadata and tracks.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Episode>? Episodes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of collections that contains this show.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Collection>? Collections { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The first episode of this show.
|
||||
/// </summary>
|
||||
[Projectable(UseMemberBody = nameof(_FirstEpisode), OnlyOnInclude = true)]
|
||||
[LoadableRelation(
|
||||
// language=PostgreSQL
|
||||
Sql = """
|
||||
select
|
||||
fe.* -- Episode as fe
|
||||
from (
|
||||
select
|
||||
e.*,
|
||||
row_number() over (partition by e.show_id order by e.absolute_number, e.season_number, e.episode_number) as number
|
||||
from
|
||||
episodes as e) as "fe"
|
||||
where
|
||||
fe.number <= 1
|
||||
""",
|
||||
On = "show_id = \"this\".id"
|
||||
)]
|
||||
public Episode? FirstEpisode { get; set; }
|
||||
|
||||
private Episode? _FirstEpisode =>
|
||||
Episodes!
|
||||
.OrderBy(x => x.AbsoluteNumber)
|
||||
.ThenBy(x => x.SeasonNumber)
|
||||
.ThenBy(x => x.EpisodeNumber)
|
||||
.FirstOrDefault();
|
||||
|
||||
/// <summary>
|
||||
/// The number of episodes in this show.
|
||||
/// </summary>
|
||||
[Projectable(UseMemberBody = nameof(_EpisodesCount), OnlyOnInclude = true)]
|
||||
[NotMapped]
|
||||
[LoadableRelation(
|
||||
// language=PostgreSQL
|
||||
Projected = """
|
||||
(
|
||||
select
|
||||
count(*)::int
|
||||
from
|
||||
episodes as e
|
||||
where
|
||||
e.show_id = "this".id) as episodes_count
|
||||
"""
|
||||
)]
|
||||
public int EpisodesCount { get; set; }
|
||||
|
||||
private int _EpisodesCount => Episodes!.Count;
|
||||
|
||||
[JsonIgnore]
|
||||
public ICollection<ShowWatchStatus>? Watched { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Metadata of what an user as started/planned to watch.
|
||||
/// </summary>
|
||||
[Projectable(UseMemberBody = nameof(_WatchStatus), OnlyOnInclude = true)]
|
||||
[LoadableRelation(
|
||||
Sql = "show_watch_status",
|
||||
On = "show_id = \"this\".id and \"relation\".user_id = [current_user]"
|
||||
)]
|
||||
public ShowWatchStatus? WatchStatus { get; set; }
|
||||
|
||||
// There is a global query filter to filter by user so we just need to do single.
|
||||
private ShowWatchStatus? _WatchStatus => Watched!.FirstOrDefault();
|
||||
|
||||
/// <inheritdoc />
|
||||
public void OnMerge(object merged)
|
||||
{
|
||||
if (Seasons != null)
|
||||
{
|
||||
foreach (Season season in Seasons)
|
||||
season.Show = this;
|
||||
}
|
||||
|
||||
if (Episodes != null)
|
||||
{
|
||||
foreach (Episode episode in Episodes)
|
||||
episode.Show = this;
|
||||
}
|
||||
}
|
||||
|
||||
public Show() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public Show(string name)
|
||||
{
|
||||
if (name != null)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The enum containing show's status.
|
||||
/// </summary>
|
||||
public enum Status
|
||||
{
|
||||
/// <summary>
|
||||
/// The status of the show is not known.
|
||||
/// </summary>
|
||||
Unknown,
|
||||
|
||||
/// <summary>
|
||||
/// The show has finished airing.
|
||||
/// </summary>
|
||||
Finished,
|
||||
|
||||
/// <summary>
|
||||
/// The show is still actively airing.
|
||||
/// </summary>
|
||||
Airing,
|
||||
|
||||
/// <summary>
|
||||
/// This show has not aired yet but has been announced.
|
||||
/// </summary>
|
||||
Planned
|
||||
}
|
||||
@@ -1,80 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A studio that make shows.
|
||||
/// </summary>
|
||||
public class Studio : IQuery, IResource, IMetadata
|
||||
{
|
||||
public static Sort DefaultSort => new Sort<Studio>.By(x => x.Name);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The name of this studio.
|
||||
/// </summary>
|
||||
public string Name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of shows that are made by this studio.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Show>? Shows { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The list of movies that are made by this studio.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public ICollection<Movie>? Movies { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public Dictionary<string, MetadataId> ExternalId { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Create a new, empty, <see cref="Studio"/>.
|
||||
/// </summary>
|
||||
public Studio() { }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Studio"/> with a specific name, the slug is calculated automatically.
|
||||
/// </summary>
|
||||
/// <param name="name">The name of the studio.</param>
|
||||
[JsonConstructor]
|
||||
public Studio(string name)
|
||||
{
|
||||
if (name != null)
|
||||
{
|
||||
Slug = Utility.ToSlug(name);
|
||||
Name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Text.Json.Serialization;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// A single user of the app.
|
||||
/// </summary>
|
||||
public class User : IQuery, IResource, IAddedDate
|
||||
{
|
||||
public static Sort DefaultSort => new Sort<User>.By(x => x.Username);
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid Id { get; set; }
|
||||
|
||||
/// <inheritdoc />
|
||||
[MaxLength(256)]
|
||||
public string Slug { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A username displayed to the user.
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user email address.
|
||||
/// </summary>
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user password (hashed, it can't be read like that). The hashing format is implementation defined.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public string? Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Does the user can sign-in with a password or only via oidc?
|
||||
/// </summary>
|
||||
public bool HasPassword => Password != null;
|
||||
|
||||
/// <summary>
|
||||
/// The list of permissions of the user. The format of this is implementation dependent.
|
||||
/// </summary>
|
||||
public string[] Permissions { get; set; } = Array.Empty<string>();
|
||||
|
||||
/// <inheritdoc />
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// User settings
|
||||
/// </summary>
|
||||
public Dictionary<string, string> Settings { get; set; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// User accounts on other services.
|
||||
/// </summary>
|
||||
public Dictionary<string, ExternalToken> ExternalId { get; set; } = new();
|
||||
|
||||
public User() { }
|
||||
|
||||
[JsonConstructor]
|
||||
public User(string username)
|
||||
{
|
||||
if (username != null)
|
||||
{
|
||||
Slug = Utility.ToSlug(username);
|
||||
Username = username;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ExternalToken
|
||||
{
|
||||
/// <summary>
|
||||
/// The id of this user on the external service.
|
||||
/// </summary>
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The username on the external service.
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The link to the user profile on this website. Null if it does not exist.
|
||||
/// </summary>
|
||||
public string? ProfileUrl { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// A jwt token used to interact with the service.
|
||||
/// Do not forget to refresh it when using it if necessary.
|
||||
/// </summary>
|
||||
public JwtToken Token { get; set; }
|
||||
}
|
||||
@@ -1,279 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Has the user started watching, is it planned?
|
||||
/// </summary>
|
||||
public enum WatchStatus
|
||||
{
|
||||
/// <summary>
|
||||
/// The user has already watched this.
|
||||
/// </summary>
|
||||
Completed,
|
||||
|
||||
/// <summary>
|
||||
/// The user started watching this but has not finished.
|
||||
/// </summary>
|
||||
Watching,
|
||||
|
||||
/// <summary>
|
||||
/// The user does not plan to continue watching.
|
||||
/// </summary>
|
||||
Droped,
|
||||
|
||||
/// <summary>
|
||||
/// The user has not started watching this but plans to.
|
||||
/// </summary>
|
||||
Planned,
|
||||
|
||||
/// <summary>
|
||||
/// The watch status was deleted and can not be retrived again.
|
||||
/// </summary>
|
||||
Deleted,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Metadata of what an user as started/planned to watch.
|
||||
/// </summary>
|
||||
[SqlFirstColumn(nameof(UserId))]
|
||||
public class MovieWatchStatus : IAddedDate
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the user that started watching this episode.
|
||||
/// </summary>
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user that started watching this episode.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the movie started.
|
||||
/// </summary>
|
||||
public Guid MovieId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Movie"/> started.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Movie Movie { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date at which this item was played.
|
||||
/// </summary>
|
||||
public DateTime? PlayedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Has the user started watching, is it planned?
|
||||
/// </summary>
|
||||
public WatchStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the movie (in seconds).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if the status is not Watching.
|
||||
/// </remarks>
|
||||
public int? WatchedTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the movie (in percentage between 0 and 100).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if the status is not Watching.
|
||||
/// </remarks>
|
||||
public int? WatchedPercent { get; set; }
|
||||
}
|
||||
|
||||
[SqlFirstColumn(nameof(UserId))]
|
||||
public class EpisodeWatchStatus : IAddedDate
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the user that started watching this episode.
|
||||
/// </summary>
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user that started watching this episode.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the episode started.
|
||||
/// </summary>
|
||||
public Guid? EpisodeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Episode"/> started.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Episode Episode { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date at which this item was played.
|
||||
/// </summary>
|
||||
public DateTime? PlayedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Has the user started watching, is it planned?
|
||||
/// </summary>
|
||||
public WatchStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the episode (in seconds).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if the status is not Watching.
|
||||
/// </remarks>
|
||||
public int? WatchedTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the episode (in percentage between 0 and 100).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if the status is not Watching or if the next episode is not started.
|
||||
/// </remarks>
|
||||
public int? WatchedPercent { get; set; }
|
||||
}
|
||||
|
||||
[SqlFirstColumn(nameof(UserId))]
|
||||
public class ShowWatchStatus : IAddedDate
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the user that started watching this episode.
|
||||
/// </summary>
|
||||
public Guid UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user that started watching this episode.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the show started.
|
||||
/// </summary>
|
||||
public Guid ShowId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The <see cref="Show"/> started.
|
||||
/// </summary>
|
||||
[JsonIgnore]
|
||||
public Show Show { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date at which this item was played.
|
||||
/// </summary>
|
||||
public DateTime? PlayedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Has the user started watching, is it planned?
|
||||
/// </summary>
|
||||
public WatchStatus Status { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The number of episodes the user has not seen.
|
||||
/// </summary>
|
||||
public int UnseenEpisodesCount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The ID of the episode started.
|
||||
/// </summary>
|
||||
public Guid? NextEpisodeId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The next <see cref="Episode"/> to watch.
|
||||
/// </summary>
|
||||
public Episode? NextEpisode { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the episode (in seconds).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if the status is not Watching or if the next episode is not started.
|
||||
/// </remarks>
|
||||
public int? WatchedTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the episode (in percentage between 0 and 100).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if the status is not Watching or if the next episode is not started.
|
||||
/// </remarks>
|
||||
public int? WatchedPercent { get; set; }
|
||||
}
|
||||
|
||||
public class WatchStatus<T> : IAddedDate
|
||||
{
|
||||
/// <summary>
|
||||
/// Has the user started watching, is it planned?
|
||||
/// </summary>
|
||||
public required WatchStatus Status { get; set; }
|
||||
|
||||
/// <inheritdoc/>
|
||||
public DateTime AddedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The date at which this item was played.
|
||||
/// </summary>
|
||||
public DateTime? PlayedDate { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the episode (in seconds).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if the status is not Watching or if the next episode is not started.
|
||||
/// </remarks>
|
||||
public int? WatchedTime { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where the player has stopped watching the episode (in percentage between 0 and 100).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Null if the status is not Watching or if the next episode is not started.
|
||||
/// </remarks>
|
||||
public int? WatchedPercent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user that started watching this episode.
|
||||
/// </summary>
|
||||
public required User User { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The episode/show/movie whose status changed
|
||||
/// </summary>
|
||||
public required T Resource { get; set; }
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// Results of a search request.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The search item's type.</typeparam>
|
||||
public class SearchPage<T> : Page<T>
|
||||
where T : IResource
|
||||
{
|
||||
public SearchPage(
|
||||
SearchResult result,
|
||||
string @this,
|
||||
string? previous,
|
||||
string? next,
|
||||
string first
|
||||
)
|
||||
: base(result.Items, @this, previous, next, first)
|
||||
{
|
||||
Query = result.Query;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The query of the search request.
|
||||
/// </summary>
|
||||
public string? Query { get; init; }
|
||||
|
||||
public class SearchResult
|
||||
{
|
||||
public string? Query { get; set; }
|
||||
|
||||
public ICollection<T> Items { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Authentication.Models;
|
||||
|
||||
/// <summary>
|
||||
/// List of well known claims of kyoo
|
||||
/// </summary>
|
||||
public static class Claims
|
||||
{
|
||||
/// <summary>
|
||||
/// The id of the user
|
||||
/// </summary>
|
||||
public static string Id => "id";
|
||||
|
||||
/// <summary>
|
||||
/// The name of the user
|
||||
/// </summary>
|
||||
public static string Name => "name";
|
||||
|
||||
/// <summary>
|
||||
/// The email of the user.
|
||||
/// </summary>
|
||||
public static string Email => "email";
|
||||
|
||||
/// <summary>
|
||||
/// The list of permissions that the user has.
|
||||
/// </summary>
|
||||
public static string Permissions => "permissions";
|
||||
|
||||
/// <summary>
|
||||
/// The type of the token (either "access" or "refresh").
|
||||
/// </summary>
|
||||
public static string Type => "type";
|
||||
|
||||
/// <summary>
|
||||
/// A guid used to identify a specific refresh token. This is only useful for the server to revokate tokens.
|
||||
/// </summary>
|
||||
public static string Guid => "guid";
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
/// <summary>
|
||||
/// A class containing constant numbers.
|
||||
/// </summary>
|
||||
public static class Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// A property to use on a Microsoft.AspNet.MVC.Route.Order property to mark it as an alternative route
|
||||
/// that won't be included on the swagger.
|
||||
/// </summary>
|
||||
public const int AlternativeRoute = 1;
|
||||
|
||||
/// <summary>
|
||||
/// A group name for <see cref="ApiDefinitionAttribute"/>. It should be used for endpoints used by users.
|
||||
/// </summary>
|
||||
public const string UsersGroup = "0:Users";
|
||||
|
||||
/// <summary>
|
||||
/// A group name for <see cref="ApiDefinitionAttribute"/>. It should be used for main resources of kyoo.
|
||||
/// </summary>
|
||||
public const string ResourcesGroup = "1:Resources";
|
||||
|
||||
/// <summary>
|
||||
/// A group name for <see cref="ApiDefinitionAttribute"/>.
|
||||
/// It should be used for sub resources of kyoo that help define the main resources.
|
||||
/// </summary>
|
||||
public const string MetadataGroup = "2:Metadata";
|
||||
|
||||
/// <summary>
|
||||
/// A group name for <see cref="ApiDefinitionAttribute"/>. It should be used for endpoints useful for playback.
|
||||
/// </summary>
|
||||
public const string WatchGroup = "3:Watch";
|
||||
|
||||
/// <summary>
|
||||
/// A group name for <see cref="ApiDefinitionAttribute"/>. It should be used for endpoints used by admins.
|
||||
/// </summary>
|
||||
public const string AdminGroup = "4:Admin";
|
||||
public const string OtherGroup = "5:Other";
|
||||
}
|
||||
@@ -1,369 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Sprache;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
public static class ParseHelper
|
||||
{
|
||||
public static Parser<T> ErrorMessage<T>(this Parser<T> @this, string message) =>
|
||||
input =>
|
||||
{
|
||||
IResult<T> result = @this(input);
|
||||
|
||||
return result.WasSuccessful
|
||||
? result
|
||||
: Result.Failure<T>(result.Remainder, message, result.Expectations);
|
||||
};
|
||||
|
||||
public static Parser<T> Error<T>(string message) =>
|
||||
input =>
|
||||
{
|
||||
return Result.Failure<T>(input, message, Array.Empty<string>());
|
||||
};
|
||||
}
|
||||
|
||||
public abstract record Filter
|
||||
{
|
||||
public static Filter<T>? And<T>(params Filter<T>?[] filters)
|
||||
{
|
||||
return filters
|
||||
.Where(x => x != null)
|
||||
.Aggregate(
|
||||
(Filter<T>?)null,
|
||||
(acc, filter) =>
|
||||
{
|
||||
if (acc == null)
|
||||
return filter;
|
||||
return new Filter<T>.And(acc, filter!);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static Filter<T>? Or<T>(params Filter<T>?[] filters)
|
||||
{
|
||||
return filters
|
||||
.Where(x => x != null)
|
||||
.Aggregate(
|
||||
(Filter<T>?)null,
|
||||
(acc, filter) =>
|
||||
{
|
||||
if (acc == null)
|
||||
return filter;
|
||||
return new Filter<T>.Or(acc, filter!);
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract record Filter<T> : Filter
|
||||
{
|
||||
public record And(Filter<T> First, Filter<T> Second) : Filter<T>;
|
||||
|
||||
public record Or(Filter<T> First, Filter<T> Second) : Filter<T>;
|
||||
|
||||
public record Not(Filter<T> Filter) : Filter<T>;
|
||||
|
||||
public record Eq(string Property, object? Value) : Filter<T>;
|
||||
|
||||
public record Ne(string Property, object? Value) : Filter<T>;
|
||||
|
||||
public record Gt(string Property, object Value) : Filter<T>;
|
||||
|
||||
public record Ge(string Property, object Value) : Filter<T>;
|
||||
|
||||
public record Lt(string Property, object Value) : Filter<T>;
|
||||
|
||||
public record Le(string Property, object Value) : Filter<T>;
|
||||
|
||||
public record Has(string Property, object Value) : Filter<T>;
|
||||
|
||||
/// <summary>
|
||||
/// Internal filter used for keyset paginations to resume random sorts.
|
||||
/// The pseudo sql is md5(seed || table.id) = md5(seed || 'hardCodedId')
|
||||
/// </summary>
|
||||
public record CmpRandom(string cmp, string Seed, Guid ReferenceId) : Filter<T>;
|
||||
|
||||
/// <summary>
|
||||
/// Internal filter used only in EF with hard coded lamdas (used for relations).
|
||||
/// </summary>
|
||||
public record Lambda(Expression<Func<T, bool>> Inner) : Filter<T>;
|
||||
|
||||
public static class FilterParsers
|
||||
{
|
||||
public static readonly Parser<Filter<T>> Filter = Parse
|
||||
.Ref(() => Bracket)
|
||||
.Or(Parse.Ref(() => Not))
|
||||
.Or(Parse.Ref(() => Eq))
|
||||
.Or(Parse.Ref(() => Ne))
|
||||
.Or(Parse.Ref(() => Gt))
|
||||
.Or(Parse.Ref(() => Ge))
|
||||
.Or(Parse.Ref(() => Lt))
|
||||
.Or(Parse.Ref(() => Le))
|
||||
.Or(Parse.Ref(() => Has));
|
||||
|
||||
public static readonly Parser<Filter<T>> CompleteFilter = Parse
|
||||
.Ref(() => Or)
|
||||
.Or(Parse.Ref(() => And))
|
||||
.Or(Filter);
|
||||
|
||||
public static readonly Parser<Filter<T>> Bracket =
|
||||
from open in Parse.Char('(').Token()
|
||||
from filter in CompleteFilter
|
||||
from close in Parse.Char(')').Token()
|
||||
select filter;
|
||||
|
||||
public static readonly Parser<IEnumerable<char>> AndOperator = Parse
|
||||
.IgnoreCase("and")
|
||||
.Or(Parse.String("&&"))
|
||||
.Token();
|
||||
|
||||
public static readonly Parser<IEnumerable<char>> OrOperator = Parse
|
||||
.IgnoreCase("or")
|
||||
.Or(Parse.String("||"))
|
||||
.Token();
|
||||
|
||||
public static readonly Parser<Filter<T>> And = Parse.ChainOperator(
|
||||
AndOperator,
|
||||
Filter,
|
||||
(_, a, b) => new And(a, b)
|
||||
);
|
||||
|
||||
public static readonly Parser<Filter<T>> Or = Parse.ChainOperator(
|
||||
OrOperator,
|
||||
And.Or(Filter),
|
||||
(_, a, b) => new Or(a, b)
|
||||
);
|
||||
|
||||
public static readonly Parser<Filter<T>> Not =
|
||||
from not in Parse.IgnoreCase("not").Or(Parse.String("!")).Token()
|
||||
from filter in CompleteFilter
|
||||
select new Not(filter);
|
||||
|
||||
private static Parser<object> _GetValueParser(Type type)
|
||||
{
|
||||
Type? nullable = Nullable.GetUnderlyingType(type);
|
||||
if (nullable != null)
|
||||
{
|
||||
return from value in _GetValueParser(nullable) select value;
|
||||
}
|
||||
|
||||
if (type == typeof(int))
|
||||
return Parse.Number.Select(x => int.Parse(x) as object);
|
||||
|
||||
if (type == typeof(float))
|
||||
{
|
||||
return from a in Parse.Number
|
||||
from dot in Parse.Char('.')
|
||||
from b in Parse.Number
|
||||
select float.Parse($"{a}.{b}") as object;
|
||||
}
|
||||
|
||||
if (type == typeof(Guid))
|
||||
{
|
||||
return from guid in Parse.Regex(
|
||||
@"[({]?[a-fA-F0-9]{8}[-]?([a-fA-F0-9]{4}[-]?){3}[a-fA-F0-9]{12}[})]?",
|
||||
"Guid"
|
||||
)
|
||||
select Guid.Parse(guid) as object;
|
||||
}
|
||||
|
||||
if (type == typeof(string))
|
||||
{
|
||||
return (
|
||||
from lq in Parse.Char('"').Or(Parse.Char('\''))
|
||||
from str in Parse.AnyChar.Where(x => x != lq).Many().Text()
|
||||
from rq in Parse.Char(lq)
|
||||
select str
|
||||
).Or(Parse.LetterOrDigit.Many().Text());
|
||||
}
|
||||
|
||||
if (type.IsEnum)
|
||||
{
|
||||
return Parse
|
||||
.LetterOrDigit.Many()
|
||||
.Text()
|
||||
.Then(x =>
|
||||
{
|
||||
if (Enum.TryParse(type, x, true, out object? value))
|
||||
return Parse.Return(value);
|
||||
return ParseHelper.Error<object>($"Invalid enum value. Unexpected {x}");
|
||||
});
|
||||
}
|
||||
|
||||
if (type == typeof(DateTime) || type == typeof(DateOnly))
|
||||
{
|
||||
return from year in Parse.Digit.Repeat(4).Text().Select(int.Parse)
|
||||
from yd in Parse.Char('-')
|
||||
from month in Parse.Digit.Repeat(2).Text().Select(int.Parse)
|
||||
from md in Parse.Char('-')
|
||||
from day in Parse.Digit.Repeat(2).Text().Select(int.Parse)
|
||||
select type == typeof(DateTime)
|
||||
? new DateTime(year, month, day) as object
|
||||
: new DateOnly(year, month, day) as object;
|
||||
}
|
||||
|
||||
if (typeof(IEnumerable).IsAssignableFrom(type))
|
||||
return ParseHelper.Error<object>(
|
||||
"Can't filter a list with a default comparator, use the 'has' filter."
|
||||
);
|
||||
return ParseHelper.Error<object>("Unfilterable field found");
|
||||
}
|
||||
|
||||
private static Parser<Filter<T>> _GetOperationParser(
|
||||
Parser<object> op,
|
||||
Func<string, object, Filter<T>> apply,
|
||||
Func<Type, Parser<object?>>? customTypeParser = null
|
||||
)
|
||||
{
|
||||
Parser<string> property = Parse.LetterOrDigit.AtLeastOnce().Text();
|
||||
|
||||
return property.Then(prop =>
|
||||
{
|
||||
Type[] types =
|
||||
typeof(T).GetCustomAttribute<OneOfAttribute>()?.Types ?? new[] { typeof(T) };
|
||||
|
||||
if (string.Equals(prop, "kind", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return from eq in op
|
||||
from val in types
|
||||
.Select(x => Parse.IgnoreCase(x.Name).Text())
|
||||
.Aggregate(
|
||||
null as Parser<string>,
|
||||
(acc, x) => acc == null ? x : Parse.Or(acc, x)
|
||||
)
|
||||
select apply("kind", val);
|
||||
}
|
||||
|
||||
PropertyInfo? propInfo = types
|
||||
.Select(x =>
|
||||
x.GetProperty(
|
||||
prop,
|
||||
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance
|
||||
)
|
||||
)
|
||||
.FirstOrDefault();
|
||||
if (propInfo == null)
|
||||
return ParseHelper.Error<Filter<T>>($"The given filter '{prop}' is invalid.");
|
||||
|
||||
Parser<object?> value =
|
||||
customTypeParser != null
|
||||
? customTypeParser(propInfo.PropertyType)
|
||||
: _GetValueParser(propInfo.PropertyType);
|
||||
|
||||
return from eq in op
|
||||
from val in value
|
||||
select apply(propInfo.Name, val);
|
||||
});
|
||||
}
|
||||
|
||||
public static readonly Parser<Filter<T>> Eq = _GetOperationParser(
|
||||
Parse.IgnoreCase("eq").Or(Parse.String("=")).Token(),
|
||||
(property, value) => new Eq(property, value),
|
||||
(Type type) =>
|
||||
{
|
||||
Type? inner = Nullable.GetUnderlyingType(type);
|
||||
if (inner == null)
|
||||
return _GetValueParser(type);
|
||||
return Parse
|
||||
.String("null")
|
||||
.Token()
|
||||
.Return((object?)null)
|
||||
.Or(_GetValueParser(inner));
|
||||
}
|
||||
);
|
||||
|
||||
public static readonly Parser<Filter<T>> Ne = _GetOperationParser(
|
||||
Parse.IgnoreCase("ne").Or(Parse.String("!=")).Token(),
|
||||
(property, value) => new Ne(property, value),
|
||||
(Type type) =>
|
||||
{
|
||||
Type? inner = Nullable.GetUnderlyingType(type);
|
||||
if (inner == null)
|
||||
return _GetValueParser(type);
|
||||
return Parse
|
||||
.String("null")
|
||||
.Token()
|
||||
.Return((object?)null)
|
||||
.Or(_GetValueParser(inner));
|
||||
}
|
||||
);
|
||||
|
||||
public static readonly Parser<Filter<T>> Gt = _GetOperationParser(
|
||||
Parse.IgnoreCase("gt").Or(Parse.String(">")).Token(),
|
||||
(property, value) => new Gt(property, value)
|
||||
);
|
||||
|
||||
public static readonly Parser<Filter<T>> Ge = _GetOperationParser(
|
||||
Parse.IgnoreCase("ge").Or(Parse.IgnoreCase("gte")).Or(Parse.String(">=")).Token(),
|
||||
(property, value) => new Ge(property, value)
|
||||
);
|
||||
|
||||
public static readonly Parser<Filter<T>> Lt = _GetOperationParser(
|
||||
Parse.IgnoreCase("lt").Or(Parse.String("<")).Token(),
|
||||
(property, value) => new Lt(property, value)
|
||||
);
|
||||
|
||||
public static readonly Parser<Filter<T>> Le = _GetOperationParser(
|
||||
Parse.IgnoreCase("le").Or(Parse.IgnoreCase("lte")).Or(Parse.String("<=")).Token(),
|
||||
(property, value) => new Le(property, value)
|
||||
);
|
||||
|
||||
public static readonly Parser<Filter<T>> Has = _GetOperationParser(
|
||||
Parse.IgnoreCase("has").Token(),
|
||||
(property, value) => new Has(property, value),
|
||||
(Type type) =>
|
||||
{
|
||||
if (typeof(IEnumerable).IsAssignableFrom(type) && type != typeof(string))
|
||||
return _GetValueParser(
|
||||
type.GetElementType() ?? type.GenericTypeArguments.First()
|
||||
);
|
||||
return ParseHelper.Error<object>("Can't use 'has' on a non-list.");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public static Filter<T>? From(string? filter)
|
||||
{
|
||||
if (filter == null)
|
||||
return null;
|
||||
|
||||
try
|
||||
{
|
||||
IResult<Filter<T>> ret = FilterParsers.CompleteFilter.End().TryParse(filter);
|
||||
if (ret.WasSuccessful)
|
||||
return ret.Value;
|
||||
throw new ValidationException(
|
||||
$"Could not parse filter argument: {ret.Message}. Not parsed: {filter[ret.Remainder.Position..]}"
|
||||
);
|
||||
}
|
||||
catch (ParseException ex)
|
||||
{
|
||||
throw new ValidationException($"Could not parse filter argument: {ex.Message}.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,245 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
/// <summary>
|
||||
/// A class that represent a resource. It is made to be used as a parameter in a query and not used somewhere else
|
||||
/// on the application.
|
||||
/// This class allow routes to be used via ether IDs or Slugs, this is suitable for every <see cref="IResource"/>.
|
||||
/// </summary>
|
||||
[TypeConverter(typeof(IdentifierConvertor))]
|
||||
public class Identifier
|
||||
{
|
||||
/// <summary>
|
||||
/// The ID of the resource or null if the slug is specified.
|
||||
/// </summary>
|
||||
private readonly Guid? _id;
|
||||
|
||||
/// <summary>
|
||||
/// The slug of the resource or null if the id is specified.
|
||||
/// </summary>
|
||||
private readonly string? _slug;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Identifier"/> for the given id.
|
||||
/// </summary>
|
||||
/// <param name="id">The id of the resource.</param>
|
||||
public Identifier(Guid id)
|
||||
{
|
||||
_id = id;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Identifier"/> for the given slug.
|
||||
/// </summary>
|
||||
/// <param name="slug">The slug of the resource.</param>
|
||||
public Identifier(string slug)
|
||||
{
|
||||
_slug = slug;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Pattern match out of the identifier to a resource.
|
||||
/// </summary>
|
||||
/// <param name="idFunc">The function to match the ID to a type <typeparamref name="T"/>.</param>
|
||||
/// <param name="slugFunc">The function to match the slug to a type <typeparamref name="T"/>.</param>
|
||||
/// <typeparam name="T">The return type that will be converted to from an ID or a slug.</typeparam>
|
||||
/// <returns>
|
||||
/// The result of the <paramref name="idFunc"/> or <paramref name="slugFunc"/> depending on the pattern.
|
||||
/// </returns>
|
||||
/// <example>
|
||||
/// Example usage:
|
||||
/// <code lang="csharp">
|
||||
/// T ret = await identifier.Match(
|
||||
/// id => _repository.GetOrDefault(id),
|
||||
/// slug => _repository.GetOrDefault(slug)
|
||||
/// );
|
||||
/// </code>
|
||||
/// </example>
|
||||
public T Match<T>(Func<Guid, T> idFunc, Func<string, T> slugFunc)
|
||||
{
|
||||
return _id.HasValue ? idFunc(_id.Value) : slugFunc(_slug!);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Match a custom type to an identifier. This can be used for wrapped resources (see example for more details).
|
||||
/// </summary>
|
||||
/// <param name="idGetter">An expression to retrieve an ID from the type <typeparamref name="T"/>.</param>
|
||||
/// <param name="slugGetter">An expression to retrieve a slug from the type <typeparamref name="T"/>.</param>
|
||||
/// <typeparam name="T">The type to match against this identifier.</typeparam>
|
||||
/// <returns>An expression to match the type <typeparamref name="T"/> to this identifier.</returns>
|
||||
/// <example>
|
||||
/// <code lang="csharp">
|
||||
/// identifier.Matcher<Season>(x => x.ShowID, x => x.Show.Slug)
|
||||
/// </code>
|
||||
/// </example>
|
||||
public Filter<T> Matcher<T>(
|
||||
Expression<Func<T, Guid>> idGetter,
|
||||
Expression<Func<T, string>> slugGetter
|
||||
)
|
||||
{
|
||||
ConstantExpression self = Expression.Constant(_id.HasValue ? _id.Value : _slug);
|
||||
BinaryExpression equal = Expression.Equal(
|
||||
_id.HasValue ? idGetter.Body : slugGetter.Body,
|
||||
self
|
||||
);
|
||||
ICollection<ParameterExpression> parameters = _id.HasValue
|
||||
? idGetter.Parameters
|
||||
: slugGetter.Parameters;
|
||||
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(equal, parameters);
|
||||
return new Filter<T>.Lambda(lambda);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A matcher overload for nullable IDs. See
|
||||
/// <see cref="Matcher{T}(Expression{Func{T,Guid}},Expression{Func{T,string}})"/>
|
||||
/// for more details.
|
||||
/// </summary>
|
||||
/// <param name="idGetter">An expression to retrieve an ID from the type <typeparamref name="T"/>.</param>
|
||||
/// <param name="slugGetter">An expression to retrieve a slug from the type <typeparamref name="T"/>.</param>
|
||||
/// <typeparam name="T">The type to match against this identifier.</typeparam>
|
||||
/// <returns>An expression to match the type <typeparamref name="T"/> to this identifier.</returns>
|
||||
public Filter<T> Matcher<T>(
|
||||
Expression<Func<T, Guid?>> idGetter,
|
||||
Expression<Func<T, string>> slugGetter
|
||||
)
|
||||
{
|
||||
ConstantExpression self = Expression.Constant(_id.HasValue ? _id.Value : _slug);
|
||||
BinaryExpression equal = Expression.Equal(
|
||||
_id.HasValue ? idGetter.Body : slugGetter.Body,
|
||||
self
|
||||
);
|
||||
ICollection<ParameterExpression> parameters = _id.HasValue
|
||||
? idGetter.Parameters
|
||||
: slugGetter.Parameters;
|
||||
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(equal, parameters);
|
||||
return new Filter<T>.Lambda(lambda);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return true if this <see cref="Identifier"/> match a resource.
|
||||
/// </summary>
|
||||
/// <param name="resource">The resource to match</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the <paramref name="resource"/> match this identifier, <c>false</c> otherwise.
|
||||
/// </returns>
|
||||
public bool IsSame(IResource resource)
|
||||
{
|
||||
return Match(id => resource.Id == id, slug => resource.Slug == slug);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a filter to get this <see cref="Identifier"/> match a given resource.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of resource to match against.</typeparam>
|
||||
/// <returns>
|
||||
/// <c>true</c> if the given resource match this identifier, <c>false</c> otherwise.
|
||||
/// </returns>
|
||||
public Filter<T> IsSame<T>()
|
||||
where T : IResource
|
||||
{
|
||||
return _id.HasValue ? new Filter<T>.Eq("Id", _id.Value) : new Filter<T>.Eq("Slug", _slug!);
|
||||
}
|
||||
|
||||
public bool Is(Guid uid)
|
||||
{
|
||||
return _id.HasValue && _id.Value == uid;
|
||||
}
|
||||
|
||||
public bool Is(string slug)
|
||||
{
|
||||
return !_id.HasValue && _slug == slug;
|
||||
}
|
||||
|
||||
private Expression<Func<T, bool>> _IsSameExpression<T>()
|
||||
where T : IResource
|
||||
{
|
||||
return _id.HasValue ? x => x.Id == _id.Value : x => x.Slug == _slug;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return an expression that return true if this <see cref="Identifier"/> is containing in a collection.
|
||||
/// </summary>
|
||||
/// <param name="listGetter">An expression to retrieve the list to check.</param>
|
||||
/// <typeparam name="T">The type that contain the list to check.</typeparam>
|
||||
/// <typeparam name="T2">The type of resource to check this identifier against.</typeparam>
|
||||
/// <returns>An expression to check if this <see cref="Identifier"/> is contained.</returns>
|
||||
public Filter<T> IsContainedIn<T, T2>(Expression<Func<T, IEnumerable<T2>?>> listGetter)
|
||||
where T2 : IResource
|
||||
{
|
||||
MethodInfo method = typeof(Enumerable)
|
||||
.GetMethods()
|
||||
.Where(x => x.Name == nameof(Enumerable.Any))
|
||||
.FirstOrDefault(x => x.GetParameters().Length == 2)!
|
||||
.MakeGenericMethod(typeof(T2));
|
||||
MethodCallExpression call = Expression.Call(
|
||||
null,
|
||||
method,
|
||||
listGetter.Body,
|
||||
_IsSameExpression<T2>()
|
||||
);
|
||||
Expression<Func<T, bool>> lambda = Expression.Lambda<Func<T, bool>>(
|
||||
call,
|
||||
listGetter.Parameters
|
||||
);
|
||||
return new Filter<T>.Lambda(lambda);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return _id.HasValue ? _id.Value.ToString() : _slug!;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A custom <see cref="TypeConverter"/> used to convert int or strings to an <see cref="Identifier"/>.
|
||||
/// </summary>
|
||||
public class IdentifierConvertor : TypeConverter
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
|
||||
{
|
||||
if (sourceType == typeof(Guid) || sourceType == typeof(string))
|
||||
return true;
|
||||
return base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override object ConvertFrom(
|
||||
ITypeDescriptorContext? context,
|
||||
CultureInfo? culture,
|
||||
object value
|
||||
)
|
||||
{
|
||||
if (value is Guid id)
|
||||
return new Identifier(id);
|
||||
if (value is not string slug)
|
||||
return base.ConvertFrom(context, culture, value)!;
|
||||
return Guid.TryParse(slug, out id) ? new Identifier(id) : new Identifier(slug);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,109 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
public class Include
|
||||
{
|
||||
/// <summary>
|
||||
/// The aditional fields to include in the result.
|
||||
/// </summary>
|
||||
public ICollection<Metadata> Metadatas { get; set; } = ArraySegment<Metadata>.Empty;
|
||||
|
||||
public abstract record Metadata(string Name);
|
||||
|
||||
public record SingleRelation(string Name, Type type, string RelationIdName) : Metadata(Name);
|
||||
|
||||
public record CustomRelation(string Name, Type type, string Sql, string? On, Type Declaring)
|
||||
: Metadata(Name);
|
||||
|
||||
public record ProjectedRelation(string Name, string Sql) : Metadata(Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The aditional fields to include in the result.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type related to the new fields</typeparam>
|
||||
public class Include<T> : Include
|
||||
{
|
||||
/// <summary>
|
||||
/// The aditional fields names to include in the result.
|
||||
/// </summary>
|
||||
public ICollection<string> Fields => Metadatas.Select(x => x.Name).ToList();
|
||||
|
||||
public Include() { }
|
||||
|
||||
public Include(params string[] fields)
|
||||
{
|
||||
Type[] types = typeof(T).GetCustomAttribute<OneOfAttribute>()?.Types ?? new[] { typeof(T) };
|
||||
Metadatas = fields
|
||||
.SelectMany(key =>
|
||||
{
|
||||
var relations = types
|
||||
.Select(x =>
|
||||
x.GetProperty(
|
||||
key,
|
||||
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance
|
||||
)!
|
||||
)
|
||||
.Select(prop =>
|
||||
(prop, attr: prop?.GetCustomAttribute<LoadableRelationAttribute>()!)
|
||||
)
|
||||
.Where(x => x.prop != null && x.attr != null)
|
||||
.ToList();
|
||||
if (!relations.Any())
|
||||
throw new ValidationException($"No loadable relation with the name {key}.");
|
||||
return relations
|
||||
.Select(x =>
|
||||
{
|
||||
(PropertyInfo prop, LoadableRelationAttribute attr) = x;
|
||||
|
||||
if (attr.RelationID != null)
|
||||
return new SingleRelation(prop.Name, prop.PropertyType, attr.RelationID)
|
||||
as Metadata;
|
||||
if (attr.Sql != null)
|
||||
return new CustomRelation(
|
||||
prop.Name,
|
||||
prop.PropertyType,
|
||||
attr.Sql,
|
||||
attr.On,
|
||||
prop.DeclaringType!
|
||||
);
|
||||
if (attr.Projected != null)
|
||||
return new ProjectedRelation(prop.Name, attr.Projected);
|
||||
throw new NotImplementedException();
|
||||
})
|
||||
.Distinct();
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
public static Include<T> From(string? fields)
|
||||
{
|
||||
if (string.IsNullOrEmpty(fields))
|
||||
return new Include<T>();
|
||||
return new Include<T>(fields.Split(','));
|
||||
}
|
||||
}
|
||||
@@ -1,72 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Information about the pagination. How many items should be displayed and where to start.
|
||||
/// </summary>
|
||||
public class Pagination
|
||||
{
|
||||
/// <summary>
|
||||
/// The count of items to return.
|
||||
/// </summary>
|
||||
public int Limit { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Where to start? Using the given sort.
|
||||
/// </summary>
|
||||
public Guid? AfterID { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Should the previous page be returned instead of the next?
|
||||
/// </summary>
|
||||
public bool Reverse { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Pagination"/> with default values.
|
||||
/// </summary>
|
||||
public Pagination()
|
||||
{
|
||||
Limit = 50;
|
||||
AfterID = null;
|
||||
Reverse = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Pagination"/> instance.
|
||||
/// </summary>
|
||||
/// <param name="count">Set the <see cref="Limit"/> value</param>
|
||||
/// <param name="afterID">Set the <see cref="AfterID"/> value. If not specified, it will start from the start</param>
|
||||
/// <param name="reverse">Should the previous page be returned instead of the next?</param>
|
||||
public Pagination(int count, Guid? afterID = null, bool reverse = false)
|
||||
{
|
||||
Limit = count;
|
||||
AfterID = afterID;
|
||||
Reverse = reverse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Implicitly create a new pagination from a limit number.
|
||||
/// </summary>
|
||||
/// <param name="limit">Set the <see cref="Limit"/> value</param>
|
||||
/// <returns>A new <see cref="Pagination"/> instance</returns>
|
||||
public static implicit operator Pagination(int limit) => new(limit);
|
||||
}
|
||||
@@ -1,56 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
|
||||
namespace Kyoo.Abstractions.Models.Utils;
|
||||
|
||||
/// <summary>
|
||||
/// The list of errors that where made in the request.
|
||||
/// </summary>
|
||||
public class RequestError
|
||||
{
|
||||
/// <summary>
|
||||
/// The list of errors that where made in the request.
|
||||
/// </summary>
|
||||
/// <example><c>["InvalidFilter: no field 'startYear' on a collection"]</c></example>
|
||||
public string[] Errors { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="RequestError"/> with one error.
|
||||
/// </summary>
|
||||
/// <param name="error">The error to specify in the response.</param>
|
||||
public RequestError(string error)
|
||||
{
|
||||
if (error == null)
|
||||
throw new ArgumentNullException(nameof(error));
|
||||
Errors = new[] { error };
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="RequestError"/> with multiple errors.
|
||||
/// </summary>
|
||||
/// <param name="errors">The errors to specify in the response.</param>
|
||||
public RequestError(string[] errors)
|
||||
{
|
||||
if (errors == null || !errors.Any())
|
||||
throw new ArgumentException("Errors must be non null and not empty", nameof(errors));
|
||||
Errors = errors;
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
/// <summary>
|
||||
/// Information about the pagination. How many items should be displayed and where to start.
|
||||
/// </summary>
|
||||
public class SearchPagination
|
||||
{
|
||||
/// <summary>
|
||||
/// The count of items to return.
|
||||
/// </summary>
|
||||
public int Limit { get; set; } = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Where to start? How many items to skip?
|
||||
/// </summary>
|
||||
public int? Skip { get; set; }
|
||||
}
|
||||
@@ -1,137 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using Kyoo.Utils;
|
||||
|
||||
namespace Kyoo.Abstractions.Controllers;
|
||||
|
||||
public record Sort;
|
||||
|
||||
/// <summary>
|
||||
/// Information about how a query should be sorted. What factor should decide the sort and in which order.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">For witch type this sort applies</typeparam>
|
||||
public record Sort<T> : Sort
|
||||
where T : IQuery
|
||||
{
|
||||
/// <summary>
|
||||
/// Sort by a specific key
|
||||
/// </summary>
|
||||
/// <param name="Key">The sort keys. This members will be used to sort the results.</param>
|
||||
/// <param name="Desendant">
|
||||
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
|
||||
/// </param>
|
||||
public record By(string Key, bool Desendant = false) : Sort<T>
|
||||
{
|
||||
/// <summary>
|
||||
/// Sort by a specific key
|
||||
/// </summary>
|
||||
/// <param name="key">The sort keys. This members will be used to sort the results.</param>
|
||||
/// <param name="desendant">
|
||||
/// If this is set to true, items will be sorted in descend order else, they will be sorted in ascendant order.
|
||||
/// </param>
|
||||
public By(Expression<Func<T, object?>> key, bool desendant = false)
|
||||
: this(Utility.GetPropertyName(key), desendant) { }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sort by multiple keys.
|
||||
/// </summary>
|
||||
/// <param name="List">The list of keys to sort by.</param>
|
||||
public record Conglomerate(params Sort<T>[] List) : Sort<T>;
|
||||
|
||||
/// <summary>Sort randomly items</summary>
|
||||
public record Random(uint Seed) : Sort<T>
|
||||
{
|
||||
public Random()
|
||||
: this(0)
|
||||
{
|
||||
uint seed = BitConverter.ToUInt32(
|
||||
BitConverter.GetBytes(new System.Random().Next(int.MinValue, int.MaxValue)),
|
||||
0
|
||||
);
|
||||
Seed = seed;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>The default sort method for the given type.</summary>
|
||||
public record Default : Sort<T>
|
||||
{
|
||||
public void Deconstruct(out Sort<T> value)
|
||||
{
|
||||
value = (Sort<T>)T.DefaultSort;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new <see cref="Sort{T}"/> instance from a key's name (case insensitive).
|
||||
/// </summary>
|
||||
/// <param name="sortBy">A key name with an optional order specifier. Format: "key:asc", "key:desc" or "key".</param>
|
||||
/// <param name="seed">The random seed.</param>
|
||||
/// <exception cref="ArgumentException">An invalid key or sort specifier as been given.</exception>
|
||||
/// <returns>A <see cref="Sort{T}"/> for the given string</returns>
|
||||
public static Sort<T> From(string? sortBy, uint seed)
|
||||
{
|
||||
if (string.IsNullOrEmpty(sortBy) || sortBy == "default")
|
||||
return new Default();
|
||||
if (sortBy == "random")
|
||||
return new Random(seed);
|
||||
if (sortBy.Contains(','))
|
||||
return new Conglomerate(sortBy.Split(',').Select(x => From(x, seed)).ToArray());
|
||||
|
||||
if (sortBy.StartsWith("random:"))
|
||||
{
|
||||
if (uint.TryParse(sortBy["random:".Length..], out uint sseed))
|
||||
return new Random(sseed);
|
||||
throw new ValidationException("Invalid random seed specified. Expected a number.");
|
||||
}
|
||||
|
||||
string key = sortBy.Contains(':') ? sortBy[..sortBy.IndexOf(':')] : sortBy;
|
||||
string? order = sortBy.Contains(':') ? sortBy[(sortBy.IndexOf(':') + 1)..] : null;
|
||||
bool desendant = order switch
|
||||
{
|
||||
"desc" => true,
|
||||
"asc" => false,
|
||||
null => false,
|
||||
_
|
||||
=> throw new ValidationException(
|
||||
$"The sort order, if set, should be :asc or :desc but it was :{order}."
|
||||
)
|
||||
};
|
||||
|
||||
Type[] types = typeof(T).GetCustomAttribute<OneOfAttribute>()?.Types ?? new[] { typeof(T) };
|
||||
PropertyInfo? property = types
|
||||
.Select(x =>
|
||||
x.GetProperty(
|
||||
key,
|
||||
BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance
|
||||
)
|
||||
)
|
||||
.FirstOrDefault(x => x != null);
|
||||
if (property == null)
|
||||
throw new ValidationException("The given sort key is not valid.");
|
||||
return new By(property.Name, desendant);
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Abstractions.Models;
|
||||
|
||||
/// <summary>
|
||||
/// The links to see a movie or an episode.
|
||||
/// </summary>
|
||||
public class VideoLinks
|
||||
{
|
||||
/// <summary>
|
||||
/// The direct link to the unprocessed video (pristine quality).
|
||||
/// </summary>
|
||||
public string Direct { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The link to an HLS master playlist containing all qualities available for this video.
|
||||
/// </summary>
|
||||
public string Hls { get; set; }
|
||||
}
|
||||
@@ -1,51 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
|
||||
namespace Kyoo.Utils;
|
||||
|
||||
public sealed class ExpressionArgumentReplacer : ExpressionVisitor
|
||||
{
|
||||
private readonly Dictionary<ParameterExpression, Expression> _mapping;
|
||||
|
||||
public ExpressionArgumentReplacer(Dictionary<ParameterExpression, Expression> dict)
|
||||
{
|
||||
_mapping = dict;
|
||||
}
|
||||
|
||||
protected override Expression VisitParameter(ParameterExpression node)
|
||||
{
|
||||
if (_mapping.TryGetValue(node, out Expression? mappedArgument))
|
||||
return Visit(mappedArgument);
|
||||
return base.VisitParameter(node);
|
||||
}
|
||||
|
||||
public static Expression ReplaceParams(
|
||||
Expression expression,
|
||||
IEnumerable<ParameterExpression> epxParams,
|
||||
params ParameterExpression[] param
|
||||
)
|
||||
{
|
||||
ExpressionArgumentReplacer replacer =
|
||||
new(epxParams.Zip(param).ToDictionary(x => x.First, x => x.Second as Expression));
|
||||
return replacer.Visit(expression);
|
||||
}
|
||||
}
|
||||
@@ -1,78 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization.Metadata;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Abstractions.Models.Attributes;
|
||||
using static System.Text.Json.JsonNamingPolicy;
|
||||
|
||||
namespace Kyoo.Utils;
|
||||
|
||||
public class JsonKindResolver : DefaultJsonTypeInfoResolver
|
||||
{
|
||||
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
|
||||
{
|
||||
JsonTypeInfo jsonTypeInfo = base.GetTypeInfo(type, options);
|
||||
|
||||
if (jsonTypeInfo.Type.GetCustomAttribute<OneOfAttribute>() != null)
|
||||
{
|
||||
jsonTypeInfo.PolymorphismOptions = new()
|
||||
{
|
||||
TypeDiscriminatorPropertyName = "kind",
|
||||
IgnoreUnrecognizedTypeDiscriminators = true,
|
||||
DerivedTypes = { },
|
||||
};
|
||||
IEnumerable<Type> derived = AppDomain
|
||||
.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(s => s.GetTypes())
|
||||
.Where(p => type.IsAssignableFrom(p) && p.IsClass);
|
||||
foreach (Type der in derived)
|
||||
{
|
||||
jsonTypeInfo.PolymorphismOptions.DerivedTypes.Add(
|
||||
new JsonDerivedType(der, CamelCase.ConvertName(der.Name))
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (
|
||||
jsonTypeInfo.Type.IsAssignableTo(typeof(IResource))
|
||||
&& jsonTypeInfo.Properties.All(x => x.Name != "kind")
|
||||
)
|
||||
{
|
||||
jsonTypeInfo.PolymorphismOptions = new JsonPolymorphismOptions
|
||||
{
|
||||
TypeDiscriminatorPropertyName = "kind",
|
||||
IgnoreUnrecognizedTypeDiscriminators = true,
|
||||
DerivedTypes =
|
||||
{
|
||||
new JsonDerivedType(
|
||||
jsonTypeInfo.Type,
|
||||
CamelCase.ConvertName(jsonTypeInfo.Type.Name)
|
||||
),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return jsonTypeInfo;
|
||||
}
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace Kyoo.Utils;
|
||||
|
||||
/// <summary>
|
||||
/// A set of utility functions that can be used everywhere.
|
||||
/// </summary>
|
||||
public static class Utility
|
||||
{
|
||||
public static readonly JsonSerializerOptions JsonOptions =
|
||||
new()
|
||||
{
|
||||
TypeInfoResolver = new JsonKindResolver(),
|
||||
Converters = { new JsonStringEnumConverter() },
|
||||
PropertyNamingPolicy = JsonNamingPolicy.CamelCase,
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Convert a string to snake case. Stollen from
|
||||
/// https://github.com/efcore/EFCore.NamingConventions/blob/main/EFCore.NamingConventions/Internal/SnakeCaseNameRewriter.cs
|
||||
/// </summary>
|
||||
/// <param name="name">The string to convert.</param>
|
||||
/// <returns>The string in snake case</returns>
|
||||
public static string ToSnakeCase(this string name)
|
||||
{
|
||||
StringBuilder builder = new(name.Length + Math.Min(2, name.Length / 5));
|
||||
UnicodeCategory? previousCategory = default;
|
||||
|
||||
for (int currentIndex = 0; currentIndex < name.Length; currentIndex++)
|
||||
{
|
||||
char currentChar = name[currentIndex];
|
||||
if (currentChar == '_')
|
||||
{
|
||||
builder.Append('_');
|
||||
previousCategory = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
UnicodeCategory currentCategory = char.GetUnicodeCategory(currentChar);
|
||||
switch (currentCategory)
|
||||
{
|
||||
case UnicodeCategory.UppercaseLetter:
|
||||
case UnicodeCategory.TitlecaseLetter:
|
||||
if (
|
||||
previousCategory == UnicodeCategory.SpaceSeparator
|
||||
|| previousCategory == UnicodeCategory.LowercaseLetter
|
||||
|| (
|
||||
previousCategory != UnicodeCategory.DecimalDigitNumber
|
||||
&& previousCategory != null
|
||||
&& currentIndex > 0
|
||||
&& currentIndex + 1 < name.Length
|
||||
&& char.IsLower(name[currentIndex + 1])
|
||||
)
|
||||
)
|
||||
{
|
||||
builder.Append('_');
|
||||
}
|
||||
|
||||
currentChar = char.ToLowerInvariant(currentChar);
|
||||
break;
|
||||
|
||||
case UnicodeCategory.LowercaseLetter:
|
||||
case UnicodeCategory.DecimalDigitNumber:
|
||||
if (previousCategory == UnicodeCategory.SpaceSeparator)
|
||||
{
|
||||
builder.Append('_');
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
if (previousCategory != null)
|
||||
{
|
||||
previousCategory = UnicodeCategory.SpaceSeparator;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
builder.Append(currentChar);
|
||||
previousCategory = currentCategory;
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Is the lambda expression a member (like x => x.Body).
|
||||
/// </summary>
|
||||
/// <param name="ex">The expression that should be checked</param>
|
||||
/// <returns>True if the expression is a member, false otherwise</returns>
|
||||
public static bool IsPropertyExpression(LambdaExpression ex)
|
||||
{
|
||||
return ex.Body is MemberExpression
|
||||
|| (
|
||||
ex.Body.NodeType == ExpressionType.Convert
|
||||
&& ((UnaryExpression)ex.Body).Operand is MemberExpression
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the name of a property. Useful for selectors as members ex: Load(x => x.Shows)
|
||||
/// </summary>
|
||||
/// <param name="ex">The expression</param>
|
||||
/// <returns>The name of the expression</returns>
|
||||
/// <exception cref="ArgumentException">If the expression is not a property, ArgumentException is thrown.</exception>
|
||||
public static string GetPropertyName(LambdaExpression ex)
|
||||
{
|
||||
if (!IsPropertyExpression(ex))
|
||||
throw new ArgumentException($"{ex} is not a property expression.");
|
||||
MemberExpression? member =
|
||||
ex.Body.NodeType == ExpressionType.Convert
|
||||
? ((UnaryExpression)ex.Body).Operand as MemberExpression
|
||||
: ex.Body as MemberExpression;
|
||||
return member!.Member.Name;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Slugify a string (Replace spaces by -, Uniformize accents)
|
||||
/// </summary>
|
||||
/// <param name="str">The string to slugify</param>
|
||||
/// <returns>The slug version of the given string</returns>
|
||||
public static string ToSlug(string str)
|
||||
{
|
||||
str = str.ToLowerInvariant();
|
||||
|
||||
string normalizedString = str.Normalize(NormalizationForm.FormD);
|
||||
StringBuilder stringBuilder = new();
|
||||
foreach (char c in normalizedString)
|
||||
{
|
||||
UnicodeCategory unicodeCategory = CharUnicodeInfo.GetUnicodeCategory(c);
|
||||
if (unicodeCategory != UnicodeCategory.NonSpacingMark)
|
||||
stringBuilder.Append(c);
|
||||
}
|
||||
str = stringBuilder.ToString().Normalize(NormalizationForm.FormC);
|
||||
|
||||
str = Regex.Replace(str, @"\s", "-", RegexOptions.Compiled);
|
||||
str = Regex.Replace(str, @"[^\w\s\p{Pd}]", string.Empty, RegexOptions.Compiled);
|
||||
str = str.Trim('-', '_');
|
||||
str = Regex.Replace(str, @"([-_]){2,}", "$1", RegexOptions.Compiled);
|
||||
return str;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return every <see cref="Type"/> in the inheritance tree of the parameter (interfaces are not returned)
|
||||
/// </summary>
|
||||
/// <param name="self">The starting type</param>
|
||||
/// <returns>A list of types</returns>
|
||||
public static IEnumerable<Type> GetInheritanceTree(this Type self)
|
||||
{
|
||||
for (Type? type = self; type != null; type = type.BaseType)
|
||||
yield return type;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the generic definition of <paramref name="genericType"/>.
|
||||
/// For example, calling this function with List<string> and typeof(IEnumerable<>) will return IEnumerable<string>
|
||||
/// </summary>
|
||||
/// <param name="type">The type to check</param>
|
||||
/// <param name="genericType">The generic type to check against (Only generic types are supported like typeof(IEnumerable<>).</param>
|
||||
/// <returns>The generic definition of genericType that type inherit or null if type does not implement the generic type.</returns>
|
||||
/// <exception cref="ArgumentException"><paramref name="genericType"/> must be a generic type</exception>
|
||||
public static Type? GetGenericDefinition(Type type, Type genericType)
|
||||
{
|
||||
if (!genericType.IsGenericType)
|
||||
throw new ArgumentException($"{nameof(genericType)} is not a generic type.");
|
||||
|
||||
IEnumerable<Type> types = genericType.IsInterface
|
||||
? type.GetInterfaces()
|
||||
: type.GetInheritanceTree();
|
||||
return types
|
||||
.Prepend(type)
|
||||
.FirstOrDefault(x => x.IsGenericType && x.GetGenericTypeDefinition() == genericType);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a dictionary to a query string.
|
||||
/// </summary>
|
||||
/// <param name="query">The list of query parameters.</param>
|
||||
/// <returns>A valid query string with all items in the dictionary.</returns>
|
||||
public static string ToQueryString(this Dictionary<string, string> query)
|
||||
{
|
||||
if (!query.Any())
|
||||
return string.Empty;
|
||||
return "?" + string.Join('&', query.Select(x => $"{x.Key}={x.Value}"));
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Data;
|
||||
using Dapper;
|
||||
|
||||
namespace Kyoo.Utils;
|
||||
|
||||
// Only used due to https://github.com/DapperLib/Dapper/issues/332
|
||||
public class Wrapper
|
||||
{
|
||||
public object Value { get; set; }
|
||||
|
||||
public Wrapper(object value)
|
||||
{
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public class Handler : SqlMapper.TypeHandler<Wrapper>
|
||||
{
|
||||
public override Wrapper? Parse(object value)
|
||||
{
|
||||
throw new NotImplementedException("Wrapper should only be used to write");
|
||||
}
|
||||
|
||||
public override void SetValue(IDbDataParameter parameter, Wrapper? value)
|
||||
{
|
||||
parameter.Value = value?.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace Kyoo.Authentication.Attributes;
|
||||
|
||||
/// <summary>
|
||||
/// Disables the action if the specified environment variable is set to true.
|
||||
/// </summary>
|
||||
public class DisableOnEnvVarAttribute(string varName) : Attribute, IResourceFilter
|
||||
{
|
||||
public void OnResourceExecuting(ResourceExecutingContext context)
|
||||
{
|
||||
var config = context.HttpContext.RequestServices.GetRequiredService<IConfiguration>();
|
||||
|
||||
if (config.GetValue(varName, false))
|
||||
context.Result = new Microsoft.AspNetCore.Mvc.NotFoundResult();
|
||||
}
|
||||
|
||||
public void OnResourceExecuted(ResourceExecutedContext context) { }
|
||||
}
|
||||
@@ -1,165 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Authentication.Models;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Serilog;
|
||||
|
||||
namespace Kyoo.Authentication;
|
||||
|
||||
public static class AuthenticationModule
|
||||
{
|
||||
public static void ConfigureAuthentication(this WebApplicationBuilder builder)
|
||||
{
|
||||
PermissionOption options =
|
||||
new()
|
||||
{
|
||||
Default = builder
|
||||
.Configuration.GetValue("UNLOGGED_PERMISSIONS", "")!
|
||||
.Split(',')
|
||||
.Where(x => x.Length > 0)
|
||||
.ToArray(),
|
||||
NewUser = builder
|
||||
.Configuration.GetValue("DEFAULT_PERMISSIONS", "overall.read,overall.play")!
|
||||
.Split(','),
|
||||
RequireVerification = builder.Configuration.GetValue(
|
||||
"REQUIRE_ACCOUNT_VERIFICATION",
|
||||
true
|
||||
),
|
||||
PublicUrl =
|
||||
builder.Configuration.GetValue<string?>("PUBLIC_URL")
|
||||
?? "http://localhost:8901",
|
||||
ApiKeys = builder.Configuration.GetValue("KYOO_APIKEYS", string.Empty)!.Split(','),
|
||||
OIDC = builder
|
||||
.Configuration.AsEnumerable()
|
||||
.Where((pair) => pair.Key.StartsWith("OIDC_"))
|
||||
.Aggregate(
|
||||
new Dictionary<string, OidcProvider>(),
|
||||
(acc, val) =>
|
||||
{
|
||||
if (val.Value is null)
|
||||
return acc;
|
||||
if (val.Key.Split("_") is not ["OIDC", string provider, string key])
|
||||
{
|
||||
Log.Error("Invalid oidc config value: {Key}", val.Key);
|
||||
return acc;
|
||||
}
|
||||
provider = provider.ToLowerInvariant();
|
||||
key = key.ToLowerInvariant();
|
||||
|
||||
if (!acc.ContainsKey(provider))
|
||||
acc.Add(provider, new(provider));
|
||||
switch (key)
|
||||
{
|
||||
case "clientid":
|
||||
acc[provider].ClientId = val.Value;
|
||||
break;
|
||||
case "secret":
|
||||
acc[provider].Secret = val.Value;
|
||||
break;
|
||||
case "scope":
|
||||
acc[provider].Scope = val.Value;
|
||||
break;
|
||||
case "authorization":
|
||||
acc[provider].AuthorizationUrl = val.Value;
|
||||
break;
|
||||
case "token":
|
||||
acc[provider].TokenUrl = val.Value;
|
||||
break;
|
||||
case "userinfo":
|
||||
case "profile":
|
||||
acc[provider].ProfileUrl = val.Value;
|
||||
break;
|
||||
case "name":
|
||||
acc[provider].DisplayName = val.Value;
|
||||
break;
|
||||
case "logo":
|
||||
acc[provider].LogoUrl = val.Value;
|
||||
break;
|
||||
case "clientauthmethod":
|
||||
case "authmethod":
|
||||
case "auth":
|
||||
case "method":
|
||||
if (!Enum.TryParse(val.Value, out AuthMethod method))
|
||||
{
|
||||
Log.Error(
|
||||
"Invalid AuthMethod value: {AuthMethod}. Ignoring.",
|
||||
val.Value
|
||||
);
|
||||
break;
|
||||
}
|
||||
acc[provider].ClientAuthMethod = method;
|
||||
break;
|
||||
default:
|
||||
Log.Error("Invalid oidc config value: {Key}", key);
|
||||
return acc;
|
||||
}
|
||||
return acc;
|
||||
}
|
||||
),
|
||||
};
|
||||
builder.Services.AddSingleton(options);
|
||||
|
||||
byte[] secret = builder.Configuration.GetValue<byte[]>("AUTHENTICATION_SECRET")!;
|
||||
builder.Services.AddSingleton(new AuthenticationOption() { Secret = secret });
|
||||
|
||||
builder
|
||||
.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
|
||||
.AddJwtBearer(options =>
|
||||
{
|
||||
options.Events = new()
|
||||
{
|
||||
OnMessageReceived = (ctx) =>
|
||||
{
|
||||
string prefix = "Bearer ";
|
||||
if (
|
||||
ctx.Request.Headers.TryGetValue("Authorization", out StringValues val)
|
||||
&& val.ToString() is string auth
|
||||
&& auth.StartsWith(prefix)
|
||||
)
|
||||
{
|
||||
ctx.Token ??= auth[prefix.Length..];
|
||||
}
|
||||
ctx.Token ??= ctx.Request.Cookies["X-Bearer"];
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
};
|
||||
options.TokenValidationParameters = new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
ValidateLifetime = true,
|
||||
ValidateIssuerSigningKey = true,
|
||||
IssuerSigningKey = new SymmetricSecurityKey(secret)
|
||||
};
|
||||
});
|
||||
|
||||
builder.Services.AddSingleton<IPermissionValidator, PermissionValidator>();
|
||||
builder.Services.AddSingleton<ITokenController, TokenController>();
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace Kyoo.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// The service that controls jwt creation and validation.
|
||||
/// </summary>
|
||||
public interface ITokenController
|
||||
{
|
||||
/// <summary>
|
||||
/// Create a new access token for the given user.
|
||||
/// </summary>
|
||||
/// <param name="user">The user to create a token for.</param>
|
||||
/// <param name="expireIn">When this token will expire.</param>
|
||||
/// <returns>A new, valid access token.</returns>
|
||||
string CreateAccessToken(User user, out TimeSpan expireIn);
|
||||
|
||||
/// <summary>
|
||||
/// Create a new refresh token for the given user.
|
||||
/// </summary>
|
||||
/// <param name="user">The user to create a token for.</param>
|
||||
/// <returns>A new, valid refresh token.</returns>
|
||||
Task<string> CreateRefreshToken(User user);
|
||||
|
||||
/// <summary>
|
||||
/// Check if the given refresh token is valid and if it is, retrieve the id of the user this token belongs to.
|
||||
/// </summary>
|
||||
/// <param name="refreshToken">The refresh token to validate.</param>
|
||||
/// <exception cref="SecurityTokenException">The given refresh token is not valid.</exception>
|
||||
/// <returns>The id of the token's user.</returns>
|
||||
Guid GetRefreshTokenUserID(string refreshToken);
|
||||
}
|
||||
@@ -1,143 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using System.Net.Http;
|
||||
using System.Net.Http.Json;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Authentication.Models;
|
||||
using Kyoo.Authentication.Models.DTO;
|
||||
|
||||
namespace Kyoo.Authentication;
|
||||
|
||||
public class OidcController(
|
||||
IUserRepository users,
|
||||
IHttpClientFactory clientFactory,
|
||||
PermissionOption options
|
||||
)
|
||||
{
|
||||
private async Task<(User, ExternalToken)> _TranslateCode(string provider, string code)
|
||||
{
|
||||
OidcProvider prov = options.OIDC[provider];
|
||||
|
||||
HttpClient client = clientFactory.CreateClient();
|
||||
|
||||
Dictionary<string, string> data =
|
||||
new()
|
||||
{
|
||||
["code"] = code,
|
||||
["redirect_uri"] = $"{options.PublicUrl.TrimEnd('/')}/api/auth/logged/{provider}",
|
||||
["grant_type"] = "authorization_code",
|
||||
};
|
||||
|
||||
if (prov.ClientAuthMethod == AuthMethod.ClientSecretBasic)
|
||||
{
|
||||
string auth = Convert.ToBase64String(
|
||||
Encoding.UTF8.GetBytes($"{prov.ClientId}:{prov.Secret}")
|
||||
);
|
||||
client.DefaultRequestHeaders.Add("Authorization", $"Basic {auth}");
|
||||
}
|
||||
else if (prov.ClientAuthMethod == AuthMethod.ClientSecretPost)
|
||||
{
|
||||
data["client_id"] = prov.ClientId;
|
||||
data["client_secret"] = prov.Secret;
|
||||
}
|
||||
|
||||
HttpResponseMessage resp = prov.TokenUseJsonBody
|
||||
? await client.PostAsJsonAsync(prov.TokenUrl, data)
|
||||
: await client.PostAsync(prov.TokenUrl, new FormUrlEncodedContent(data));
|
||||
if (!resp.IsSuccessStatusCode)
|
||||
throw new ValidationException(
|
||||
$"Invalid code or configuration. {resp.StatusCode}: {await resp.Content.ReadAsStringAsync()}"
|
||||
);
|
||||
JwtToken? token = await resp.Content.ReadFromJsonAsync<JwtToken>();
|
||||
if (token is null)
|
||||
throw new ValidationException("Could not retrive token.");
|
||||
|
||||
client.DefaultRequestHeaders.Remove("Authorization");
|
||||
client.DefaultRequestHeaders.Add("Authorization", $"{token.TokenType} {token.AccessToken}");
|
||||
Dictionary<string, string>? extraHeaders = prov.GetExtraHeaders?.Invoke(prov);
|
||||
if (extraHeaders is not null)
|
||||
{
|
||||
foreach ((string key, string value) in extraHeaders)
|
||||
client.DefaultRequestHeaders.Add(key, value);
|
||||
}
|
||||
|
||||
JwtProfile? profile = await client.GetFromJsonAsync<JwtProfile>(prov.ProfileUrl);
|
||||
if (profile is null || profile.Sub is null)
|
||||
throw new ValidationException(
|
||||
$"Missing sub on user object. Got: {JsonSerializer.Serialize(profile)}"
|
||||
);
|
||||
ExternalToken extToken =
|
||||
new()
|
||||
{
|
||||
Id = profile.Sub,
|
||||
Token = token,
|
||||
ProfileUrl = prov.GetProfileUrl?.Invoke(profile),
|
||||
};
|
||||
User newUser = new();
|
||||
if (profile.Email is not null)
|
||||
newUser.Email = profile.Email;
|
||||
if (profile.Username is null)
|
||||
{
|
||||
throw new ValidationException(
|
||||
$"Could not find a username for the user. You may need to add more scopes. Fields: {string.Join(',', profile.Extra)}"
|
||||
);
|
||||
}
|
||||
extToken.Username = profile.Username;
|
||||
newUser.Username = profile.Username;
|
||||
newUser.Slug = Utils.Utility.ToSlug(newUser.Username);
|
||||
newUser.ExternalId.Add(provider, extToken);
|
||||
return (newUser, extToken);
|
||||
}
|
||||
|
||||
public async Task<User> LoginViaCode(string provider, string code)
|
||||
{
|
||||
(User newUser, ExternalToken extToken) = await _TranslateCode(provider, code);
|
||||
User? user = await users.GetByExternalId(provider, extToken.Id);
|
||||
if (user == null)
|
||||
{
|
||||
try
|
||||
{
|
||||
user = await users.Create(newUser);
|
||||
}
|
||||
catch
|
||||
{
|
||||
throw new ValidationException(
|
||||
"A user already exists with the same username. If this is you, login via username and then link your account."
|
||||
);
|
||||
}
|
||||
}
|
||||
return user;
|
||||
}
|
||||
|
||||
public async Task<User> LinkAccountOrLogin(Guid userId, string provider, string code)
|
||||
{
|
||||
(_, ExternalToken extToken) = await _TranslateCode(provider, code);
|
||||
User? user = await users.GetByExternalId(provider, extToken.Id);
|
||||
if (user != null)
|
||||
return user;
|
||||
return await users.AddExternalToken(userId, provider, extToken);
|
||||
}
|
||||
}
|
||||
@@ -1,284 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Controllers;
|
||||
using Kyoo.Abstractions.Models.Permissions;
|
||||
using Kyoo.Abstractions.Models.Utils;
|
||||
using Kyoo.Authentication.Models;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.JwtBearer;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.AspNetCore.Mvc.Filters;
|
||||
using Microsoft.Extensions.Primitives;
|
||||
|
||||
namespace Kyoo.Authentication;
|
||||
|
||||
/// <summary>
|
||||
/// A permission validator to validate permission with user Permission array
|
||||
/// or the default array from the configurations if the user is not logged.
|
||||
/// </summary>
|
||||
public class PermissionValidator : IPermissionValidator
|
||||
{
|
||||
/// <summary>
|
||||
/// The permissions options to retrieve default permissions.
|
||||
/// </summary>
|
||||
private readonly PermissionOption _options;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new factory with the given options.
|
||||
/// </summary>
|
||||
/// <param name="options">The option containing default values.</param>
|
||||
public PermissionValidator(PermissionOption options)
|
||||
{
|
||||
_options = options;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata Create(PermissionAttribute attribute)
|
||||
{
|
||||
return new PermissionValidatorFilter(
|
||||
attribute.Type,
|
||||
attribute.Kind,
|
||||
attribute.Group,
|
||||
_options
|
||||
);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IFilterMetadata Create(PartialPermissionAttribute attribute)
|
||||
{
|
||||
return new PermissionValidatorFilter(
|
||||
((object?)attribute.Type ?? attribute.Kind)!,
|
||||
attribute.Group,
|
||||
_options
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The authorization filter used by <see cref="PermissionValidator"/>.
|
||||
/// </summary>
|
||||
private class PermissionValidatorFilter : IAsyncAuthorizationFilter
|
||||
{
|
||||
/// <summary>
|
||||
/// The permission to validate.
|
||||
/// </summary>
|
||||
private readonly string? _permission;
|
||||
|
||||
/// <summary>
|
||||
/// The kind of permission needed.
|
||||
/// </summary>
|
||||
private readonly Kind? _kind;
|
||||
|
||||
/// <summary>
|
||||
/// The group of he permission.
|
||||
/// </summary>
|
||||
private Group _group;
|
||||
|
||||
/// <summary>
|
||||
/// The permissions options to retrieve default permissions.
|
||||
/// </summary>
|
||||
private readonly PermissionOption _options;
|
||||
|
||||
/// <summary>
|
||||
/// Create a new permission validator with the given options.
|
||||
/// </summary>
|
||||
/// <param name="permission">The permission to validate.</param>
|
||||
/// <param name="kind">The kind of permission needed.</param>
|
||||
/// <param name="group">The group of the permission.</param>
|
||||
/// <param name="options">The option containing default values.</param>
|
||||
public PermissionValidatorFilter(
|
||||
string permission,
|
||||
Kind kind,
|
||||
Group group,
|
||||
PermissionOption options
|
||||
)
|
||||
{
|
||||
_permission = permission;
|
||||
_kind = kind;
|
||||
_group = group;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new permission validator with the given options.
|
||||
/// </summary>
|
||||
/// <param name="partialInfo">The partial permission to validate.</param>
|
||||
/// <param name="group">The group of the permission.</param>
|
||||
/// <param name="options">The option containing default values.</param>
|
||||
public PermissionValidatorFilter(object partialInfo, Group? group, PermissionOption options)
|
||||
{
|
||||
switch (partialInfo)
|
||||
{
|
||||
case Kind kind:
|
||||
_kind = kind;
|
||||
break;
|
||||
case string perm:
|
||||
_permission = perm;
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentException(
|
||||
$"{nameof(partialInfo)} can only be a permission string or a kind."
|
||||
);
|
||||
}
|
||||
|
||||
if (group is not null and not Group.None)
|
||||
_group = group.Value;
|
||||
_options = options;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
|
||||
{
|
||||
string? permission = _permission;
|
||||
Kind? kind = _kind;
|
||||
|
||||
if (permission == null || kind == null)
|
||||
{
|
||||
if (context.HttpContext.Items["PermissionGroup"] is Group group and not Group.None)
|
||||
_group = group;
|
||||
else if (_group == Group.None)
|
||||
_group = Group.Overall;
|
||||
else
|
||||
context.HttpContext.Items["PermissionGroup"] = _group;
|
||||
|
||||
switch (context.HttpContext.Items["PermissionType"])
|
||||
{
|
||||
case string perm:
|
||||
permission = perm;
|
||||
break;
|
||||
case Kind kin:
|
||||
kind = kin;
|
||||
break;
|
||||
case null when kind != null:
|
||||
context.HttpContext.Items["PermissionType"] = kind;
|
||||
return;
|
||||
case null when permission != null:
|
||||
context.HttpContext.Items["PermissionType"] = permission;
|
||||
return;
|
||||
default:
|
||||
throw new ArgumentException(
|
||||
"Multiple non-matching partial permission attribute "
|
||||
+ "are not supported."
|
||||
);
|
||||
}
|
||||
if (permission == null || kind == null)
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"The permission type or kind is still missing after two partial "
|
||||
+ "permission attributes, this is unsupported."
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
string permStr = $"{permission.ToLower()}.{kind.ToString()!.ToLower()}";
|
||||
string overallStr = $"{_group.ToString().ToLower()}.{kind.ToString()!.ToLower()}";
|
||||
AuthenticateResult res = _ApiKeyCheck(context);
|
||||
if (res.None)
|
||||
res = await _JwtCheck(context);
|
||||
|
||||
if (res.Succeeded)
|
||||
{
|
||||
ICollection<string> permissions = res.Principal.GetPermissions();
|
||||
if (permissions.All(x => x != permStr && x != overallStr))
|
||||
context.Result = _ErrorResult(
|
||||
$"Missing permission {permStr} or {overallStr}",
|
||||
StatusCodes.Status403Forbidden
|
||||
);
|
||||
}
|
||||
else if (res.None)
|
||||
{
|
||||
ICollection<string> permissions = _options.Default ?? Array.Empty<string>();
|
||||
if (permissions.All(x => x != permStr && x != overallStr))
|
||||
{
|
||||
context.Result = _ErrorResult(
|
||||
$"Unlogged user does not have permission {permStr} or {overallStr}",
|
||||
StatusCodes.Status401Unauthorized
|
||||
);
|
||||
}
|
||||
}
|
||||
else if (res.Failure != null)
|
||||
context.Result = _ErrorResult(res.Failure.Message, StatusCodes.Status403Forbidden);
|
||||
else
|
||||
context.Result = _ErrorResult(
|
||||
"Authentication panic",
|
||||
StatusCodes.Status500InternalServerError
|
||||
);
|
||||
}
|
||||
|
||||
private AuthenticateResult _ApiKeyCheck(ActionContext context)
|
||||
{
|
||||
if (
|
||||
!context.HttpContext.Request.Headers.TryGetValue(
|
||||
"X-API-Key",
|
||||
out StringValues apiKey
|
||||
)
|
||||
)
|
||||
return AuthenticateResult.NoResult();
|
||||
if (!_options.ApiKeys.Contains<string>(apiKey!))
|
||||
return AuthenticateResult.Fail("Invalid API-Key.");
|
||||
return AuthenticateResult.Success(
|
||||
new AuthenticationTicket(
|
||||
new ClaimsPrincipal(
|
||||
new[]
|
||||
{
|
||||
new ClaimsIdentity(
|
||||
new[]
|
||||
{
|
||||
// TODO: Make permission configurable, for now every APIKEY as all permissions.
|
||||
new Claim(
|
||||
Claims.Permissions,
|
||||
string.Join(',', PermissionOption.Admin)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
),
|
||||
"apikey"
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private async Task<AuthenticateResult> _JwtCheck(ActionContext context)
|
||||
{
|
||||
AuthenticateResult ret = await context.HttpContext.AuthenticateAsync(
|
||||
JwtBearerDefaults.AuthenticationScheme
|
||||
);
|
||||
// Change the failure message to make the API nice to use.
|
||||
if (ret.Failure != null)
|
||||
return AuthenticateResult.Fail("Invalid JWT token. The token may have expired.");
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create a new action result with the given error message and error code.
|
||||
/// </summary>
|
||||
/// <param name="error">The error message.</param>
|
||||
/// <param name="code">The status code of the error.</param>
|
||||
/// <returns>The resulting error action.</returns>
|
||||
private static IActionResult _ErrorResult(string error, int code)
|
||||
{
|
||||
return new ObjectResult(new RequestError(error)) { StatusCode = code };
|
||||
}
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.Linq;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Authentication.Models;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
|
||||
namespace Kyoo.Authentication;
|
||||
|
||||
public class TokenController(AuthenticationOption options) : ITokenController
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public string CreateAccessToken(User user, out TimeSpan expireIn)
|
||||
{
|
||||
expireIn = new TimeSpan(1, 0, 0);
|
||||
|
||||
SymmetricSecurityKey key = new(options.Secret);
|
||||
SigningCredentials credential = new(key, SecurityAlgorithms.HmacSha256Signature);
|
||||
string permissions =
|
||||
user.Permissions != null ? string.Join(',', user.Permissions) : string.Empty;
|
||||
List<Claim> claims =
|
||||
new()
|
||||
{
|
||||
new Claim(Claims.Id, user.Id.ToString()),
|
||||
new Claim(Claims.Name, user.Username),
|
||||
new Claim(Claims.Permissions, permissions),
|
||||
new Claim(Claims.Type, "access")
|
||||
};
|
||||
if (user.Email != null)
|
||||
claims.Add(new Claim(Claims.Email, user.Email));
|
||||
JwtSecurityToken token =
|
||||
new(
|
||||
signingCredentials: credential,
|
||||
claims: claims,
|
||||
expires: DateTime.UtcNow.Add(expireIn)
|
||||
);
|
||||
return new JwtSecurityTokenHandler().WriteToken(token);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Task<string> CreateRefreshToken(User user)
|
||||
{
|
||||
SymmetricSecurityKey key = new(options.Secret);
|
||||
SigningCredentials credential = new(key, SecurityAlgorithms.HmacSha256Signature);
|
||||
JwtSecurityToken token =
|
||||
new(
|
||||
signingCredentials: credential,
|
||||
claims: new[]
|
||||
{
|
||||
new Claim(Claims.Id, user.Id.ToString()),
|
||||
new Claim(Claims.Guid, Guid.NewGuid().ToString()),
|
||||
new Claim(Claims.Type, "refresh")
|
||||
},
|
||||
expires: DateTime.UtcNow.AddYears(1)
|
||||
);
|
||||
// TODO: refresh keys are unique (thanks to the guid) but we could store them in DB to invalidate them if requested by the user.
|
||||
return Task.FromResult(new JwtSecurityTokenHandler().WriteToken(token));
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public Guid GetRefreshTokenUserID(string refreshToken)
|
||||
{
|
||||
SymmetricSecurityKey key = new(options.Secret);
|
||||
JwtSecurityTokenHandler tokenHandler = new();
|
||||
ClaimsPrincipal principal;
|
||||
try
|
||||
{
|
||||
principal = tokenHandler.ValidateToken(
|
||||
refreshToken,
|
||||
new TokenValidationParameters
|
||||
{
|
||||
ValidateIssuer = false,
|
||||
ValidateAudience = false,
|
||||
ValidateIssuerSigningKey = true,
|
||||
ValidateLifetime = true,
|
||||
IssuerSigningKey = key
|
||||
},
|
||||
out SecurityToken _
|
||||
);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
throw new SecurityTokenException("Invalid refresh token");
|
||||
}
|
||||
|
||||
if (principal.Claims.First(x => x.Type == Claims.Type).Value != "refresh")
|
||||
throw new SecurityTokenException(
|
||||
"Invalid token type. The token should be a refresh token."
|
||||
);
|
||||
Claim identifier = principal.Claims.First(x => x.Type == Claims.Id);
|
||||
if (Guid.TryParse(identifier.Value, out Guid id))
|
||||
return id;
|
||||
throw new SecurityTokenException("Token not associated to any user.");
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="8.0.21" />
|
||||
<PackageReference Include="BCrypt.Net-Next" Version="4.0.3" />
|
||||
<PackageReference Include="Serilog" Version="4.3.0" />
|
||||
|
||||
<ProjectReference Include="../Kyoo.Abstractions/Kyoo.Abstractions.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@@ -1,77 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Text.Json.Nodes;
|
||||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Kyoo.Authentication.Models.DTO;
|
||||
|
||||
public class JwtProfile
|
||||
{
|
||||
public string? Sub { get; set; }
|
||||
public string? Uid
|
||||
{
|
||||
set => Sub ??= value;
|
||||
}
|
||||
public string? Id
|
||||
{
|
||||
set => Sub ??= value;
|
||||
}
|
||||
public string? Guid
|
||||
{
|
||||
set => Sub ??= value;
|
||||
}
|
||||
|
||||
public string? Username { get; set; }
|
||||
public string? Name
|
||||
{
|
||||
set => Username ??= value;
|
||||
}
|
||||
|
||||
public string? Email { get; set; }
|
||||
|
||||
public JsonObject? Account
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
return;
|
||||
// simkl store their ids there.
|
||||
Sub ??= value["id"]?.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public JsonObject? User
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value is null)
|
||||
return;
|
||||
// trakt store their name there (they also store name but that's not the same).
|
||||
Username ??= value["username"]?.ToString();
|
||||
// simkl store their name there.
|
||||
Username ??= value["name"]?.ToString();
|
||||
|
||||
Sub ??= value["ids"]?["uuid"]?.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
[JsonExtensionData]
|
||||
public Dictionary<string, object> Extra { get; set; }
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
namespace Kyoo.Authentication.Models.DTO;
|
||||
|
||||
/// <summary>
|
||||
/// A model only used on login requests.
|
||||
/// </summary>
|
||||
public class LoginRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The user's username.
|
||||
/// </summary>
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's password.
|
||||
/// </summary>
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="LoginRequest"/> class.
|
||||
/// </summary>
|
||||
/// <param name="username">The user's username.</param>
|
||||
/// <param name="password">The user's password.</param>
|
||||
public LoginRequest(string username, string password)
|
||||
{
|
||||
Username = username;
|
||||
Password = password;
|
||||
}
|
||||
}
|
||||
@@ -1,38 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace Kyoo.Authentication.Models.DTO;
|
||||
|
||||
/// <summary>
|
||||
/// A model only used on password resets.
|
||||
/// </summary>
|
||||
public class PasswordResetRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The old password
|
||||
/// </summary>
|
||||
public string? OldPassword { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The new password
|
||||
/// </summary>
|
||||
[MinLength(4, ErrorMessage = "The password must have at least {1} characters")]
|
||||
public string NewPassword { get; set; }
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
// Kyoo - A portable and vast media library solution.
|
||||
// Copyright (c) Kyoo.
|
||||
//
|
||||
// See AUTHORS.md and LICENSE file in the project root for full license information.
|
||||
//
|
||||
// Kyoo is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// any later version.
|
||||
//
|
||||
// Kyoo is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with Kyoo. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Kyoo.Abstractions.Models;
|
||||
using Kyoo.Utils;
|
||||
using BCryptNet = BCrypt.Net.BCrypt;
|
||||
|
||||
namespace Kyoo.Authentication.Models.DTO;
|
||||
|
||||
/// <summary>
|
||||
/// A model only used on register requests.
|
||||
/// </summary>
|
||||
public class RegisterRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The user email address
|
||||
/// </summary>
|
||||
[EmailAddress(ErrorMessage = "The email must be a valid email address")]
|
||||
public string Email { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's username.
|
||||
/// </summary>
|
||||
[MinLength(4, ErrorMessage = "The username must have at least {1} characters")]
|
||||
public string Username { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The user's password.
|
||||
/// </summary>
|
||||
[MinLength(4, ErrorMessage = "The password must have at least {1} characters")]
|
||||
public string Password { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="RegisterRequest"/> class.
|
||||
/// </summary>
|
||||
/// <param name="email">The user email address.</param>
|
||||
/// <param name="username">The user's username.</param>
|
||||
/// <param name="password">The user's password.</param>
|
||||
public RegisterRequest(string email, string username, string password)
|
||||
{
|
||||
Email = email;
|
||||
Username = username;
|
||||
Password = password;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert this register request to a new <see cref="User"/> class.
|
||||
/// </summary>
|
||||
/// <returns>A user representing this request.</returns>
|
||||
public User ToUser()
|
||||
{
|
||||
return new User
|
||||
{
|
||||
Slug = Utility.ToSlug(Username),
|
||||
Username = Username,
|
||||
Password = BCryptNet.HashPassword(Password),
|
||||
Email = Email,
|
||||
};
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user