wi1-bot 2.0.2__tar.gz → 2.0.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. wi1_bot-2.0.4/.dockerignore +25 -0
  2. wi1_bot-2.0.4/.github/workflows/docker.yaml +124 -0
  3. wi1_bot-2.0.4/Dockerfile +36 -0
  4. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/PKG-INFO +1 -1
  5. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/compose.yaml +7 -6
  6. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/discord/bot.py +10 -12
  7. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/discord/cogs/movie.py +2 -3
  8. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/discord/cogs/series.py +4 -3
  9. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/transcoder/transcode_queue.py +2 -1
  10. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/webhook.py +5 -0
  11. wi1_bot-2.0.2/.dockerignore +0 -9
  12. wi1_bot-2.0.2/.github/workflows/docker.yaml +0 -59
  13. wi1_bot-2.0.2/Dockerfile +0 -32
  14. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/.envrc +0 -0
  15. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/.github/workflows/pypi-publish.yml +0 -0
  16. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/.gitignore +0 -0
  17. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/.pre-commit-config.yaml +0 -0
  18. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/LICENSE +0 -0
  19. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/README.md +0 -0
  20. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/config.yaml.template +0 -0
  21. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/flake.nix +0 -0
  22. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/pyproject.toml +0 -0
  23. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/tests/movie_downloaded.py +0 -0
  24. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/uv.lock +0 -0
  25. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/__init__.py +0 -0
  26. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/arr/__init__.py +0 -0
  27. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/arr/download.py +0 -0
  28. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/arr/episode.py +0 -0
  29. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/arr/movie.py +0 -0
  30. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/arr/radarr.py +0 -0
  31. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/arr/sonarr.py +0 -0
  32. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/arr/util.py +0 -0
  33. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/config.py +0 -0
  34. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/discord/__init__.py +0 -0
  35. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/discord/cogs/__init__.py +0 -0
  36. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/discord/helpers.py +0 -0
  37. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/push.py +0 -0
  38. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/scripts/__init__.py +0 -0
  39. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/scripts/add_tag.py +0 -0
  40. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/scripts/rescan.py +0 -0
  41. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/scripts/start.py +0 -0
  42. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/scripts/transcode_item.py +0 -0
  43. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/transcoder/__init__.py +0 -0
  44. {wi1_bot-2.0.2 → wi1_bot-2.0.4}/wi1_bot/transcoder/transcoder.py +0 -0
