diff options
-rw-r--r-- | flake.lock | 72 | ||||
-rw-r--r-- | flake.nix | 15 | ||||
-rw-r--r-- | hosts/vidhar/audiobookshelf.nix | 13 | ||||
-rw-r--r-- | hosts/vidhar/audiobookshelf/abs-podcast-autoplaylist-gkleen.toml | 19 | ||||
-rw-r--r-- | hosts/vidhar/audiobookshelf/default.nix | 21 | ||||
-rw-r--r-- | hosts/vidhar/default.nix | 2 | ||||
-rw-r--r-- | modules/abs-podcast-autoplaylist.nix | 54 | ||||
-rw-r--r-- | overlays/abs-podcast-autoplaylist/.gitignore | 2 | ||||
-rw-r--r-- | overlays/abs-podcast-autoplaylist/abs_podcast_autoplaylist/__init__.py | 0 | ||||
-rw-r--r-- | overlays/abs-podcast-autoplaylist/abs_podcast_autoplaylist/__main__.py | 107 | ||||
-rw-r--r-- | overlays/abs-podcast-autoplaylist/default.nix | 28 | ||||
-rw-r--r-- | overlays/abs-podcast-autoplaylist/pyproject.toml | 16 | ||||
-rw-r--r-- | overlays/abs-podcast-autoplaylist/uv.lock | 129 | ||||
-rw-r--r-- | shell.nix | 2 |
14 files changed, 465 insertions, 15 deletions
@@ -879,6 +879,52 @@ | |||
879 | "type": "gitlab" | 879 | "type": "gitlab" |
880 | } | 880 | } |
881 | }, | 881 | }, |
882 | "pyproject-build-systems": { | ||
883 | "inputs": { | ||
884 | "nixpkgs": [ | ||
885 | "nixpkgs" | ||
886 | ], | ||
887 | "pyproject-nix": [ | ||
888 | "pyproject-nix" | ||
889 | ], | ||
890 | "uv2nix": [ | ||
891 | "uv2nix" | ||
892 | ] | ||
893 | }, | ||
894 | "locked": { | ||
895 | "lastModified": 1744599653, | ||
896 | "narHash": "sha256-nysSwVVjG4hKoOjhjvE6U5lIKA8sEr1d1QzEfZsannU=", | ||
897 | "owner": "pyproject-nix", | ||
898 | "repo": "build-system-pkgs", | ||
899 | "rev": "7dba6dbc73120e15b558754c26024f6c93015dd7", | ||
900 | "type": "github" | ||
901 | }, | ||
902 | "original": { | ||
903 | "owner": "pyproject-nix", | ||
904 | "repo": "build-system-pkgs", | ||
905 | "type": "github" | ||
906 | } | ||
907 | }, | ||
908 | "pyproject-nix": { | ||
909 | "inputs": { | ||
910 | "nixpkgs": [ | ||
911 | "nixpkgs" | ||
912 | ] | ||
913 | }, | ||
914 | "locked": { | ||
915 | "lastModified": 1746540146, | ||
916 | "narHash": "sha256-QxdHGNpbicIrw5t6U3x+ZxeY/7IEJ6lYbvsjXmcxFIM=", | ||
917 | "owner": "pyproject-nix", | ||
918 | "repo": "pyproject.nix", | ||
919 | "rev": "e09c10c24ebb955125fda449939bfba664c467fd", | ||
920 | "type": "github" | ||
921 | }, | ||
922 | "original": { | ||
923 | "owner": "pyproject-nix", | ||
924 | "repo": "pyproject.nix", | ||
925 | "type": "github" | ||
926 | } | ||
927 | }, | ||
882 | "root": { | 928 | "root": { |
883 | "inputs": { | 929 | "inputs": { |
884 | "backup-utils": "backup-utils", | 930 | "backup-utils": "backup-utils", |
@@ -902,7 +948,10 @@ | |||
902 | "nvfetcher": "nvfetcher", | 948 | "nvfetcher": "nvfetcher", |
903 | "poetry2nix": "poetry2nix", | 949 | "poetry2nix": "poetry2nix", |
904 | "prometheus-borg-exporter": "prometheus-borg-exporter", | 950 | "prometheus-borg-exporter": "prometheus-borg-exporter", |
951 | "pyproject-build-systems": "pyproject-build-systems", | ||
952 | "pyproject-nix": "pyproject-nix", | ||
905 | "sops-nix": "sops-nix", | 953 | "sops-nix": "sops-nix", |
954 | "uv2nix": "uv2nix", | ||
906 | "waybar": "waybar" | 955 | "waybar": "waybar" |
907 | } | 956 | } |
908 | }, | 957 | }, |
@@ -978,6 +1027,29 @@ | |||
978 | "type": "github" | 1027 | "type": "github" |
979 | } | 1028 | } |
980 | }, | 1029 | }, |
1030 | "uv2nix": { | ||
1031 | "inputs": { | ||
1032 | "nixpkgs": [ | ||
1033 | "nixpkgs" | ||
1034 | ], | ||
1035 | "pyproject-nix": [ | ||
1036 | "pyproject-nix" | ||
1037 | ] | ||
1038 | }, | ||
1039 | "locked": { | ||
1040 | "lastModified": 1746649034, | ||
1041 | "narHash": "sha256-gmv+ZiY3pQnwgI0Gm3Z1tNSux1CnOJ0De+xeDOol1+0=", | ||
1042 | "owner": "pyproject-nix", | ||
1043 | "repo": "uv2nix", | ||
1044 | "rev": "fe540e91c26f378c62bf6da365a97e848434d0cd", | ||
1045 | "type": "github" | ||
1046 | }, | ||
1047 | "original": { | ||
1048 | "owner": "pyproject-nix", | ||
1049 | "repo": "uv2nix", | ||
1050 | "type": "github" | ||
1051 | } | ||
1052 | }, | ||
981 | "waybar": { | 1053 | "waybar": { |
982 | "inputs": { | 1054 | "inputs": { |
983 | "flake-compat": [ | 1055 | "flake-compat": [ |
@@ -125,6 +125,21 @@ | |||
125 | nixpkgs.follows = "nixpkgs"; | 125 | nixpkgs.follows = "nixpkgs"; |
126 | }; | 126 | }; |
127 | }; | 127 | }; |
128 | pyproject-nix = { | ||
129 | url = "github:pyproject-nix/pyproject.nix"; | ||
130 | inputs.nixpkgs.follows = "nixpkgs"; | ||
131 | }; | ||
132 | uv2nix = { | ||
133 | url = "github:pyproject-nix/uv2nix"; | ||
134 | inputs.pyproject-nix.follows = "pyproject-nix"; | ||
135 | inputs.nixpkgs.follows = "nixpkgs"; | ||
136 | }; | ||
137 | pyproject-build-systems = { | ||
138 | url = "github:pyproject-nix/build-system-pkgs"; | ||
139 | inputs.pyproject-nix.follows = "pyproject-nix"; | ||
140 | inputs.uv2nix.follows = "uv2nix"; | ||
141 | inputs.nixpkgs.follows = "nixpkgs"; | ||
142 | }; | ||
128 | 143 | ||
129 | ca-util = { | 144 | ca-util = { |
130 | type = "gitlab"; | 145 | type = "gitlab"; |
diff --git a/hosts/vidhar/audiobookshelf.nix b/hosts/vidhar/audiobookshelf.nix deleted file mode 100644 index 0f3b73e8..00000000 --- a/hosts/vidhar/audiobookshelf.nix +++ /dev/null | |||
@@ -1,13 +0,0 @@ | |||
1 | { pkgs, ... }: | ||
2 | |||
3 | { | ||
4 | config = { | ||
5 | services.audiobookshelf = { | ||
6 | enable = true; | ||
7 | host = "2a03:4000:52:ada:4:1::"; | ||
8 | port = 28982; | ||
9 | }; | ||
10 | |||
11 | users.groups.audiobookshelf.members = [ "gkleen" ]; | ||
12 | }; | ||
13 | } | ||
diff --git a/hosts/vidhar/audiobookshelf/abs-podcast-autoplaylist-gkleen.toml b/hosts/vidhar/audiobookshelf/abs-podcast-autoplaylist-gkleen.toml new file mode 100644 index 00000000..a5319e38 --- /dev/null +++ b/hosts/vidhar/audiobookshelf/abs-podcast-autoplaylist-gkleen.toml | |||
@@ -0,0 +1,19 @@ | |||
1 | { | ||
2 | "data": "ENC[AES256_GCM,data:60OmHwuLC7RJVNNn8lsCFjIFrtDlmmT3yAm3DYn/K2b8OJB/lzKBhMUCyPpoI2lfMm6y47/DMwXI3ExH3QwfgGRf4i/Tcv7p6FCkjFgDc0RhAM7cXNSnh1gKTff8QYtPoNIzmycFCThNr7iZsPsf2/1npVaVHTnt9nTc+cmDLc+lELlvjSE00JOXch/if7KPwFww9K83XlrFmoRvwybfXR0unJqxK2XLvj+dQuKD4Bhyb88iSgu4dX1yw2uBSZBD16S4Io0DaZ+as5Yw4Kon7WMj3Jd5kz8ZxK+0NCy1CVJHOfJIwgYl0SVPp4DpbAPtJO4R/ciXyDQ/XGpoLtHjxnKXaJlJoSiA7FhuSEk+jB/peLHrYV1obdIRE5Dstly01S5cydKlfQ+A0TSjxFSWBYMEiD89sD09Br3iSJX5FejOoS8d2IQJ5faVzgQl4T5aBKsxCNNwmYrEe8m9HN7o2eer8nTKMln5IxZi3ZWhnjgJfrJ4QTXFndxCb78jo8HroN3+7VhoM136UZkqH1OMrIgAH/XSlW08G8m9MRamKsAWklq9aVflcEsPWTHmYW7rjAapQYf+jyK6BbfHcYmyKM82TFZ5iNB60Pth6EJgb2V8PZiChGvDzQvFYYOO3p9a/J8bVqsnPZBXXYcIBt42ZuRPvyyUTfM+75V1eYE9ZGFML+QlofwNCAg+/Rnl+RRy4z+8xQxd8Dn06geDpHsr4yND72FRUTKLbjxF5xfbzBRcZEXjGkyFdEAF7rB78I8xIqii+n6Yt8uEURmd4geI9KWXRQnwofTz9pklaAnRbER8zy/BJIiIYy8zecUHJn9v/DPnsnksfL6RRmG4tHaRBDbpAag0kVkCrpO/flK6dZOl/wvoVVVqT2O69a9/RpHLSV2f//ZS6L9s6vaYe4pXL0M6QymgA22sNHaws6XggJlTxVOFGRejMGYrKqVWtC+2UNbnel+/J0N1qj4luWfQaf9+1j+fq7vyLSzXYFCiyOLAznpqOhzKu6VWy2IbR0UnCoL5ZbhIba9e2MXM7Czy9Yee4xc=,iv:M0GbtFFl1XUeq+y9H+MiD+9z/ASB9hsd06KhpPzSwEo=,tag:vTLIIf+CeZN6DU25CSP8tw==,type:str]", | ||
3 | "sops": { | ||
4 | "age": [ | ||
5 | { | ||
6 | "recipient": "age1rmmhetcmllq0ahl5qznlr0eya2zdxwl9h6y5wnl97d2wtyx5t99sm2u866", | ||
7 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0aE1XNUNCM1Q5V0d3R2JG\nbjJZTmdvQ21JbmtyR0ZmODFMdVBGejRoam1vCjMzMGdTb3BReDVCa2JJU0JrSHFP\ndTdicU5TRjIrTWpteDMzeGtDT0xaelkKLS0tIFhaSlFrbzFDUjRZV0lGR0cydVdZ\nY2xma0VSVXlTM1JucFJUSys4dlRvdEUK9gQNQEdKDDf1ikWzd6uTlE50WsfO/EB0\nGH2Ono6oNWbKWTyl/wRO8NzXx0nudwqq66s0oBLIdTMQOpIBBNI0XQ==\n-----END AGE ENCRYPTED FILE-----\n" | ||
8 | }, | ||
9 | { | ||
10 | "recipient": "age1qffdqvy9arld9zd5a5cylt0n98xhcns5shxhrhwjq5g4qa844ejselaa4l", | ||
11 | "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiRWFqSHNlY1IvMkkwaEto\ncHZHa2p1Y25SakFkS2JYMlRFcFhnZGY1dVRFCkxSWmxvcHZMampQKzdKRHI0ZVMx\nUTFtR0pHbzFaQ0xQUFA2ZERDSWpwS0UKLS0tIFBaSGczY3VWdy9TKzRDZWZ2SElY\nbVQ4dDNhQllmVmViWGs5c3V4TmNscjQKeugevQJFAN/8JrzeAm4hm2JsQGb26BCb\n3dKYnN1kJU7oVHr1aVfXwMpELNYt9poX6WTY2h9lsdHuRlqoFXAA5Q==\n-----END AGE ENCRYPTED FILE-----\n" | ||
12 | } | ||
13 | ], | ||
14 | "lastmodified": "2025-05-10T10:25:15Z", | ||
15 | "mac": "ENC[AES256_GCM,data:dhj7e+vF3uiR6I22PR5tdNdM8EyrWmGGTIqjj8H7IdNIsZBHzjeHlBDFOwN7z/JMO0BVwIi4DmhApg2BSPGsQZGDQZ28UTCC8TDtd1zmfGtSP8R8AFHADYdLK/desMtHg6BZTnLv5tpba34WWdflMNOQpwgWPZsIk/DkLaoXdvk=,iv:qkoAZngTz2sfWdxDs+h8Mb2IrkF8gqnQoR5iRoeKjbY=,tag:zXrkBJmPM4ItJxMnX8IDxQ==,type:str]", | ||
16 | "unencrypted_suffix": "_unencrypted", | ||
17 | "version": "3.10.2" | ||
18 | } | ||
19 | } | ||
diff --git a/hosts/vidhar/audiobookshelf/default.nix b/hosts/vidhar/audiobookshelf/default.nix new file mode 100644 index 00000000..136bcaff --- /dev/null +++ b/hosts/vidhar/audiobookshelf/default.nix | |||
@@ -0,0 +1,21 @@ | |||
1 | { config, pkgs, lib, ... }: | ||
2 | |||
3 | { | ||
4 | config = { | ||
5 | services.audiobookshelf = { | ||
6 | enable = true; | ||
7 | host = "2a03:4000:52:ada:4:1::"; | ||
8 | port = 28982; | ||
9 | }; | ||
10 | |||
11 | users.groups.audiobookshelf.members = [ "gkleen" ]; | ||
12 | |||
13 | services.abs-podcast-autoplaylist = { | ||
14 | gkleen = {}; | ||
15 | }; | ||
16 | sops.secrets.${config.services.abs-podcast-autoplaylist.gkleen.configSecret} = { | ||
17 | format = "binary"; | ||
18 | sopsFile = ./abs-podcast-autoplaylist-gkleen.toml; | ||
19 | }; | ||
20 | }; | ||
21 | } | ||
diff --git a/hosts/vidhar/default.nix b/hosts/vidhar/default.nix index b65a4cf8..c9470ee9 100644 --- a/hosts/vidhar/default.nix +++ b/hosts/vidhar/default.nix | |||
@@ -4,7 +4,7 @@ with lib; | |||
4 | 4 | ||
5 | { | 5 | { |
6 | imports = with flake.nixosModules.systemProfiles; [ | 6 | imports = with flake.nixosModules.systemProfiles; [ |
7 | ./zfs.nix ./network ./samba.nix ./dns ./prometheus ./borg ./pgbackrest ./postgresql.nix ./immich.nix ./paperless ./hledger ./audiobookshelf.nix | 7 | ./zfs.nix ./network ./samba.nix ./dns ./prometheus ./borg ./pgbackrest ./postgresql.nix ./immich.nix ./paperless ./hledger ./audiobookshelf |
8 | tmpfs-root zfs | 8 | tmpfs-root zfs |
9 | initrd-all-crypto-modules default-locale openssh rebuild-machines | 9 | initrd-all-crypto-modules default-locale openssh rebuild-machines |
10 | build-server | 10 | build-server |
diff --git a/modules/abs-podcast-autoplaylist.nix b/modules/abs-podcast-autoplaylist.nix new file mode 100644 index 00000000..2532cfc3 --- /dev/null +++ b/modules/abs-podcast-autoplaylist.nix | |||
@@ -0,0 +1,54 @@ | |||
1 | { config, pkgs, lib, utils, ... }: | ||
2 | |||
3 | let | ||
4 | cfg = config.services.abs-podcast-autoplaylist; | ||
5 | |||
6 | enabledAttrs = lib.filterAttrs (_name: { enable, ... }: enable) cfg; | ||
7 | in { | ||
8 | options = { | ||
9 | services.abs-podcast-autoplaylist = lib.mkOption { | ||
10 | default = {}; | ||
11 | type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: { | ||
12 | options = { | ||
13 | enable = lib.mkEnableOption "this instance of abs-podcast-autoplaylist" // { | ||
14 | default = true; | ||
15 | }; | ||
16 | cron = lib.mkOption { | ||
17 | type = lib.types.str; | ||
18 | default = "*-*-* *:00/30:00"; | ||
19 | }; | ||
20 | configSecret = lib.mkOption { | ||
21 | type = lib.types.str; | ||
22 | default = "abs-podcast-autoplaylist-${name}.toml"; | ||
23 | }; | ||
24 | }; | ||
25 | })); | ||
26 | }; | ||
27 | }; | ||
28 | |||
29 | config = lib.mkIf (enabledAttrs != {}) { | ||
30 | systemd.services = { | ||
31 | "abs-podcast-autoplaylist@" = { | ||
32 | serviceConfig = { | ||
33 | WorkingDirectory = "%d"; | ||
34 | DynamicUser = true; | ||
35 | ProtectHome = true; | ||
36 | PrivateTmp = true; | ||
37 | PrivateDevices = true; | ||
38 | Type = "oneshot"; | ||
39 | ExecStart = "${lib.getExe pkgs.abs-podcast-autoplaylist} %I.toml"; | ||
40 | }; | ||
41 | }; | ||
42 | } // lib.mapAttrs' (name: { configSecret, ... }: lib.nameValuePair "abs-podcast-autoplaylist@${utils.escapeSystemdPath name}" { | ||
43 | overrideStrategy = "asDropin"; | ||
44 | serviceConfig = { | ||
45 | LoadCredential = "${name}.toml:${config.sops.secrets.${configSecret}.path}"; | ||
46 | }; | ||
47 | }) enabledAttrs; | ||
48 | |||
49 | systemd.timers = lib.mapAttrs' (name: { cron, ... }: lib.nameValuePair "abs-podcast-autoplaylist@${utils.escapeSystemdPath name}" { | ||
50 | wantedBy = [ "timers.target" ]; | ||
51 | timerConfig.OnCalendar = cron; | ||
52 | }) enabledAttrs; | ||
53 | }; | ||
54 | } | ||
diff --git a/overlays/abs-podcast-autoplaylist/.gitignore b/overlays/abs-podcast-autoplaylist/.gitignore new file mode 100644 index 00000000..4ccfae70 --- /dev/null +++ b/overlays/abs-podcast-autoplaylist/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | .venv | ||
2 | **/__pycache__ | ||
diff --git a/overlays/abs-podcast-autoplaylist/abs_podcast_autoplaylist/__init__.py b/overlays/abs-podcast-autoplaylist/abs_podcast_autoplaylist/__init__.py new file mode 100644 index 00000000..e69de29b --- /dev/null +++ b/overlays/abs-podcast-autoplaylist/abs_podcast_autoplaylist/__init__.py | |||
diff --git a/overlays/abs-podcast-autoplaylist/abs_podcast_autoplaylist/__main__.py b/overlays/abs-podcast-autoplaylist/abs_podcast_autoplaylist/__main__.py new file mode 100644 index 00000000..fd739805 --- /dev/null +++ b/overlays/abs-podcast-autoplaylist/abs_podcast_autoplaylist/__main__.py | |||
@@ -0,0 +1,107 @@ | |||
1 | import click | ||
2 | from pathlib import Path | ||
3 | import tomllib | ||
4 | import requests | ||
5 | from urllib.parse import urljoin | ||
6 | from operator import itemgetter | ||
7 | import re | ||
8 | from frozendict import frozendict | ||
9 | |||
10 | class BearerAuth(requests.auth.AuthBase): | ||
11 | def __init__(self, token): | ||
12 | self.token = token | ||
13 | def __call__(self, r): | ||
14 | r.headers["authorization"] = "Bearer " + self.token | ||
15 | return r | ||
16 | |||
17 | class ABSSession(requests.Session): | ||
18 | def __init__(self, config): | ||
19 | super().__init__() | ||
20 | self.base_url = config['instance'] | ||
21 | self.auth = BearerAuth(config['api_token']) | ||
22 | |||
23 | def request(self, method, url, *args, **kwargs): | ||
24 | joined_url = urljoin(self.base_url, url) | ||
25 | return super().request(method, joined_url, *args, **kwargs) | ||
26 | |||
27 | @click.command() | ||
28 | @click.argument('config_file', type=click.Path(dir_okay=False, path_type=Path)) | ||
29 | def main(config_file: Path): | ||
30 | with config_file.open('rb') as fh: | ||
31 | config = tomllib.load(fh) | ||
32 | |||
33 | with ABSSession(config) as s: | ||
34 | libraries = s.get('/api/libraries').json()['libraries'] | ||
35 | playlists = s.get('/api/playlists').json()['playlists'] | ||
36 | |||
37 | for library_config in config['libraries']: | ||
38 | [library] = filter(lambda l: l['name'] == library_config['name'], libraries) | ||
39 | filtered_playlists = list(filter(lambda p: p['name'] == library_config['playlist'] and p['libraryId'] == library['id'], playlists)) | ||
40 | def get_playlist(): | ||
41 | playlist = None | ||
42 | if filtered_playlists: | ||
43 | [playlist] = filtered_playlists | ||
44 | if not playlist: | ||
45 | playlist = s.post('/api/playlists', json={ | ||
46 | 'libraryId': library['id'], | ||
47 | 'name': library_config['playlist'], | ||
48 | }).json() | ||
49 | return playlist | ||
50 | |||
51 | podcasts = dict() | ||
52 | items = s.get('/api/libraries/{}/items'.format(library['id'])).json()['results'] | ||
53 | for item in items: | ||
54 | item = s.get('/api/items/{}'.format(item['id']), json={'expanded': True}).json() | ||
55 | episodes = list() | ||
56 | for episode in sorted(item['media']['episodes'], key = itemgetter('publishedAt')): | ||
57 | progress = s.get('/api/me/progress/{}/{}'.format(episode['libraryItemId'], episode['id'])) | ||
58 | if progress.ok and progress.json()["isFinished"]: | ||
59 | continue | ||
60 | episodes.append(episode) | ||
61 | podcasts[item['media']['metadata']['title']] = list(map(lambda x: frozendict({ 'libraryItemId': x['libraryItemId'], 'episodeId': x['id']}), episodes)) | ||
62 | def lookup_podcast(expr): | ||
63 | expr = re.compile(expr, flags=re.I) | ||
64 | matches = filter(lambda t: expr.search(t), podcasts.keys()) | ||
65 | match list(matches): | ||
66 | case [x]: | ||
67 | return (x,) | ||
68 | case _: | ||
69 | raise RuntimeError("No unique match for ‘{}’".format(expr)) | ||
70 | |||
71 | priorities = [ | ||
72 | [ | ||
73 | k | ||
74 | for item in (section if type(section) is list else [section]) | ||
75 | for k in lookup_podcast(item) | ||
76 | ] | ||
77 | for section in library_config['priorities'] | ||
78 | ] | ||
79 | |||
80 | playlist_items = list() | ||
81 | for section in priorities: | ||
82 | while any(map(lambda item: item in podcasts, section)): | ||
83 | for item in section: | ||
84 | if not item in podcasts: | ||
85 | continue | ||
86 | |||
87 | if not podcasts[item]: | ||
88 | del podcasts[item] | ||
89 | continue | ||
90 | |||
91 | playlist_items.append(podcasts[item].pop(0)) | ||
92 | |||
93 | playlist = get_playlist() | ||
94 | current_playlist_items = map(lambda item: frozendict({ k: v for k, v in item.items() if k in {'libraryItemId', 'episodeId'}}), playlist['items']) | ||
95 | |||
96 | if current_playlist_items == playlist_items: | ||
97 | continue | ||
98 | |||
99 | to_remove = set(current_playlist_items) - set(playlist_items) | ||
100 | if to_remove: | ||
101 | s.post('/api/playlists/{}/batch/remove'.format(playlist['id']), json={'items': list(to_remove)}).raise_for_status() | ||
102 | playlist = get_playlist() | ||
103 | to_add = set(playlist_items) - set(current_playlist_items) | ||
104 | if to_add: | ||
105 | s.post('/api/playlists/{}/batch/add'.format(playlist['id']), json={'items': list(to_add)}).raise_for_status() | ||
106 | |||
107 | r = s.patch('/api/playlists/{}'.format(playlist['id']), json={'items': playlist_items}).raise_for_status() | ||
diff --git a/overlays/abs-podcast-autoplaylist/default.nix b/overlays/abs-podcast-autoplaylist/default.nix new file mode 100644 index 00000000..075e0ba0 --- /dev/null +++ b/overlays/abs-podcast-autoplaylist/default.nix | |||
@@ -0,0 +1,28 @@ | |||
1 | { prev, final, flakeInputs, ... }: | ||
2 | |||
3 | with flakeInputs; | ||
4 | |||
5 | let | ||
6 | workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; | ||
7 | overlay = workspace.mkPyprojectOverlay { | ||
8 | sourcePreference = "wheel"; | ||
9 | }; | ||
10 | python = final.python312; | ||
11 | pythonSet = | ||
12 | (final.callPackage pyproject-nix.build.packages { | ||
13 | inherit python; | ||
14 | }).overrideScope | ||
15 | ( | ||
16 | prev.lib.composeManyExtensions [ | ||
17 | pyproject-build-systems.overlays.default | ||
18 | overlay | ||
19 | ] | ||
20 | ); | ||
21 | virtualEnv = pythonSet.mkVirtualEnv "abs-podcast-autoplaylist-env" workspace.deps.default; | ||
22 | in { | ||
23 | abs-podcast-autoplaylist = virtualEnv.overrideAttrs (oldAttrs: { | ||
24 | meta = (oldAttrs.meta or {}) // { | ||
25 | mainProgram = "abs-podcast-autoplaylist"; | ||
26 | }; | ||
27 | }); | ||
28 | } | ||
diff --git a/overlays/abs-podcast-autoplaylist/pyproject.toml b/overlays/abs-podcast-autoplaylist/pyproject.toml new file mode 100644 index 00000000..f52a84bc --- /dev/null +++ b/overlays/abs-podcast-autoplaylist/pyproject.toml | |||
@@ -0,0 +1,16 @@ | |||
1 | [project] | ||
2 | name = "abs-podcast-autoplaylist" | ||
3 | version = "0.1.0" | ||
4 | requires-python = ">=3.12" | ||
5 | dependencies = [ | ||
6 | "click>=8.1.8", | ||
7 | "frozendict>=2.4.6", | ||
8 | "requests>=2.32.3", | ||
9 | ] | ||
10 | |||
11 | [project.scripts] | ||
12 | abs-podcast-autoplaylist = "abs_podcast_autoplaylist.__main__:main" | ||
13 | |||
14 | [build-system] | ||
15 | requires = ["hatchling"] | ||
16 | build-backend = "hatchling.build" | ||
diff --git a/overlays/abs-podcast-autoplaylist/uv.lock b/overlays/abs-podcast-autoplaylist/uv.lock new file mode 100644 index 00000000..17de5f0e --- /dev/null +++ b/overlays/abs-podcast-autoplaylist/uv.lock | |||
@@ -0,0 +1,129 @@ | |||
1 | version = 1 | ||
2 | revision = 2 | ||
3 | requires-python = ">=3.12" | ||
4 | |||
5 | [[package]] | ||
6 | name = "abs-podcast-autoplaylist" | ||
7 | version = "0.1.0" | ||
8 | source = { editable = "." } | ||
9 | dependencies = [ | ||
10 | { name = "click" }, | ||
11 | { name = "frozendict" }, | ||
12 | { name = "requests" }, | ||
13 | ] | ||
14 | |||
15 | [package.metadata] | ||
16 | requires-dist = [ | ||
17 | { name = "click", specifier = ">=8.1.8" }, | ||
18 | { name = "frozendict", specifier = ">=2.4.6" }, | ||
19 | { name = "requests", specifier = ">=2.32.3" }, | ||
20 | ] | ||
21 | |||
22 | [[package]] | ||
23 | name = "certifi" | ||
24 | version = "2025.4.26" | ||
25 | source = { registry = "https://pypi.org/simple" } | ||
26 | sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload_time = "2025-04-26T02:12:29.51Z" } | ||
27 | wheels = [ | ||
28 | { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload_time = "2025-04-26T02:12:27.662Z" }, | ||
29 | ] | ||
30 | |||
31 | [[package]] | ||
32 | name = "charset-normalizer" | ||
33 | version = "3.4.2" | ||
34 | source = { registry = "https://pypi.org/simple" } | ||
35 | sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload_time = "2025-05-02T08:34:42.01Z" } | ||
36 | wheels = [ | ||
37 | { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload_time = "2025-05-02T08:32:33.712Z" }, | ||
38 | { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload_time = "2025-05-02T08:32:35.768Z" }, | ||
39 | { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload_time = "2025-05-02T08:32:37.284Z" }, | ||
40 | { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload_time = "2025-05-02T08:32:38.803Z" }, | ||
41 | { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload_time = "2025-05-02T08:32:40.251Z" }, | ||
42 | { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload_time = "2025-05-02T08:32:41.705Z" }, | ||
43 | { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload_time = "2025-05-02T08:32:43.709Z" }, | ||
44 | { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload_time = "2025-05-02T08:32:46.197Z" }, | ||
45 | { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload_time = "2025-05-02T08:32:48.105Z" }, | ||
46 | { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload_time = "2025-05-02T08:32:49.719Z" }, | ||
47 | { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload_time = "2025-05-02T08:32:51.404Z" }, | ||
48 | { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload_time = "2025-05-02T08:32:53.079Z" }, | ||
49 | { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload_time = "2025-05-02T08:32:54.573Z" }, | ||
50 | { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload_time = "2025-05-02T08:32:56.363Z" }, | ||
51 | { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload_time = "2025-05-02T08:32:58.551Z" }, | ||
52 | { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload_time = "2025-05-02T08:33:00.342Z" }, | ||
53 | { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload_time = "2025-05-02T08:33:02.081Z" }, | ||
54 | { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload_time = "2025-05-02T08:33:04.063Z" }, | ||
55 | { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload_time = "2025-05-02T08:33:06.418Z" }, | ||
56 | { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload_time = "2025-05-02T08:33:08.183Z" }, | ||
57 | { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload_time = "2025-05-02T08:33:09.986Z" }, | ||
58 | { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload_time = "2025-05-02T08:33:11.814Z" }, | ||
59 | { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload_time = "2025-05-02T08:33:13.707Z" }, | ||
60 | { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload_time = "2025-05-02T08:33:15.458Z" }, | ||
61 | { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload_time = "2025-05-02T08:33:17.06Z" }, | ||
62 | { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload_time = "2025-05-02T08:33:18.753Z" }, | ||
63 | { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload_time = "2025-05-02T08:34:40.053Z" }, | ||
64 | ] | ||
65 | |||
66 | [[package]] | ||
67 | name = "click" | ||
68 | version = "8.1.8" | ||
69 | source = { registry = "https://pypi.org/simple" } | ||
70 | dependencies = [ | ||
71 | { name = "colorama", marker = "sys_platform == 'win32'" }, | ||
72 | ] | ||
73 | sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload_time = "2024-12-21T18:38:44.339Z" } | ||
74 | wheels = [ | ||
75 | { url = "https://files.pythonhosted.org/packages/7e/d4/7ebdbd03970677812aac39c869717059dbb71a4cfc033ca6e5221787892c/click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2", size = 98188, upload_time = "2024-12-21T18:38:41.666Z" }, | ||
76 | ] | ||
77 | |||
78 | [[package]] | ||
79 | name = "colorama" | ||
80 | version = "0.4.6" | ||
81 | source = { registry = "https://pypi.org/simple" } | ||
82 | sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload_time = "2022-10-25T02:36:22.414Z" } | ||
83 | wheels = [ | ||
84 | { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload_time = "2022-10-25T02:36:20.889Z" }, | ||
85 | ] | ||
86 | |||
87 | [[package]] | ||
88 | name = "frozendict" | ||
89 | version = "2.4.6" | ||
90 | source = { registry = "https://pypi.org/simple" } | ||
91 | sdist = { url = "https://files.pythonhosted.org/packages/bb/59/19eb300ba28e7547538bdf603f1c6c34793240a90e1a7b61b65d8517e35e/frozendict-2.4.6.tar.gz", hash = "sha256:df7cd16470fbd26fc4969a208efadc46319334eb97def1ddf48919b351192b8e", size = 316416, upload_time = "2024-10-13T12:15:32.449Z" } | ||
92 | wheels = [ | ||
93 | { url = "https://files.pythonhosted.org/packages/04/13/d9839089b900fa7b479cce495d62110cddc4bd5630a04d8469916c0e79c5/frozendict-2.4.6-py311-none-any.whl", hash = "sha256:d065db6a44db2e2375c23eac816f1a022feb2fa98cbb50df44a9e83700accbea", size = 16148, upload_time = "2024-10-13T12:15:26.839Z" }, | ||
94 | { url = "https://files.pythonhosted.org/packages/ba/d0/d482c39cee2ab2978a892558cf130681d4574ea208e162da8958b31e9250/frozendict-2.4.6-py312-none-any.whl", hash = "sha256:49344abe90fb75f0f9fdefe6d4ef6d4894e640fadab71f11009d52ad97f370b9", size = 16146, upload_time = "2024-10-13T12:15:28.16Z" }, | ||
95 | { url = "https://files.pythonhosted.org/packages/a5/8e/b6bf6a0de482d7d7d7a2aaac8fdc4a4d0bb24a809f5ddd422aa7060eb3d2/frozendict-2.4.6-py313-none-any.whl", hash = "sha256:7134a2bb95d4a16556bb5f2b9736dceb6ea848fa5b6f3f6c2d6dba93b44b4757", size = 16146, upload_time = "2024-10-13T12:15:29.495Z" }, | ||
96 | ] | ||
97 | |||
98 | [[package]] | ||
99 | name = "idna" | ||
100 | version = "3.10" | ||
101 | source = { registry = "https://pypi.org/simple" } | ||
102 | sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload_time = "2024-09-15T18:07:39.745Z" } | ||
103 | wheels = [ | ||
104 | { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload_time = "2024-09-15T18:07:37.964Z" }, | ||
105 | ] | ||
106 | |||
107 | [[package]] | ||
108 | name = "requests" | ||
109 | version = "2.32.3" | ||
110 | source = { registry = "https://pypi.org/simple" } | ||
111 | dependencies = [ | ||
112 | { name = "certifi" }, | ||
113 | { name = "charset-normalizer" }, | ||
114 | { name = "idna" }, | ||
115 | { name = "urllib3" }, | ||
116 | ] | ||
117 | sdist = { url = "https://files.pythonhosted.org/packages/63/70/2bf7780ad2d390a8d301ad0b550f1581eadbd9a20f896afe06353c2a2913/requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760", size = 131218, upload_time = "2024-05-29T15:37:49.536Z" } | ||
118 | wheels = [ | ||
119 | { url = "https://files.pythonhosted.org/packages/f9/9b/335f9764261e915ed497fcdeb11df5dfd6f7bf257d4a6a2a686d80da4d54/requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6", size = 64928, upload_time = "2024-05-29T15:37:47.027Z" }, | ||
120 | ] | ||
121 | |||
122 | [[package]] | ||
123 | name = "urllib3" | ||
124 | version = "2.4.0" | ||
125 | source = { registry = "https://pypi.org/simple" } | ||
126 | sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload_time = "2025-04-10T15:23:39.232Z" } | ||
127 | wheels = [ | ||
128 | { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload_time = "2025-04-10T15:23:37.377Z" }, | ||
129 | ] | ||
@@ -14,6 +14,6 @@ in pkgs.mkShell { | |||
14 | yq | 14 | yq |
15 | nvfetcher.packages.${system}.default | 15 | nvfetcher.packages.${system}.default |
16 | ca-util.packages.${system}.ca | 16 | ca-util.packages.${system}.ca |
17 | poetry | 17 | poetry uv |
18 | ]); | 18 | ]); |
19 | } | 19 | } |