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.
- {ffmpeg_update-3.0.2 → ffmpeg_update-3.1.1}/PKG-INFO +6 -4
- {ffmpeg_update-3.0.2 → ffmpeg_update-3.1.1}/README.md +4 -3
- {ffmpeg_update-3.0.2 → ffmpeg_update-3.1.1}/pyproject.toml +2 -1
- {ffmpeg_update-3.0.2 → ffmpeg_update-3.1.1}/src/ffmpeg_update/__init__.py +34 -34
- {ffmpeg_update-3.0.2 → ffmpeg_update-3.1.1}/src/ffmpeg_update/__main__.py +0 -0
- {ffmpeg_update-3.0.2 → ffmpeg_update-3.1.1}/src/ffmpeg_update/py.typed +0 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: ffmpeg-update
|
|
3
|
-
Version: 3.
|
|
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.
|
|
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.
|
|
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.
|
|
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
|
|
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"] =
|
|
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[
|
|
74
|
+
client: Annotated[AsyncSession, Parameter(parse=False)],
|
|
74
75
|
) -> None:
|
|
75
76
|
with progress:
|
|
76
|
-
for bin in bins:
|
|
77
|
-
|
|
78
|
-
|
|
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[
|
|
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[
|
|
116
|
+
client: Annotated[AsyncSession, Parameter(parse=False)],
|
|
115
117
|
) -> None:
|
|
116
118
|
with progress:
|
|
117
|
-
for
|
|
118
|
-
|
|
119
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
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)
|
|
File without changes
|
|
File without changes
|