@@ -0,0 +1,25 @@
1
+ .DS_Store
2
+ .direnv/
3
+ .dockerignore
4
+ .envrc
5
+ .git/
6
+ .github/
7
+ .gitignore
8
+ .mypy_cache/
9
+ .pre-commit-config.yaml
10
+ .ruff_cache/
11
+ .venv/
12
+ .vscode/
13
+ Dockerfile
14
+ compose.yaml
15
+ flake.lock
16
+ flake.nix
17
+
18
+ config.yaml
19
+ tests/files/
20
+ log/
21
+
22
+ build/
23
+ dist/
24
+ *.egg-info/
25
+ _version.py
@@ -0,0 +1,124 @@
1
+ name: docker
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - main
7
+
8
+ permissions:
9
+ packages: write
10
+ contents: read
11
+ attestations: write
12
+ id-token: write
13
+
14
+ jobs:
15
+ docker:
16
+ strategy:
17
+ fail-fast: false
18
+ matrix:
19
+ platform: [linux/amd64, linux/arm64]
20
+ include:
21
+ - platform: linux/amd64
22
+ runner: ubuntu-latest
23
+ - platform: linux/arm64
24
+ runner: ubuntu-24.04-arm
25
+
26
+ runs-on: ${{ matrix.runner }}
27
+
28
+ steps:
29
+ - name: Prepare
30
+ run: |
31
+ platform=${{ matrix.platform }}
32
+ echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV
33
+
34
+ - name: Checkout
35
+ uses: actions/checkout@v4
36
+
37
+ - name: Login to Docker Hub
38
+ uses: docker/login-action@v3
39
+ with:
40
+ username: ${{ vars.DOCKERHUB_USERNAME }}
41
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
42
+
43
+ - name: Set up Docker Buildx
44
+ uses: docker/setup-buildx-action@v3
45
+
46
+ - name: Docker meta
47
+ id: meta
48
+ uses: docker/metadata-action@v5
49
+ with:
50
+ images: wthueb/wi1-bot
51
+
52
+ - name: Build and push by digest
53
+ id: build
54
+ uses: docker/build-push-action@v6
55
+ with:
56
+ context: .
57
+ platforms: ${{ matrix.platform }}
58
+ tags: wthueb/wi1-bot
59
+ labels: ${{ steps.meta.outputs.labels }}
60
+ outputs: type=image,push-by-digest=true,name-canonical=true,push=true
61
+ cache-from: type=gha
62
+ cache-to: type=gha,mode=max
63
+
64
+ - name: Export digest
65
+ run: |
66
+ mkdir -p ${{ runner.temp }}/digests
67
+ digest="${{ steps.build.outputs.digest }}"
68
+ touch "${{ runner.temp }}/digests/${digest#sha256:}"
69
+
70
+ - name: Upload digest
71
+ uses: actions/upload-artifact@v4
72
+ with:
73
+ name: digests-${{ env.PLATFORM_PAIR }}
74
+ path: ${{ runner.temp }}/digests
75
+ if-no-files-found: error
76
+ retention-days: 1
77
+
78
+ merge:
79
+ runs-on: ubuntu-latest
80
+ needs: docker
81
+
82
+ steps:
83
+ - name: Download digests
84
+ uses: actions/download-artifact@v4
85
+ with:
86
+ path: ${{ runner.temp }}/digests
87
+ pattern: digests-*
88
+ merge-multiple: true
89
+
90
+ - name: Login to Docker Hub
91
+ uses: docker/login-action@v3
92
+ with:
93
+ username: ${{ vars.DOCKERHUB_USERNAME }}
94
+ password: ${{ secrets.DOCKERHUB_TOKEN }}
95
+
96
+ - name: Login to GitHub Container Registry
97
+ uses: docker/login-action@v3
98
+ with:
99
+ registry: ghcr.io
100
+ username: ${{ github.actor }}
101
+ password: ${{ secrets.GITHUB_TOKEN }}
102
+
103
+ - name: Set up Docker Buildx
104
+ uses: docker/setup-buildx-action@v3
105
+
106
+ - name: Docker meta
107
+ id: meta
108
+ uses: docker/metadata-action@v5
109
+ with:
110
+ images: |
111
+ wthueb/wi1-bot
112
+ ghcr.io/${{ github.repository_owner }}/wi1-bot
113
+
114
+ - name: Create Docker Hub manifest list and push
115
+ working-directory: ${{ runner.temp }}/digests
116
+ run: |
117
+ docker buildx imagetools create \
118
+ $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \
119
+ $(printf 'wthueb/wi1-bot@sha256:%s ' *)
120
+
121
+ - name: Inspect image
122
+ run: |
123
+ docker buildx imagetools inspect wthueb/wi1-bot:${{ steps.meta.outputs.version }}
124
+ docker buildx imagetools inspect ghcr.io/${{ github.repository_owner }}/wi1-bot:${{ steps.meta.outputs.version }}
@@ -0,0 +1,36 @@
1
+ FROM linuxserver/ffmpeg:latest AS base
2
+
3
+ RUN apt-get update && apt-get install -yqq --no-install-recommends python3
4
+
5
+ FROM base AS builder
6
+
7
+ COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
8
+ ENV UV_PYTHON_DOWNLOADS=0 UV_COMPILE_BYTECODE=1 UV_LINK_MODE=copy
9
+
10
+ WORKDIR /app
11
+
12
+ COPY pyproject.toml uv.lock .
13
+
14
+ RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked --no-install-project --no-dev
15
+
16
+ COPY . .
17
+
18
+ RUN --mount=type=cache,target=/root/.cache/uv uv sync --locked --no-dev
19
+
20
+ FROM base
21
+
22
+ COPY --from=builder --chown=app:app /app /app
23
+ ENV PATH="/app/.venv/bin:$PATH"
24
+
25
+ LABEL org.opencontainers.image.source="https://github.com/wthueb/wi1-bot"
26
+ LABEL org.opencontainers.image.maintainer="wilhueb@gmail.com"
27
+
28
+ ENV WB_CONFIG_PATH=/config/config.yaml
29
+ ENV WB_LOG_DIR=/logs
30
+
31
+ RUN mkdir -p /config
32
+ RUN mkdir -p /logs
33
+
34
+ EXPOSE 9000
35
+
36
+ ENTRYPOINT ["python", "-m", "wi1_bot.scripts.start"]
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wi1-bot
3
- Version: 2.0.2
3
+ Version: 2.0.4
4
4
  Summary: Discord bot for Radarr/Sonarr integration
