wi1-bot 1.4.3__tar.gz → 1.4.5__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.
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/.github/workflows/pypi-publish.yml +1 -1
- wi1-bot-1.4.5/.gitignore +8 -0
- wi1-bot-1.4.5/Dockerfile +20 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/PKG-INFO +2 -1
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/README.md +1 -0
- wi1-bot-1.4.5/compose.yaml +16 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/pyproject.toml +1 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/_version.py +2 -2
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/arr/radarr.py +2 -2
- wi1-bot-1.4.5/wi1_bot/scripts/rescan.py +57 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/transcoder/transcoder.py +28 -26
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot.egg-info/PKG-INFO +2 -1
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot.egg-info/SOURCES.txt +4 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot.egg-info/entry_points.txt +1 -0
- /wi1-bot-1.4.3/.gitignore → /wi1-bot-1.4.5/.dockerignore +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/.pre-commit-config.yaml +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/.vscode/launch.json +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/.vscode/settings.json +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/LICENSE +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/config.yaml.template +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/setup.cfg +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/tests/movie_downloaded.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/__init__.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/arr/__init__.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/arr/download.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/arr/episode.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/arr/movie.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/arr/sonarr.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/config.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/discord/__init__.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/discord/bot.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/discord/cogs/__init__.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/discord/cogs/movie.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/discord/cogs/series.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/discord/helpers.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/push.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/scripts/__init__.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/scripts/add_tag.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/scripts/start.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/scripts/transcode_item.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/transcoder/__init__.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/transcoder/transcode_queue.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot/webhook.py +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot.egg-info/dependency_links.txt +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot.egg-info/requires.txt +0 -0
- {wi1-bot-1.4.3 → wi1-bot-1.4.5}/wi1_bot.egg-info/top_level.txt +0 -0
wi1-bot-1.4.5/.gitignore
ADDED
wi1-bot-1.4.5/Dockerfile
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
FROM python:3.10
|
2
|
+
|
3
|
+
RUN apt-get update && apt-get install -y ffmpeg
|
4
|
+
|
5
|
+
WORKDIR /app
|
6
|
+
|
7
|
+
COPY . .
|
8
|
+
|
9
|
+
RUN pip install .
|
10
|
+
|
11
|
+
ENV WB_CONFIG_PATH=/app/config/config.yaml
|
12
|
+
ENV WB_LOG_DIR=/app/logs
|
13
|
+
|
14
|
+
RUN mkdir -p config
|
15
|
+
RUN mkdir -p logs
|
16
|
+
|
17
|
+
EXPOSE 9000
|
18
|
+
|
19
|
+
ENTRYPOINT ["python", "-m", "wi1_bot.scripts.start"]
|
20
|
+
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: wi1-bot
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.5
|
4
4
|
Summary: Discord bot for Radarr/Sonarr integration
|
5
5
|
Home-page: https://github.com/wthueb/wi1-bot
|
6
6
|
Author-email: William Huebner <wilhueb@gmail.com>
|
@@ -57,6 +57,7 @@ Requires Python >=3.10.
|
|
57
57
|
|
58
58
|
### TODO
|
59
59
|
|
60
|
+
- use sqlite
|
60
61
|
- have config.discord.users be a dict with 'quotas' and 'name' for *arr tags
|
61
62
|
- Better pushover notifications
|
62
63
|
- Failures for pretty much everything
|
@@ -0,0 +1,16 @@
|
|
1
|
+
services:
|
2
|
+
wi1-bot:
|
3
|
+
container_name: wi1-bot
|
4
|
+
image: wthueb/wi1-bot
|
5
|
+
runtime: nvidia
|
6
|
+
deploy:
|
7
|
+
resources:
|
8
|
+
reservations:
|
9
|
+
devices:
|
10
|
+
- capabilities:
|
11
|
+
- gpu
|
12
|
+
environment:
|
13
|
+
- WB_CONFIG_PATH=/data/config.yaml
|
14
|
+
- WB_LOG_PATH=/data/logs
|
15
|
+
volumes:
|
16
|
+
- .:/data
|
@@ -27,6 +27,7 @@ Homepage = "https://github.com/wthueb/wi1-bot"
|
|
27
27
|
wi1-bot = "wi1_bot.scripts.start:main"
|
28
28
|
transcode-item = "wi1_bot.scripts.transcode_item:main"
|
29
29
|
add-tag = "wi1_bot.scripts.add_tag:main"
|
30
|
+
rescan = "wi1_bot.scripts.rescan:main"
|
30
31
|
|
31
32
|
[project.optional-dependencies]
|
32
33
|
dev = [
|
@@ -149,10 +149,10 @@ class Radarr:
|
|
149
149
|
raise ValueError(f"no quality profile with the id {profile_id}")
|
150
150
|
|
151
151
|
def rescan_movie(self, movie_id: int) -> None:
|
152
|
-
self._radarr.post_command("RescanMovie", movieId=movie_id)
|
152
|
+
self._radarr.post_command("RescanMovie", movieId=movie_id)
|
153
153
|
|
154
154
|
def refresh_movie(self, movie_id: int) -> None:
|
155
|
-
self._radarr.post_command("RefreshMovie", movieIds=[movie_id])
|
155
|
+
self._radarr.post_command("RefreshMovie", movieIds=[movie_id])
|
156
156
|
|
157
157
|
def search_missing(self) -> None:
|
158
158
|
self._radarr.post_command(name="MissingMoviesSearch")
|
@@ -0,0 +1,57 @@
|
|
1
|
+
import argparse
|
2
|
+
from time import sleep
|
3
|
+
from typing import cast
|
4
|
+
|
5
|
+
from wi1_bot.arr.radarr import Radarr
|
6
|
+
from wi1_bot.arr.sonarr import Sonarr
|
7
|
+
from wi1_bot.config import config
|
8
|
+
|
9
|
+
|
10
|
+
def rescan_radarr() -> None:
|
11
|
+
radarr = Radarr(config["radarr"]["url"], config["radarr"]["api_key"])
|
12
|
+
|
13
|
+
all_movies = radarr._radarr.get_movie()
|
14
|
+
assert isinstance(all_movies, list)
|
15
|
+
all_movies.sort(key=lambda m: cast(str, m["title"]))
|
16
|
+
|
17
|
+
for movie in all_movies:
|
18
|
+
assert isinstance(movie, dict)
|
19
|
+
print(f"Rescanning {movie['title']}...")
|
20
|
+
radarr.refresh_movie(movie["id"])
|
21
|
+
sleep(3)
|
22
|
+
|
23
|
+
|
24
|
+
def rescan_sonarr() -> None:
|
25
|
+
sonarr = Sonarr(config["sonarr"]["url"], config["sonarr"]["api_key"])
|
26
|
+
|
27
|
+
all_series = sonarr._sonarr.get_series()
|
28
|
+
assert isinstance(all_series, list)
|
29
|
+
all_series.sort(key=lambda s: cast(str, s["title"]))
|
30
|
+
|
31
|
+
for series in all_series:
|
32
|
+
assert isinstance(series, dict)
|
33
|
+
print(f"Rescanning {series['title']}...")
|
34
|
+
sonarr.rescan_series(series["id"])
|
35
|
+
sleep(5)
|
36
|
+
|
37
|
+
|
38
|
+
def main() -> None:
|
39
|
+
parser = argparse.ArgumentParser(description="Rescan all movies/shows")
|
40
|
+
|
41
|
+
parser.add_argument(
|
42
|
+
"service", nargs="?", choices=["radarr", "sonarr"], help="radarr or sonarr"
|
43
|
+
)
|
44
|
+
|
45
|
+
args = parser.parse_args()
|
46
|
+
|
47
|
+
if args.service == "radarr":
|
48
|
+
rescan_radarr()
|
49
|
+
elif args.service == "sonarr":
|
50
|
+
rescan_sonarr()
|
51
|
+
else:
|
52
|
+
rescan_radarr()
|
53
|
+
rescan_sonarr()
|
54
|
+
|
55
|
+
|
56
|
+
if __name__ == "__main__":
|
57
|
+
main()
|
@@ -46,17 +46,10 @@ class Transcoder:
|
|
46
46
|
continue
|
47
47
|
|
48
48
|
try:
|
49
|
-
self._do_transcode(item)
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
pass
|
54
|
-
except FileNotFoundError:
|
55
|
-
# don't retry
|
56
|
-
queue.remove(item)
|
57
|
-
except UnknownError:
|
58
|
-
# don't retry
|
59
|
-
queue.remove(item)
|
49
|
+
remove = self._do_transcode(item)
|
50
|
+
|
51
|
+
if remove:
|
52
|
+
queue.remove(item)
|
60
53
|
except Exception:
|
61
54
|
self.logger.warning(
|
62
55
|
"got exception when trying to transcode", exc_info=True
|
@@ -64,14 +57,14 @@ class Transcoder:
|
|
64
57
|
|
65
58
|
sleep(3)
|
66
59
|
|
67
|
-
def _do_transcode(self, item: TranscodeItem) ->
|
60
|
+
def _do_transcode(self, item: TranscodeItem) -> bool:
|
68
61
|
path = pathlib.Path(item.path)
|
69
62
|
|
70
|
-
self.logger.
|
63
|
+
self.logger.info(f"attempting to transcode {path.name}")
|
71
64
|
|
72
65
|
if path.suffix == ".avi":
|
73
|
-
self.logger.
|
74
|
-
return
|
66
|
+
self.logger.info(f"cannot transcode {path.name}: .avi not supported")
|
67
|
+
return True
|
75
68
|
|
76
69
|
# push.send(f"{basename}", title="starting transcode")
|
77
70
|
|
@@ -103,26 +96,32 @@ class Transcoder:
|
|
103
96
|
tmp_log_path = tmp_folder / "wi1_bot.transcoder.log"
|
104
97
|
|
105
98
|
with open(tmp_log_path, "w") as ffmpeg_log_file:
|
106
|
-
|
99
|
+
assert proc.stdout is not None
|
100
|
+
for line in proc.stdout:
|
107
101
|
ffmpeg_log_file.write(line)
|
108
102
|
last_output = line.strip()
|
109
103
|
|
110
104
|
status = proc.wait()
|
111
105
|
|
112
106
|
if status != 0:
|
113
|
-
|
114
|
-
|
115
|
-
if "No such file or directory" in last_output:
|
116
|
-
self.logger.debug(
|
107
|
+
if "Error opening input files" in last_output:
|
108
|
+
self.logger.info(
|
117
109
|
f"file does not exist: {path}, skipping transcoding"
|
118
110
|
)
|
119
|
-
|
111
|
+
return True
|
120
112
|
|
121
113
|
if "received signal 15" in last_output:
|
122
|
-
self.logger.
|
114
|
+
self.logger.info(
|
123
115
|
f"transcoding interrupted by signal: {path}, will retry"
|
124
116
|
)
|
125
|
-
|
117
|
+
return False
|
118
|
+
|
119
|
+
if "cannot open shared object file" in last_output:
|
120
|
+
self.logger.error(
|
121
|
+
"ffmpeg error: missing shared object file, will retry"
|
122
|
+
)
|
123
|
+
push.send(f"ffmpeg error: {last_output}", title="ffmpeg error")
|
124
|
+
return False
|
126
125
|
|
127
126
|
perm_log_path = tmp_folder / f"{path.stem}.log"
|
128
127
|
|
@@ -133,6 +132,8 @@ class Transcoder:
|
|
133
132
|
perm_log_path.parent.mkdir(parents=True, exist_ok=True)
|
134
133
|
|
135
134
|
shutil.copy(tmp_log_path, perm_log_path)
|
135
|
+
|
136
|
+
self.logger.error(f"ffmpeg failed (status {status}): {last_output}")
|
136
137
|
self.logger.error(f"log file: {perm_log_path}")
|
137
138
|
|
138
139
|
push.send(
|
@@ -140,7 +141,7 @@ class Transcoder:
|
|
140
141
|
title="transcoding error",
|
141
142
|
)
|
142
143
|
|
143
|
-
|
144
|
+
return True
|
144
145
|
|
145
146
|
new_path = path.parent / transcode_to.name
|
146
147
|
|
@@ -150,7 +151,7 @@ class Transcoder:
|
|
150
151
|
)
|
151
152
|
|
152
153
|
transcode_to.unlink()
|
153
|
-
return
|
154
|
+
return True
|
154
155
|
|
155
156
|
shutil.move(transcode_to, new_path)
|
156
157
|
path.unlink()
|
@@ -160,8 +161,9 @@ class Transcoder:
|
|
160
161
|
self.logger.info(f"transcoded: {path.name} -> {new_path.name}")
|
161
162
|
# push.send(f"{path.name} -> {new_path.name}", title="file transcoded")
|
162
163
|
|
164
|
+
return True
|
165
|
+
|
163
166
|
def _rescan_content(self, item: TranscodeItem, new_path: str) -> None:
|
164
|
-
# FIXME: don't hardcode library paths (config)
|
165
167
|
if item.content_id is not None:
|
166
168
|
if new_path.startswith(config["radarr"]["root_folder"]):
|
167
169
|
self.radarr.rescan_movie(item.content_id)
|
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: wi1-bot
|
3
|
-
Version: 1.4.
|
3
|
+
Version: 1.4.5
|
4
4
|
Summary: Discord bot for Radarr/Sonarr integration
|
5
5
|
Home-page: https://github.com/wthueb/wi1-bot
|
6
6
|
Author-email: William Huebner <wilhueb@gmail.com>
|
@@ -57,6 +57,7 @@ Requires Python >=3.10.
|
|
57
57
|
|
58
58
|
### TODO
|
59
59
|
|
60
|
+
- use sqlite
|
60
61
|
- have config.discord.users be a dict with 'quotas' and 'name' for *arr tags
|
61
62
|
- Better pushover notifications
|
62
63
|
- Failures for pretty much everything
|
@@ -1,7 +1,10 @@
|
|
1
|
+
.dockerignore
|
1
2
|
.gitignore
|
2
3
|
.pre-commit-config.yaml
|
4
|
+
Dockerfile
|
3
5
|
LICENSE
|
4
6
|
README.md
|
7
|
+
compose.yaml
|
5
8
|
config.yaml.template
|
6
9
|
pyproject.toml
|
7
10
|
setup.cfg
|
@@ -34,6 +37,7 @@ wi1_bot/discord/cogs/movie.py
|
|
34
37
|
wi1_bot/discord/cogs/series.py
|
35
38
|
wi1_bot/scripts/__init__.py
|
36
39
|
wi1_bot/scripts/add_tag.py
|
40
|
+
wi1_bot/scripts/rescan.py
|
37
41
|
wi1_bot/scripts/start.py
|
38
42
|
wi1_bot/scripts/transcode_item.py
|
39
43
|
wi1_bot/transcoder/__init__.py
|
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
|
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
|