Skip to content

Commit cfe7ebc

Browse files
committed
tested dowload and decompress
1 parent 94bbcc4 commit cfe7ebc

File tree

8 files changed

+227
-107
lines changed

8 files changed

+227
-107
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -154,4 +154,4 @@ docs/
154154
tests/*.7z
155155
tests/*.tar.xz
156156
tests/*/
157-
tests/7z
157+
tests/*.zip

.vscode/launch.json

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
{
2+
// Use IntelliSense to learn about possible attributes.
3+
// Hover to view descriptions of existing attributes.
4+
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5+
"version": "0.2.0",
6+
"configurations": [
7+
{
8+
"name": "Python: Current File",
9+
"type": "python",
10+
"request": "launch",
11+
"program": "${file}",
12+
"console": "integratedTerminal",
13+
"justMyCode": false
14+
}
15+
]
16+
}

CHANGELOG.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Changelog
2+
All notable changes to this project will be documented in this file.
3+
4+
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
5+
6+
## [Unreleased]
7+
8+
- First beta release.
9+
10+
[Unreleased]: https://github.com/python-ffmpegio/python-ffmpegio/compare/94bbcc4...HEAD

README.rst

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
`ffmpeg-downloader`: Python FFmpeg binary downloader
2+
===================================================
3+
4+
|pypi| |pypi-status| |pypi-pyvers| |github-license| |github-status|
5+
6+
.. |pypi| image:: https://img.shields.io/pypi/v/ffmpeg-downloader
7+
:alt: PyPI
8+
.. |pypi-status| image:: https://img.shields.io/pypi/status/ffmpeg-downloader
9+
:alt: PyPI - Status
10+
.. |pypi-pyvers| image:: https://img.shields.io/pypi/pyversions/ffmpeg-downloader
11+
:alt: PyPI - Python Version
12+
.. |github-license| image:: https://img.shields.io/github/license/python-ffmpegio/python-ffmpeg-downloader
13+
:alt: GitHub License
14+
.. |github-status| image:: https://img.shields.io/github/workflow/status/python-ffmpegio/python-ffmpeg-downloader/Run%20Tests
15+
:alt: GitHub Workflow Status
16+
17+
Python `ffmpeg-downloader` package automatically downloads FFmpeg binaries for Windows, Linux, & MacOS. Note
18+
while it supports Linux and MacOS, it is intended for Windows users, for whom there is no installer is currently
19+
available. Linux and MacOS users should install via OS package manager (e.g., `apt-get` for Ubuntu and `brew` for MacOS).
20+
21+
Install `ffmpeg-downloader` package via ``pip``:
22+
23+
.. code-block:: bash
24+
25+
pip install ffmpeg-downloader
26+
27+
Console Command
28+
---------------
29+
30+
*
31+
32+
In-Python Use
33+
-------------
34+
35+
*

tests/requirements.txt

Lines changed: 0 additions & 1 deletion
This file was deleted.

tests/test_appdirs.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import appdirs
2+
3+
# get current version
4+
# get current paths (ffmpeg/ffprobe)
5+
# delete current version
6+
# copy
7+
8+
app = "ffmpeg-downloader", "python-ffmpegio"
9+
10+
print(appdirs.user_data_dir(*app))

tests/test_decompress.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
from os import path
2+
from posixpath import relpath
3+
import sys
4+
from urllib import request, parse
5+
import shutil
6+
from glob import glob
7+
import re
8+
from os import path
9+
from contextlib import contextmanager
10+
11+
12+
import ssl
13+
from pprint import pprint
14+
15+
import tarfile, zipfile
16+
17+
download_dir = "tests"
18+
19+
with zipfile.ZipFile(path.join(download_dir,'ffmpeg_win32.zip'),'r') as f:
20+
f.extractall(download_dir)
21+
with zipfile.ZipFile(path.join(download_dir,'ffmpeg_macos.zip'),'r') as f:
22+
f.extractall(download_dir)
23+
with zipfile.ZipFile(path.join(download_dir,'ffprobe_macos.zip'),'r') as f:
24+
f.extractall(download_dir)
25+
with tarfile.open(path.join(download_dir,'ffmpeg_linux.tar.xz'),'r') as f:
26+
f.extractall(download_dir)

tests/test_downloader.py

Lines changed: 129 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,117 +1,141 @@
11
from os import path
2-
from posixpath import relpath
3-
import sys
4-
from urllib import request, parse
5-
import shutil
6-
from glob import glob
2+
from urllib import request
73
import re
84
from os import path
5+
from contextlib import contextmanager
6+
import ssl
7+
import json
98

9+
# download binary
10+
# download version info
1011

11-
import ssl
12+
ctx = ssl.create_default_context()
13+
ctx.check_hostname = False
14+
ctx.verify_mode = ssl.CERT_NONE
1215

13-
sources = {
14-
"win32": {
15-
"url": "https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-{build_type}.7z",
16-
"build_type": ("essentials", "full", "full-shared"),
17-
"content_type": "application/x-7z-compressed",
18-
},
19-
"darwin": {
20-
"url": "https://evermeet.cx/ffmpeg/getrelease/{app_name}/7z",
21-
"app_name": ("ffmpeg", "ffprobe"),
22-
"content_type": "application/x-7z-compressed",
23-
"download_all": True,
24-
},
25-
"linux": {
26-
"url": "https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-{arch}-static.tar.xz",
27-
"arch": ("amd64", "i686", "arm64", "armhf", "armel"),
28-
"content_type": "application/x-xz",
29-
"need_ctx": True,
30-
},
31-
}
32-
33-
34-
def download(dstpath, platform=sys.platform, **opts):
35-
src = sources[platform]
36-
37-
if src.get("need_ctx", False):
38-
ctx = ssl.create_default_context()
39-
ctx.check_hostname = False
40-
ctx.verify_mode = ssl.CERT_NONE
41-
else:
42-
ctx = None
43-
44-
url = src["url"]
45-
m = re.search(r"\{(.+?)\}", url)
46-
while m:
47-
key = m[1]
48-
val = opts.pop(key, src[key][0])
49-
if val not in src[key]:
50-
raise ValueError(f"Unknown value ({val}) specified for {key}.")
51-
url = url[: m.start()] + val + url[m.end() :]
52-
m = re.search(r"\{(.+?)\}", url)
53-
54-
zippath = path.join(dstpath, path.basename(url))
55-
if not path.exists(zippath):
56-
with request.urlopen(url, context=ctx) as response:
57-
# pprint(response.headers.__dict__)
58-
if response.headers.get_content_type() != src["content_type"]:
59-
raise RuntimeError(f'"{url}" is not the expected content type.')
60-
try:
61-
nbytes = int(response.getheader("content-length"))
62-
except:
63-
nbytes = 0
64-
blksz = nbytes // 32 or 1024 * 1024
65-
with open(zippath, "wb") as f:
66-
nread = 0
67-
while True:
68-
b = response.read(blksz)
69-
if not b:
70-
break
71-
f.write(b)
72-
nread += len(b)
73-
print(f"downloaded: {nread}/{nbytes} bytes")
16+
@contextmanager
17+
def download_base(url, content_type, ctx=None):
18+
with request.urlopen(url, timeout=1.0, context=ctx) as response:
19+
# pprint(response.headers.get_content_type())
20+
if response.headers.get_content_type() != content_type:
21+
raise RuntimeError(f'"{url}" is not the expected content type.')
22+
try:
23+
nbytes = int(response.getheader("content-length"))
24+
except:
25+
nbytes = 0
26+
yield response, nbytes
27+
28+
29+
def download_info(url, content_type, ctx=None):
30+
with download_base(url, content_type, ctx) as (response, nbytes):
31+
info = response.read().decode("utf-8")
32+
return info
33+
34+
35+
def get_version_win32():
36+
return download_info(
37+
"https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-essentials.zip.ver",
38+
"text/plain",
39+
)
40+
41+
42+
43+
44+
def get_version_macos():
45+
return json.loads(
46+
download_info(
47+
"https://evermeet.cx/ffmpeg/info/ffmpeg/release", "application/json"
48+
)
49+
)["version"]
50+
51+
52+
def get_version_linux():
53+
54+
return re.search(
55+
r"version: (\d+\.\d+(?:\.\d+)?)",
56+
download_info(
57+
"https://johnvansickle.com/ffmpeg/release-readme.txt",
58+
"text/plain",
59+
ctx,
60+
),
61+
)[1]
62+
63+
64+
def download_file(outfile, url, content_type, ctx=None, progress=None):
65+
66+
if progress:
67+
progress(0, 1)
68+
69+
with download_base(url, content_type, ctx) as (response, nbytes):
70+
71+
blksz = nbytes // 32 or 1024 * 1024
72+
with open(outfile, "wb") as f:
73+
nread = 0
74+
while True:
75+
b = response.read(blksz)
76+
if not b:
77+
break
78+
f.write(b)
79+
nread += len(b)
80+
if progress:
81+
progress(nread, nbytes)
82+
83+
return outfile
84+
85+
86+
# if sys.platform == 'win32':
87+
# def
88+
89+
90+
def download_win32(download_dir, build_type=None, progress=None):
91+
build_types = ("essentials", "full", "full-shared")
92+
if build_type is None:
93+
build_type = build_types[0]
94+
elif build_type not in build_types:
95+
raise ValueError(f"Invalid build_type specified. Must be one of {build_types}")
96+
97+
zippath = path.join(download_dir, "ffmpeg_win32.zip")
98+
url = f"https://www.gyan.dev/ffmpeg/builds/ffmpeg-release-{build_type}.zip"
99+
download_file(zippath, url, "application/zip", progress=progress)
100+
return (zippath,)
101+
102+
103+
def download_macos(download_dir, progress=None):
104+
zipffmpegpath = path.join(download_dir, "ffmpeg_macos.zip")
105+
download_file(
106+
zipffmpegpath,
107+
"https://evermeet.cx/ffmpeg/getrelease/ffmpeg/zip",
108+
"application/zip",
109+
progress=progress,
110+
)
111+
zipffprobepath = path.join(download_dir, "ffprobe_macos.zip")
112+
download_file(
113+
zipffprobepath,
114+
"https://evermeet.cx/ffmpeg/getrelease/ffprobe/zip",
115+
"application/zip",
116+
progress=progress,
117+
)
118+
return zipffmpegpath, zipffprobepath
119+
120+
121+
def download_linux(download_dir, arch=None, progress=None):
122+
archs = ("amd64", "i686", "arm64", "armhf", "armel")
123+
if arch is None:
124+
arch = archs[0]
125+
elif arch not in archs:
126+
raise ValueError(f"Invalid arch specified. Must be one of {arch}")
127+
zippath = path.join(download_dir, "ffmpeg_linux.tar.xz")
128+
url = (
129+
f"https://johnvansickle.com/ffmpeg/releases/ffmpeg-release-{arch}-static.tar.xz"
130+
)
74131

132+
download_file(zippath, url, "application/x-xz", ctx, progress=progress)
75133
return zippath
76134

77-
# --no-check-certificate
78-
79135

80-
from pprint import pprint
136+
print(get_version_win32(), get_version_macos(), get_version_linux())
81137

82138
download_dir = "tests"
83-
84-
zippath = download(download_dir,platform='linux')
85-
86-
import tarfile
87-
with tarfile.open(zippath) as tar:
88-
tar.extractall(path='tests')
89-
#
90-
#
91-
92-
93-
# # import patoolib
94-
# # patoolib.extract_archive(zippath, outdir=download_dir)
95-
96-
# # import os
97-
# # os.system(r'')
98-
99-
# from py7zlib import Archive7z
100-
101-
# # setup
102-
# with open(zippath, "rb") as fp:
103-
# archive = Archive7z(fp)
104-
# filenames = archive.getnames()
105-
# for filename in filenames:
106-
# cf = archive.getmember(filename)
107-
# print(f"{filename}: crc={cf.uncompressed:x}")
108-
# try:
109-
# cf.checkcrc()
110-
# except:
111-
# raise RuntimeError(f"crc failed for {filename}")
112-
113-
# b = cf.read()
114-
# try:
115-
# assert len(b) == cf.uncompressed
116-
# except:
117-
# raise RuntimeError(f"incorrect uncompressed file size for {filename}")
139+
download_win32(download_dir)
140+
download_macos(download_dir)
141+
download_linux(download_dir)

0 commit comments

Comments
 (0)