Skip to content

Commit a1342e6

Browse files
committed
added os-specific download & install functions
1 parent cfe7ebc commit a1342e6

File tree

11 files changed

+240
-168
lines changed

11 files changed

+240
-168
lines changed

.github/workflows/test_n_pub.yml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,11 +46,9 @@ jobs:
4646

4747
- name: Setup Python dependencies
4848
run: |
49-
python -m pip install -U pip
50-
pip install -U build pytest pytest-github-actions-annotate-failures
51-
pip install -U numpy
49+
python -m pip install -U pip pytest pytest-github-actions-annotate-failures
5250
53-
- name: Install ffmpegio_downloader package
51+
- name: Install ffmpeg_downloader package
5452
run: pip install -q .
5553

5654
- name: Run tests

pyproject.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
11
[build-system]
22
requires = ["setuptools >= 40.9.0", "wheel"]
33
build-backend = "setuptools.build_meta"
4+
5+
[tool.pytest.ini_options]
6+
testpaths = ["tests"]
File renamed without changes.
File renamed without changes.

src/ffmpeg_downloader/__init__.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,10 @@
1-
__version__ = '0.0.0'
1+
__version__ = "0.0.0"
2+
3+
import sys
4+
5+
if sys.platform in ("win32", "cygwin"):
6+
from ._win32 import download_n_install, get_version
7+
elif sys.platform == "darwin":
8+
from ._macos import download_n_install, get_version
9+
else:
10+
from ._linux import download_n_install, get_version
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
from urllib import request
2+
from contextlib import contextmanager
3+
import os, stat
4+
5+
6+
@contextmanager
7+
def download_base(url, content_type, ctx=None):
8+
with request.urlopen(url, timeout=1.0, context=ctx) as response:
9+
# pprint(response.headers.get_content_type())
10+
if response.headers.get_content_type() != content_type:
11+
raise RuntimeError(f'"{url}" is not the expected content type.')
12+
try:
13+
nbytes = int(response.getheader("content-length"))
14+
except:
15+
nbytes = 0
16+
yield response, nbytes
17+
18+
19+
def download_info(url, content_type, ctx=None):
20+
with download_base(url, content_type, ctx) as (response, nbytes):
21+
info = response.read().decode("utf-8")
22+
return info
23+
24+
25+
def download_file(outfile, url, content_type, ctx=None, progress=None):
26+
27+
if progress:
28+
progress(0, 1)
29+
30+
with download_base(url, content_type, ctx) as (response, nbytes):
31+
32+
blksz = nbytes // 32 or 1024 * 1024
33+
with open(outfile, "wb") as f:
34+
nread = 0
35+
while True:
36+
b = response.read(blksz)
37+
if not b:
38+
break
39+
f.write(b)
40+
nread += len(b)
41+
if progress:
42+
progress(nread, nbytes)
43+
44+
return outfile
45+
46+
47+
def chmod(binfile):
48+
# Set bits for execution and read for all users.
49+
exe_bits = stat.S_IXOTH | stat.S_IXUSR | stat.S_IXGRP
50+
read_bits = stat.S_IRUSR | stat.S_IRGRP | stat.S_IXGRP
51+
write_bits = stat.S_IWUSR | stat.S_IWGRP | stat.S_IWGRP
52+
os.chmod(binfile, exe_bits | read_bits | write_bits)

src/ffmpeg_downloader/_linux.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
from tempfile import TemporaryDirectory
2+
from ._download_helper import download_info, download_file, chmod
3+
import re, ssl, tarfile, os, shutil
4+
from os import path
5+
6+
ctx = ssl.create_default_context()
7+
ctx.check_hostname = False
8+
ctx.verify_mode = ssl.CERT_NONE
9+
10+
11+
def get_version():
12+
13+
return re.search(
14+
r"version: (\d+\.\d+(?:\.\d+)?)",
15+
download_info(
16+
"https://johnvansickle.com/ffmpeg/release-readme.txt",
17+
"text/plain",
18+
ctx,
19+
),
20+
)[1]
21+
22+
23+
def download_n_install(install_dir, progress=None, arch=None):
24+
archs = ("amd64", "i686", "arm64", "armhf", "armel")
25+
if arch is None:
26+
arch = archs[0]
27+
elif arch not in archs:
28+
raise ValueError(f"Invalid arch specified. Must be one of {arch}")
29+
30+
with TemporaryDirectory() as tmpdir:
31+
tarpath = path.join(tmpdir, "ffmpeg_linux.tar.xz")
32+
url = f"https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-{arch}-static.tar.xz"
33+
34+
with TemporaryDirectory() as tmpdir:
35+
download_file(tarpath, url, "application/x-xz", ctx, progress=progress)
36+
37+
with tarfile.open(tarpath, "r") as f:
38+
f.extractall(tmpdir)
39+
40+
_, (src_dir_name, *_), _ = next(os.walk(tmpdir))
41+
src_dir_path = path.join(tmpdir, src_dir_name)
42+
43+
with open(path.join(src_dir_path, "VERSION"), "wt") as f:
44+
f.write(get_version())
45+
46+
try:
47+
shutil.rmtree(install_dir)
48+
except:
49+
pass
50+
51+
shutil.move(src_dir_path, install_dir)
52+
53+
ffmpegpath = path.join(install_dir, "ffmpeg")
54+
ffprobepath = path.join(install_dir, "ffprobe")
55+
chmod(ffmpegpath)
56+
chmod(ffprobepath)
57+
58+
return ffmpegpath, ffprobepath

