├── .env.example ├── .eslintrc.js ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .npmrc ├── Dockerfile ├── LICENSE ├── README.md ├── apps ├── backend │ ├── Dockerfile │ ├── cache │ │ └── cache.go │ ├── common │ │ └── common.go │ ├── downloader │ │ ├── alldebrid │ │ │ └── alldebrid.go │ │ └── realdebrid │ │ │ └── realdebrid.go │ ├── go.mod │ ├── go.sum │ ├── helpers │ │ └── helpers.go │ ├── imdb │ │ └── imdb.go │ ├── indexer │ │ ├── indexer.go │ │ ├── jackett │ │ │ └── jackett.go │ │ └── prowlarr │ │ │ └── prowlarr.go │ ├── main.go │ ├── migrations │ │ └── 1735493885_collections_snapshot.go │ ├── package.json │ ├── pb_public │ ├── scraper │ │ └── scraper.go │ ├── settings │ │ └── settings.go │ ├── tmdb │ │ └── tmdb.go │ ├── trakt │ │ └── trakt.go │ └── types │ │ └── types.go ├── frontend │ ├── .gitignore │ ├── .npmrc │ ├── .prettierrc │ ├── Dockerfile │ ├── README.md │ ├── app.vue │ ├── components │ │ ├── AllDebrid.vue │ │ ├── Detail │ │ │ ├── Info.vue │ │ │ └── SeasonsAndEpisodes.vue │ │ ├── Header │ │ │ └── NavBar.vue │ │ ├── MediaList.vue │ │ ├── Profile │ │ │ └── Trakt.vue │ │ ├── RealDebrid.vue │ │ ├── Streams.vue │ │ ├── User │ │ │ └── List.vue │ │ └── Video.vue │ ├── composables │ │ ├── useMedia.ts │ │ ├── usePb.ts │ │ ├── useProfile.ts │ │ ├── useSettings.ts │ │ └── useStreams.ts │ ├── layouts │ │ ├── admin.vue │ │ ├── default.vue │ │ ├── detail.vue │ │ └── empty.vue │ ├── middleware │ │ └── auth.global.ts │ ├── nuxt.config.ts │ ├── package.json │ ├── pages │ │ ├── [type] │ │ │ └── [id].vue │ │ ├── admin │ │ │ └── index.vue │ │ ├── devices.vue │ │ ├── index.vue │ │ ├── login.vue │ │ ├── movies.vue │ │ ├── profile.vue │ │ ├── search.vue │ │ ├── settings.vue │ │ └── shows.vue │ ├── plugins │ │ ├── fontawesome.ts │ │ └── video.ts │ ├── pnpm-lock.yaml │ ├── public │ │ ├── favicon.ico │ │ └── logo.svg │ ├── server │ │ └── tsconfig.json │ ├── tailwind.config.js │ ├── tsconfig.json │ └── utils │ │ └── index.ts └── services │ ├── Caddyfile │ ├── docker-compose.yaml │ ├── mosquitto.conf │ ├── package.json │ └── start.sh ├── bun.lockb ├── entrypoint.sh ├── go.work ├── go.work.sum ├── odin-turbo.code-workspace ├── package.json ├── packages ├── eslint-config │ ├── README.md │ ├── library.js │ ├── next.js │ ├── package.json │ └── react-internal.js ├── typescript-config │ ├── base.json │ ├── nextjs.json │ ├── package.json │ └── react-library.json └── ui │ ├── .eslintrc.js │ ├── package.json │ ├── src │ ├── button.tsx │ ├── card.tsx │ └── code.tsx │ ├── tsconfig.json │ ├── tsconfig.lint.json │ └── turbo │ └── generators │ ├── config.ts │ └── templates │ └── component.hbs ├── screenshots ├── btc_donation.png ├── connect.png ├── odin-screenshot.png └── odin-screenshot2.png ├── tsconfig.json ├── turbo.json └── version.txt /.env.example: -------------------------------------------------------------------------------- 1 | LOG_LEVEL=info 2 | ALLDEBRID_KEY=key 3 | TMDB_KEY=key 4 | TRAKT_CLIENTID=key 5 | TRAKT_SECRET=key 6 | JACKETT_URL=url 7 | JACKETT_KEY=key 8 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | // This configuration only applies to the package manager root. 2 | /** @type {import("eslint").Linter.Config} */ 3 | module.exports = { 4 | ignorePatterns: ["apps/**", "packages/**"], 5 | extends: ["@repo/eslint-config/library.js"], 6 | parser: "@typescript-eslint/parser", 7 | parserOptions: { 8 | project: true, 9 | }, 10 | }; 11 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI - Build and push 2 | 3 | on: 4 | push: 5 | tags: 6 | - "*" 7 | 8 | env: 9 | GHCR_REPO: ghcr.io/ad-on-is/odin 10 | 11 | concurrency: 12 | group: ${{ github.workflow }} 13 | cancel-in-progress: true 14 | 15 | jobs: 16 | build-and-push: 17 | name: Build and push 18 | runs-on: ubuntu-latest 19 | strategy: 20 | fail-fast: false 21 | matrix: 22 | platform: 23 | - linux/amd64 24 | - linux/arm64 25 | steps: 26 | - name: Prepare 27 | run: | 28 | platform=${{ matrix.platform }} 29 | echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV 30 | 31 | - name: Docker meta 32 | id: meta 33 | uses: docker/metadata-action@v5 34 | with: 35 | images: ${{ env.GHCR_REPO }} 36 | - name: Checkout 37 | uses: actions/checkout@v4 38 | - name: Log in to the Container registry 39 | uses: docker/login-action@v3 40 | with: 41 | registry: ghcr.io 42 | username: ${{ github.actor }} 43 | password: ${{ secrets.GITHUB_TOKEN }} 44 | - name: Set up Docker 45 | uses: docker/setup-docker-action@v4 46 | with: 47 | daemon-config: | 48 | { 49 | "debug": true, 50 | "features": { 51 | "containerd-snapshotter": true 52 | } 53 | } 54 | - name: Set up QEMU 55 | uses: docker/setup-qemu-action@v3 56 | - name: Set image tags 57 | id: tags 58 | run: | 59 | if [ "${{ matrix.platform }}" = "linux/amd64" ]; then 60 | echo "" >> $GITHUB_OUTPUT 61 | else 62 | echo "IMAGE_TAG=-arm64" >> $GITHUB_OUTPUT 63 | fi 64 | - name: Build 65 | uses: docker/build-push-action@v6 66 | with: 67 | context: . 68 | file: Dockerfile 69 | push: true 70 | platforms: ${{ matrix.platform }} 71 | tags: | 72 | ghcr.io/${{ github.actor }}/odin:${{ github.ref_name }}${{steps.tags.outputs.IMAGE_TAG}} 73 | ghcr.io/${{ github.actor }}/odin:latest${{steps.tags.outputs.IMAGE_TAG}} 74 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | deploy.sh 3 | # Dependencies 4 | node_modules 5 | .pnp 6 | .pnp.js 7 | 8 | # Local env files 9 | .env 10 | .env.local 11 | .env.development.local 12 | .env.test.local 13 | .env.production.local 14 | 15 | # Testing 16 | coverage 17 | 18 | # Turbo 19 | .turbo 20 | 21 | # Vercel 22 | .vercel 23 | 24 | # Build Outputs 25 | .next/ 26 | out/ 27 | build 28 | dist 29 | 30 | 31 | # Debug 32 | npm-debug.log* 33 | yarn-debug.log* 34 | yarn-error.log* 35 | 36 | # Misc 37 | .DS_Store 38 | *.pem 39 | 40 | 41 | apps/backend/pb_data 42 | apps/backend/version.txt 43 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ad-on-is/odin-server/f188b743bac4664515f1c48dd8f232bf9c153037/.npmrc -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM golang:alpine AS bebuilder 2 | WORKDIR /build/ 3 | COPY ./apps/backend/go.mod . 4 | COPY ./apps/backend/go.sum . 5 | RUN CGO_ENABLED=0 GOOS=linux go mod download 6 | COPY ./apps/backend . 7 | RUN CGO_ENABLED=0 GOOS=linux go build -o odin-backend 8 | 9 | FROM node:alpine AS fe-builder 10 | WORKDIR /build/ 11 | RUN npm i -g pnpm 12 | COPY ./apps/frontend/package.json . 13 | RUN pnpm i 14 | COPY ./apps/frontend . 15 | RUN pnpm run build 16 | 17 | 18 | FROM node:alpine 19 | RUN apk --update add ca-certificates curl mailcap caddy mosquitto bash 20 | 21 | COPY --from=fe-builder /build/.output /odin-frontend 22 | COPY --from=bebuilder /build/odin-backend /odin-server 23 | COPY ./apps/services/Caddyfile /etc/caddy/Caddyfile 24 | COPY ./apps/services/mosquitto.conf /etc/mosquitto/mosquitto.conf 25 | 26 | COPY ./apps/backend/migrations/1735493885_collections_snapshot.go /migrations/1735493885_collections_snapshot.go 27 | 28 | COPY ./entrypoint.sh /entrypoint.sh 29 | COPY ./version.txt /version.txt 30 | 31 | CMD ["/entrypoint.sh"] 32 | 33 | 34 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
{{ profile.data.user.username }}
7 |{{ profile.data.user.email }}
8 |{{ profile.data.user.premiumUntil }}
9 |Not connected!
12 |{{ item.tmdb.production_companies.at(0).name }}
6 |{{ item.overview }}
15 |
24 | {{ actor.name }}
{{ actor.character }}
25 |
S{{ sNumber }}xE{{ e.number }} - {{ e.title }}
24 |{{ e.first_aired }}
25 |
19 | {{ item['title'] }}
20 |
{{ traktProfile.user.username }}
{{ traktProfile.user.name }}
Click below to login into Trakt
27 |{{ profile.username }}
7 |{{ profile.email }}
8 |{{ profile.expiration }}
9 |ID | 9 |Username | 10 |12 | | |
{{ user.id }} | 16 |{{ user.username }} | 17 |{{ user.email }} | 18 |19 | 22 | | 23 |
{{ device.name }} | 9 |{{ device.created }} | 10 |
Version: {{ serverVersion }}
8 |Please see Trakt API for reference.
35 |37 | ::(year|month|day):: current year|month|day 38 | ::(year|month|day):-1: current year|month|day +1 (or -1) 39 | ::monthdays:: days of the current month41 | Example: /movies/popular?years=::year::,::year:-1: -> /movies/popular?years=2024,2023 42 |
{children}
23 | 24 | ); 25 | } 26 | -------------------------------------------------------------------------------- /packages/ui/src/code.tsx: -------------------------------------------------------------------------------- 1 | export function Code({ 2 | children, 3 | className, 4 | }: { 5 | children: React.ReactNode; 6 | className?: string; 7 | }): JSX.Element { 8 | return{children}
;
9 | }
10 |
--------------------------------------------------------------------------------
/packages/ui/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@repo/typescript-config/react-library.json",
3 | "compilerOptions": {
4 | "outDir": "dist"
5 | },
6 | "include": ["src"],
7 | "exclude": ["node_modules", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/ui/tsconfig.lint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "@repo/typescript-config/react-library.json",
3 | "compilerOptions": {
4 | "outDir": "dist"
5 | },
6 | "include": ["src", "turbo"],
7 | "exclude": ["node_modules", "dist"]
8 | }
9 |
--------------------------------------------------------------------------------
/packages/ui/turbo/generators/config.ts:
--------------------------------------------------------------------------------
1 | import type { PlopTypes } from "@turbo/gen";
2 |
3 | // Learn more about Turborepo Generators at https://turbo.build/repo/docs/core-concepts/monorepos/code-generation
4 |
5 | export default function generator(plop: PlopTypes.NodePlopAPI): void {
6 | // A simple generator to add a new React component to the internal UI library
7 | plop.setGenerator("react-component", {
8 | description: "Adds a new react component",
9 | prompts: [
10 | {
11 | type: "input",
12 | name: "name",
13 | message: "What is the name of the component?",
14 | },
15 | ],
16 | actions: [
17 | {
18 | type: "add",
19 | path: "src/{{kebabCase name}}.tsx",
20 | templateFile: "templates/component.hbs",
21 | },
22 | {
23 | type: "append",
24 | path: "package.json",
25 | pattern: /"exports": {(?