ffmpeg-update 3.0.2__tar.gz → 3.1.1__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.
@@ -1,11 +1,12 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ffmpeg-update
3
- Version: 3.0.2
3
+ Version: 3.1.1
4
4
  Summary: Package manager for FFmpeg, FFprobe, and FFplay static binaries
5
5
  Keywords: updater,installer,downloader,program,executable,binary,command,line,cli,tool
6
6
  Author: Asadullah Shaikh
7
7
  Classifier: Development Status :: 5 - Production/Stable
8
8
  Classifier: Environment :: Console
9
+ Classifier: Framework :: AsyncIO
9
10
  Classifier: Intended Audience :: Developers
10
11
  Classifier: Intended Audience :: End Users/Desktop
11
12
  Classifier: Intended Audience :: System Administrators
@@ -38,6 +39,7 @@ FFmpeg-update is a package manager for the FFmpeg suite, available as both a CLI
38
39
  - Configure custom installation location
39
40
  - Update to latest version
40
41
  - Check for updates
42
+ - Concurrent downloads
41
43
  - Uninstall from system
42
44
  - Progress bar with ETA
43
45
  - Smart permission handling
@@ -102,8 +104,8 @@ Alternatively, can be invoked as a module with `python -m ffmpeg_update <COMMAND
102
104
 
103
105
  ## Functions
104
106
 
105
- - `update(bins = {"ffmpeg"}, /, *, dry_run = False, dir, tempdir, progress, client) -> None`
106
- - `install(bins = {"ffmpeg"}, /, *, dir, tempdir, progress, client) -> None`
107
+ - async `update(bins = {"ffmpeg"}, /, *, dry_run = False, dir, tempdir, progress, client) -> None`
108
+ - async `install(bins = {"ffmpeg"}, /, *, dir, tempdir, progress, client) -> None`
107
109
  - `uninstall(bins = {"ffmpeg"}, /, *, dir) -> None`
108
110
  - `get_arch() -> Literal["amd64", "arm64"]`
109
111
  - `get_os() -> Literal["linux", "macos"]`
@@ -120,7 +122,7 @@ Alternatively, can be invoked as a module with `python -m ffmpeg_update <COMMAND
120
122
  >
121
123
  > - `progress`: A `rich.progress.Progress` used to show progress bars in the terminal
122
124
  >
123
- > - `client`: A `niquests.Session` used to make HTTP requests
125
+ > - `client`: A `niquests.AsyncSession` used to make HTTP requests
124
126
  > - Must set parameter `base_url` to `f"https://ffmpeg.martin-riedl.de/redirect/latest/{os}/{arch}/{build}/"`
125
127
  > - `build`: `"release"`, `"snapshot"`
126
128
  > - `arch`: `"amd64"`, `"arm64"`
@@ -10,6 +10,7 @@ FFmpeg-update is a package manager for the FFmpeg suite, available as both a CLI
10
10
  - Configure custom installation location
11
11
  - Update to latest version
12
12
  - Check for updates
13
+ - Concurrent downloads
13
14
  - Uninstall from system
14
15
  - Progress bar with ETA
15
16
  - Smart permission handling
@@ -74,8 +75,8 @@ Alternatively, can be invoked as a module with `python -m ffmpeg_update <COMMAND
74
75
 
75
76
  ## Functions
76
77
 
77
- - `update(bins = {"ffmpeg"}, /, *, dry_run = False, dir, tempdir, progress, client) -> None`
78
- - `install(bins = {"ffmpeg"}, /, *, dir, tempdir, progress, client) -> None`
78
+ - async `update(bins = {"ffmpeg"}, /, *, dry_run = False, dir, tempdir, progress, client) -> None`
79
+ - async `install(bins = {"ffmpeg"}, /, *, dir, tempdir, progress, client) -> None`
79
80
  - `uninstall(bins = {"ffmpeg"}, /, *, dir) -> None`
80
81
  - `get_arch() -> Literal["amd64", "arm64"]`
81
82
  - `get_os() -> Literal["linux", "macos"]`
@@ -92,7 +93,7 @@ Alternatively, can be invoked as a module with `python -m ffmpeg_update <COMMAND
92
93
  >