src/ffmpeg_downloader/_macos.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
from tempfile import TemporaryDirectory
2+
from os import path
3+
import json, os, zipfile
4+
from ._download_helper import download_info, download_file, chmod
5+
6+
7+
def get_version():
8+
return json.loads(
9+
download_info(
10+
"https://evermeet.cx/ffmpeg/info/ffmpeg/release", "application/json"
11+
)
12+
)["version"]
13+
14+
15+
def download_n_install(install_dir, progress=None):
16+
17+
with TemporaryDirectory() as tmpdir:
18+
zipffmpegpath = path.join(tmpdir, "ffmpeg_macos.zip")
19+
download_file(
20+
zipffmpegpath,
21+
"https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip",
22+
"application/zip",
23+
progress=progress,
24+
)
25+
zipffprobepath = path.join(tmpdir, "ffprobe_macos.zip")
26+
download_file(
27+
zipffprobepath,
28+
"https://evermeet.cx/ffmpeg/getrelease/ffprobe/zip",
29+
"application/zip",
30+
progress=progress,
31+
)
32+
33+
with zipfile.ZipFile(zipffmpegpath, "r") as f:
34+
f.extractall(tmpdir)
35+
with zipfile.ZipFile(zipffprobepath, "r") as f:
36+
f.extractall(tmpdir)
37+
38+
dst_ffmpeg = path.join(install_dir, "ffmpeg")
39+
try:
40+
os.remove(dst_ffmpeg)
41+
except:
42+
pass
43+
os.rename(path.join(tmpdir, "ffmpeg"), dst_ffmpeg)
44+
chmod(dst_ffmpeg)
45+
46+
dst_ffprobe = path.join(install_dir, "ffprobe")
47+
try:
48+
os.remove(dst_ffprobe)
49+
except:
50+
pass
51+
os.rename(path.join(tmpdir, "ffprobe"), dst_ffprobe)
52+
chmod(dst_ffprobe)
53+
54+
with open(path.join(install_dir, "VERSION"), "wt") as f:
55+
f.write(get_version())
56+
57+
return dst_ffmpeg, dst_ffprobe

src/ffmpeg_downloader/_win32.py

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import os
2+
import shutil
3+
from ._download_helper import download_info, download_file
4+
from tempfile import TemporaryDirectory
5+
from os import path
6+
import zipfile
7+
8+
9+
def get_version():
10+
return download_info(
11+
"https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip.ver",
12+
"text/plain",
13+
)
14+
15+
16+
def download_n_install(install_dir, progress=None, build_type=None):
17+
18+
build_types = ("essentials", "full", "full-shared")
19+
if build_type is None:
20+
build_type = build_types[0]
21+
elif build_type not in build_types:
22+
raise ValueError(f"Invalid build_type specified. Must be one of {build_types}")
23+
24+
with TemporaryDirectory() as tmpdir:
25+
zippath = path.join(tmpdir, "ffmpeg_win32.zip")
26+
url = f"https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-{build_type}.zip"
27+
download_file(zippath, url, "application/zip", progress=progress)
28+
29+
with zipfile.ZipFile(zippath, "r") as f:
30+
f.extractall(tmpdir)
31+
32+
_, (src_dir_name, *_), _ = next(os.walk(tmpdir))
33+
src_dir_path = path.join(tmpdir, src_dir_name)
34+
35+
with open(path.join(src_dir_path, "VERSION"), "wt") as f:
36+
f.write(get_version())
37+
38+
try:
39+
shutil.rmtree(install_dir)
40+
except:
41+
pass
42+
43+
shutil.move(src_dir_path, install_dir)
44+
45+
return path.join(install_dir, "bin", "ffmpeg"), path.join(
46+
install_dir, "bin", "ffprobe"
47+
)

tests/test_decompress.py

Lines changed: 0 additions & 26 deletions
This file was deleted.

0 commit comments

Comments
 (0)