5
5
  Project-URL: Homepage, https://github.com/wthueb/wi1-bot
6
6
  Author-email: William Huebner <wilhueb@gmail.com>
@@ -2,21 +2,22 @@ services:
2
2
  wi1-bot:
3
3
  container_name: wi1-bot
4
4
  image: wthueb/wi1-bot
5
- runtime: nvidia
6
5
  deploy:
7
6
  resources:
8
7
  reservations:
9
8
  devices:
10
- - capabilities:
11
- - gpu
9
+ - driver: nvidia
10
+ count: all
11
+ capabilities: [gpu]
12
+ devices:
13
+ - /dev/dri:/dev/dri
12
14
  environment:
13
15
  - WB_CONFIG_PATH=/data/config.yaml
14
- - WB_LOG_PATH=/data/logs
16
+ - WB_LOG_DIR=/data/logs
17
+ - MONGODB_CONNECTION_STRING=mongodb://mongodb:27017
15
18
  volumes:
16
19
  - .:/data
17
20
 
18
21
  mongodb:
19
22
  container_name: mongodb
20
23
  image: mongo:8.0
21
- ports:
22
- - 27017:27017
@@ -1,7 +1,6 @@
1
1
  import asyncio
2
2
  import logging
3
3
  import traceback
4
- from typing import Any
5
4
 
6
5
  import discord
7
6
  from discord.ext import commands
@@ -21,12 +20,14 @@ sonarr = Sonarr(config["sonarr"]["url"], config["sonarr"]["api_key"])
21
20
 
22
21
 
23
22
  @bot.check
24
- async def check_channel(ctx: commands.Context[Any]) -> bool:
23
+ async def check_channel(ctx: commands.Context[commands.Bot]) -> bool:
25
24
  return ctx.channel.id == config["discord"]["channel_id"]
26
25
 
27
26
 
28
27
  @bot.event
29
- async def on_command_error(ctx: commands.Context[Any], error: commands.CommandError) -> None:
28
+ async def on_command_error(
29
+ ctx: commands.Context[commands.Bot], error: commands.CommandError
30
+ ) -> None:
30
31
  match error:
31
32
  case commands.CommandNotFound() | commands.CheckFailure():
32
33
  pass
@@ -63,13 +64,13 @@ async def on_ready() -> None:
63
64
 
64
65
 
65
66
  @bot.before_invoke
66
- async def before_invoke(ctx: commands.Context[Any]) -> None:
67
+ async def before_invoke(ctx: commands.Context[commands.Bot]) -> None:
67
68
  logger.info(f"got command from {ctx.message.author}: {ctx.message.content}")
68
69
 
69
70
 
70
71
  @bot.command(name="downloads", aliases=["queue", "q"], help="see the status of movie downloads")
71
72
  @commands.cooldown(1, 10)
72
- async def downloads_cmd(ctx: commands.Context[Any]) -> None:
73
+ async def downloads_cmd(ctx: commands.Context[commands.Bot]) -> None:
73
74
  async with ctx.typing():
74
75
  queue = radarr.get_downloads() + sonarr.get_downloads()
75
76
 
@@ -84,7 +85,7 @@ async def downloads_cmd(ctx: commands.Context[Any]) -> None:
84
85
 
85
86
  @bot.command(name="quota", help="see your used space on the plex")
86
87
  @commands.cooldown(1, 60, commands.BucketType.user)
87
- async def quota_cmd(ctx: commands.Context[Any]) -> None:
88
+ async def quota_cmd(ctx: commands.Context[commands.Bot]) -> None:
88
89
  async with ctx.typing():