93
94
  > - `progress`: A `rich.progress.Progress` used to show progress bars in the terminal
94
95
  >
95
- > - `client`: A `niquests.Session` used to make HTTP requests
96
+ > - `client`: A `niquests.AsyncSession` used to make HTTP requests
96
97
  > - Must set parameter `base_url` to `f"https://ffmpeg.martin-riedl.de/redirect/latest/{os}/{arch}/{build}/"`
97
98
  > - `build`: `"release"`, `"snapshot"`
98
99
  > - `arch`: `"amd64"`, `"arm64"`
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "ffmpeg-update"
3
- version = "3.0.2"
3
+ version = "3.1.1"
4
4
  description = "Package manager for FFmpeg, FFprobe, and FFplay static binaries"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -11,6 +11,7 @@ keywords = ["updater", "installer", "downloader", "program", "executable", "bina
11
11
  classifiers = [
12
12
  "Development Status :: 5 - Production/Stable",
13
13
  "Environment :: Console",
14
+ "Framework :: AsyncIO",
14
15
  "Intended Audience :: Developers",
15
16
  "Intended Audience :: End Users/Desktop",
16
17
  "Intended Audience :: System Administrators",
@@ -1,3 +1,4 @@
1
+ import asyncio
1
2
  import io
2
3
  import platform
3
4
  import re
@@ -11,7 +12,7 @@ from typing import Annotated, Literal
11
12
 
12
13
  from cyclopts import App, Parameter
13
14
  from cyclopts.types import ResolvedExistingDirectory
14
- from niquests import Session
15
+ from niquests import AsyncSession
15
16
  from rich import print
16
17
  from rich.progress import Progress
17
18
 
@@ -29,7 +30,7 @@ app.register_install_completion_command(add_to_startup=False)
29
30
 
30
31
 
31
32
  @app.meta.default
32
- def ffup(
33
+ async def ffup(
33
34
  *tokens: Annotated[str, Parameter(show=False, allow_leading_hyphen=True)],
34
35
  dir: Annotated[
35
36
  ResolvedExistingDirectory, Parameter(env_var=("FFUP_DIR", "XDG_BIN_HOME"))
@@ -54,15 +55,15 @@ def ffup(
54
55
  arch = get_arch() if arch is None else arch
55
56
  os = get_os() if os is None else os
56
57
 
57
- additional_kwargs["client"] = Session(
58
+ additional_kwargs["client"] = AsyncSession(
58
59
  base_url=f"https://ffmpeg.martin-riedl.de/redirect/latest/{os}/{arch}/{build}/"
59
60
  )
60
61
 
61
- return command(*bound.args, **bound.kwargs, **additional_kwargs)
62
+ return await command(*bound.args, **bound.kwargs, **additional_kwargs)
62
63
 
63
64
 
64
65
  @app.command
65
- def update(
66
+ async def update(
66
67
  bins: set[BinType] = {"ffmpeg"},
67
68
  /,
68
69
  *,
@@ -70,53 +71,55 @@ def update(
70
71
  dir: Annotated[ResolvedExistingDirectory, Parameter(parse=False)],
71
72
  tempdir: Annotated[TemporaryDirectory[str], Parameter(parse=False)],
72
73
  progress: Annotated[Progress, Parameter(parse=False)],
73
- client: Annotated[Session, Parameter(parse=False)],
74
+ client: Annotated[AsyncSession, Parameter(parse=False)],
74
75
  ) -> None:
75
76
  with progress:
76
- for bin in bins:
77
- path = dir / bin
78
- current = _current(path)
79
- latest = _latest(bin, client)
77
+ for bin in bins.copy():
78
+ current = _current(dir / bin)
79
+ latest = await _latest(bin, client)
80
80
  print(f"{_fmt_FF(bin)}:\n\tCurrent: {current}\n\tLatest: {latest}")
81
81
  if current != latest:
82
82
  print(f"{_fmt_FF(bin)}: update available")
83
- if not dry_run:
84
- file = _download(bin, tempdir, progress, client)
85
- _install(file, path)
86
- print("Updated:", path)
87
83
  else:
84
+ bins.remove(bin)
88
85
  print(f"{_fmt_FF(bin)}: up to date")
89
86
 
87
+ if not dry_run and bins:
88
+ await install(
89
+ bins, dir=dir, tempdir=tempdir, progress=progress, client=client
90
+ )
91
+
90
92
 
91
93
  @app.command
92
- def check(
94
+ async def check(
93
95
  bins: set[BinType] = {"ffmpeg"},
94
96
  /,
95
97
  *,
96
98
  dir: Annotated[ResolvedExistingDirectory, Parameter(parse=False)],
97
99
  tempdir: Annotated[TemporaryDirectory[str], Parameter(parse=False)],
98
100
  progress: Annotated[Progress, Parameter(parse=False)],
99
- client: Annotated[Session, Parameter(parse=False)],
101
+ client: Annotated[AsyncSession, Parameter(parse=False)],
100
102
  ):
101
- update(
103
+ await update(
102
104
  bins, dry_run=True, dir=dir, tempdir=tempdir, progress=progress, client=client
103
105
  )
104
106
 
105
107
 
106
108
  @app.command
107
- def install(
109
+ async def install(
108
110
  bins: set[BinType] = {"ffmpeg"},
109
111
  /,
110
112
  *,
111
113
  dir: Annotated[ResolvedExistingDirectory, Parameter(parse=False)],
112
114
  tempdir: Annotated[TemporaryDirectory[str], Parameter(parse=False)],
113
115
  progress: Annotated[Progress, Parameter(parse=False)],
114
- client: Annotated[Session, Parameter(parse=False)],
116
+ client: Annotated[AsyncSession, Parameter(parse=False)],
115
117
  ) -> None:
116
118
  with progress:
117
- for bin in bins:
118
- path = dir / bin
119
- file = _download(bin, tempdir, progress, client)
119
+ for file in await asyncio.gather(
120
+ *[_download(bin, tempdir, progress, client) for bin in bins]
121
+ ):
122
+ path = dir / file.name
120
123
  _install(file, path)
121
124
  print("Installed:", path)
122
125
 
@@ -164,24 +167,21 @@ def _current(path):
164
167
  return match.group(1)
165
168
 
166
169
 
167
- def _latest(bin, client):
168
- response = client.get(f"{bin}.zip", allow_redirects=False)
170
+ async def _latest(bin, client):
171
+ response = await client.get(f"{bin}.zip", allow_redirects=False, stream=True)
169
172
  response.raise_for_status()
170
- if response.status_code == 307:
171
- match = re.search(r"_(N-\d+-\w+|\d\.\d(\.\d)?)", response.headers["location"])
172
- if match is None:
173
- raise ValueError("failed to parse version from HTTP response")
174
- return match.group(1)
175
- else:
176
- raise ValueError(f"unexpected {response}")
173
+ match = re.search(r"_(N-\d+-\w+|\d\.\d(\.\d)?)", response.headers["location"])
174
+ if match is None:
175
+ raise ValueError("failed to parse version from HTTP response")
176
+ return match.group(1)
177
177
 
178
178
 
179
- def _download(bin, tempdir, progress, client):
180
- response = client.get(f"{bin}.zip", stream=True)
179
+ async def _download(bin, tempdir, progress, client):
180
+ response = await client.get(f"{bin}.zip", stream=True)
181
181
  response.raise_for_status()
182
182
  id = progress.add_task(_fmt_FF(bin), total=int(response.headers["content-length"]))
183
183
  with io.BytesIO() as buf:
184
- for chunk in response.iter_content():
184
+ async for chunk in await response.iter_content():
185
185
  chunk_size = buf.write(chunk)
186
186
  progress.update(id, advance=chunk_size)
187
187
  progress.update(id, visible=False)