89
90
  used = (
90
91
  radarr.get_quota_amount(ctx.message.author.id)
@@ -98,17 +99,14 @@ async def quota_cmd(ctx: commands.Context[Any]) -> None:
98
99
 
99
100
  pct = used / maximum * 100 if maximum != 0 else 100
100
101
 
101
- msg = (
102
- f"you have added {used:.2f}/{maximum:.2f} GB ({pct:.1f}%) of useless crap"
103
- " to the plex"
104
- )
102
+ msg = f"you have added {used:.2f}/{maximum:.2f} GB ({pct:.1f}%) of useless crap to the plex"
105
103
 
106
104
  await reply(ctx.message, msg)
107
105
 
108
106
 
109
107
  @bot.command(name="quotas", help="see everyone's used space on the plex")
110
108
  @commands.cooldown(1, 60)
111
- async def quotas_cmd(ctx: commands.Context[Any]) -> None:
109
+ async def quotas_cmd(ctx: commands.Context[commands.Bot]) -> None:
112
110
  if "quotas" not in config["discord"]:
113
111
  await reply(ctx.message, "quotas are not implemented here")
114
112
  return
@@ -139,7 +137,7 @@ async def quotas_cmd(ctx: commands.Context[Any]) -> None:
139
137
 
140
138
  @bot.command(name="addtag", help="add a user tag")
141
139
  @commands.has_role("plex-admin")
142
- async def addtag_cmd(ctx: commands.Context[Any], name: str, user: discord.Member) -> None:
140
+ async def addtag_cmd(ctx: commands.Context[commands.Bot], name: str, user: discord.Member) -> None:
143
141
  tag = f"{name}: {user.id}"
144
142
 
145
143
  radarr.create_tag(tag)
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
  import logging
3
- from typing import Any
4
3
 
5
4
  from discord.ext import commands
6
5
 
@@ -18,7 +17,7 @@ class MovieCog(commands.Cog):
18
17
  self.radarr = Radarr(config["radarr"]["url"], config["radarr"]["api_key"])
19
18
 
20
19
  @commands.command(name="addmovie", help="add a movie to the plex")
21
- async def addmovie_cmd(self, ctx: commands.Context[Any], *, query: str = "") -> None:
20
+ async def addmovie_cmd(self, ctx: commands.Context[commands.Bot], *, query: str = "") -> None:
22
21
  if not query:
23
22
  await reply(ctx.message, "usage: !addmovie KEYWORDS...")
24
23
  return
@@ -71,7 +70,7 @@ class MovieCog(commands.Cog):
71
70
  await ctx.send(f"hey <@!{config['discord']['admin_id']}> get this guy a tag")
72
71
 
73
72
  @commands.command(name="delmovie", help="delete a movie from the plex")
74
- async def delmovie_cmd(self, ctx: commands.Context[Any], *, query: str = "") -> None:
73
+ async def delmovie_cmd(self, ctx: commands.Context[commands.Bot], *, query: str = "") -> None:
75
74
  if not query:
76
75
  await reply(ctx.message, "usage: !delmovie KEYWORDS...")
77
76
  return
@@ -1,6 +1,5 @@
1
1
  import asyncio
2
2
  import logging
3
- from typing import Any
4
3
 
5
4
  from discord.ext import commands
6
5
 
@@ -19,7 +18,7 @@ class SeriesCog(commands.Cog):
19
18
 
20
19
  @commands.command(name="addshow", help="add a show to the plex")
21
20
  @commands.has_any_role("plex-admin", "plex-shows")
22
- async def addshow_cmd(self, ctx: commands.Context[Any], *, query: str = "") -> None:
21
+ async def addshow_cmd(self, ctx: commands.Context[commands.Bot], *, query: str = "") -> None:
23
22
  if not query:
24
23
  await reply(ctx.message, "usage: !addshow KEYWORDS...")
25
24
  return
@@ -91,7 +90,9 @@ class SeriesCog(commands.Cog):
91
90
 
92
91
  @commands.command(name="delshow", help="delete a show from the plex")
93
92
  @commands.has_any_role("plex-admin", "plex-shows")
94
- async def delshow_command(self, ctx: commands.Context[Any], *, query: str = "") -> None:
93
+ async def delshow_command(
94
+ self, ctx: commands.Context[commands.Bot], *, query: str = ""
95
+ ) -> None:
95
96
  if not query:
96
97
  await reply(ctx.message, "usage: !delshow KEYWORDS...")
97
98
  return
@@ -1,3 +1,4 @@
1
+ import os
1
2
  from typing import Any, cast
2
3
 
3
4
  from mongoengine import Document, connect
@@ -23,7 +24,7 @@ class TranscodeItem(Document):
23
24
 
24
25
  class TranscodeQueue:
25
26
  def __init__(self) -> None:
26
- connect("wi1_bot", connect=False)
27
+ connect("wi1_bot", connect=True, host=os.environ.get("MONGODB_CONNECTION_STRING", None))
27
28
 
28
29
  def add(
29
30
  self,
@@ -103,6 +103,11 @@ def index() -> Any:
103
103
  return "", 200
104
104
 
105
105
 
106
+ @app.route("/health", methods=["GET"])
107
+ def health() -> Any:
108
+ return "OK", 200
109
+
110
+
106
111
  def start() -> None:
107
112
  logger.info("starting webhook listener")
108
113
 
@@ -1,9 +0,0 @@
1
- env/
2
- config.yaml
3
- tests/files/
4
- log/
5
-
6
- build/
7
- dist/
8
- *.egg-info/
9
- _version.py
@@ -1,59 +0,0 @@
1
- name: docker
2
-
3
- on:
4
- push:
5
- branches:
6
- - main
7
-
8
- jobs:
9
- docker:
10
- runs-on: ubuntu-latest
11
- permissions:
12
- packages: write
13
- contents: read
14
- attestations: write
15
- id-token: write
16
- steps:
17
- - name: Checkout
18
- uses: actions/checkout@v4
19
- with:
20
- fetch-depth: 0
21
-
22
- - name: Login to Docker Hub
23
- uses: docker/login-action@v3
24
- with:
25
- username: ${{ vars.DOCKERHUB_USERNAME }}
26
- password: ${{ secrets.DOCKERHUB_TOKEN }}
27
-
28
- - name: Login to GitHub Container Registry
29
- uses: docker/login-action@v3
30
- with:
31
- registry: ghcr.io
32
- username: ${{ github.actor }}
33
- password: ${{ secrets.GITHUB_TOKEN }}
34
-
35
- - name: Set up QEMU
36
- uses: docker/setup-qemu-action@v3
37
-
38
- - name: Set up Docker Buildx
39
- uses: docker/setup-buildx-action@v3
40
-
41
- - name: Docker meta
42
- id: meta
43
- uses: docker/metadata-action@v5
44
- with:
45
- images: |
46
- wthueb/wi1-bot
47
- ghcr.io/wthueb/wi1-bot
48
-
49
- - name: Build and push
50
- id: push
51
- uses: docker/build-push-action@v6
52
- with:
53
- context: .
54
- cache-from: type=gha
55
- cache-to: type=gha,mode=max
56
- platforms: linux/amd64,linux/arm64
57
- push: true
58
- tags: wthueb/wi1-bot:latest
59
- labels: ${{ steps.meta.outputs.labels }}
wi1_bot-2.0.2/Dockerfile DELETED
@@ -1,32 +0,0 @@
1
- FROM jrottenberg/ffmpeg:7.1-nvidia2404 AS base
2
-
3
- RUN apt-get update && apt-get install -yqq --no-install-recommends python3
4
-
5
- FROM base AS compiler
6
-
7
- RUN apt-get install -yqq --no-install-recommends python3-venv git
8
-
9
- RUN python3 -m venv /opt/venv
10
- ENV PATH="/opt/venv/bin:$PATH"
11
-
12
- WORKDIR /app
13
- COPY . .
14
- RUN pip install .
15
-
16
- FROM base
17
-
18
- COPY --from=compiler /opt/venv /opt/venv
19
- ENV PATH="/opt/venv/bin:$PATH"
20
-
21
- LABEL org.opencontainers.image.source="https://github.com/wthueb/wi1-bot"
22
- LABEL org.opencontainers.image.maintainer="wilhueb@gmail.com"
23
-
24
- ENV WB_CONFIG_PATH=/config/config.yaml
25
- ENV WB_LOG_DIR=/logs
26
-
27
- RUN mkdir -p /config
28
- RUN mkdir -p /logs
29
-
30
- EXPOSE 9000
31
-
32
- ENTRYPOINT ["python", "-m", "wi1_bot.scripts.start"]
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes