From 4f52d2e372508a17f0a1d18adb3f876e2bf307f5 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 30 Jul 2020 19:56:25 -0700 Subject: [PATCH 01/11] Improve download experience pt 1 --- frameioclient/download.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/frameioclient/download.py b/frameioclient/download.py index b2ed6cba..ad1f45d0 100644 --- a/frameioclient/download.py +++ b/frameioclient/download.py @@ -10,9 +10,14 @@ def __init__(self, asset, download_folder): def download(self): original_filename = self.asset['name'] final_destination = os.path.join(self.download_folder, original_filename) - - url = self.asset['original'] - r = requests.get(url) - - open(final_destination, 'wb').write(r.content) + + print(f"Final destiation: {final_destination}") + + if os.path.isfile(final_destination): + return final_destination + else: + url = self.asset['original'] + r = requests.get(url) + open(final_destination, 'wb').write(r.content) + return final_destination \ No newline at end of file From 6f01bd8b3a6799c86752b58cab8e95db1afab6a5 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 13 Aug 2020 11:27:26 -0700 Subject: [PATCH 02/11] Add support for Watermark ID downloads --- examples/download_asset.py | 12 ++++++++++++ frameioclient/download.py | 34 ++++++++++++++++++++++++++++++---- frameioclient/exceptions.py | 11 +++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 examples/download_asset.py diff --git a/examples/download_asset.py b/examples/download_asset.py new file mode 100644 index 00000000..546486cc --- /dev/null +++ b/examples/download_asset.py @@ -0,0 +1,12 @@ +import os + +from frameioclient import FrameioClient + +def download_file(asset_id): + token = os.getenv("FRAMEIO_TOKEN") + client = FrameioClient(token) + asset_info = client.get_asset(asset_id) + client.download(asset_info, "downloads") + +if __name__ == "__main__": + download_file("6cc9a45f-64a7-456e-a95f-98687220bf6e") \ No newline at end of file diff --git a/frameioclient/download.py b/frameioclient/download.py index ad1f45d0..b5402c47 100644 --- a/frameioclient/download.py +++ b/frameioclient/download.py @@ -1,22 +1,48 @@ -import requests -import math import os +import math +import requests + +from .exceptions import DownloadException class FrameioDownloader(object): def __init__(self, asset, download_folder): self.asset = asset self.download_folder = download_folder + def get_download_key(self): + try: + url = self.asset['original'] + except KeyError: + if self.asset['is_session_watermarked'] == True: + resolution_map = dict() + for resolution_key, download_url in sorted(self.asset['downloads'].items()): + resolution = resolution_key.split("_")[1] # Grab the item at index 1 (resolution) + try: + resolution = int(resolution) + if download_url is not None: + resolution_map.update({ + resolution: download_url + }) + except Exception: + continue + + # Grab the highest resolution now + url = resolution_map.values()[0] + else: + raise DownloadException + + return url + def download(self): original_filename = self.asset['name'] final_destination = os.path.join(self.download_folder, original_filename) - print(f"Final destiation: {final_destination}") + print("Final destiation: {}".format(final_destination)) if os.path.isfile(final_destination): return final_destination else: - url = self.asset['original'] + url = self.get_download_key() r = requests.get(url) open(final_destination, 'wb').write(r.content) return final_destination diff --git a/frameioclient/exceptions.py b/frameioclient/exceptions.py index e42caffb..7e1b831d 100644 --- a/frameioclient/exceptions.py +++ b/frameioclient/exceptions.py @@ -10,3 +10,14 @@ def __init__( ): self.message = message super().__init__(self.message) + +class DownloadException(Exception): + """Exception raised when trying to download a file where there is no available + download URL. + """ + def __init__( + self, + message="This file is unavailable for download due to security and permission settings." + ): + self.message = message + super().__init__(self.message) \ No newline at end of file From af8a50e7de6472733edca13af485a5aea94b7294 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 13 Aug 2020 16:02:27 -0700 Subject: [PATCH 03/11] Use less broad exception handling --- frameioclient/download.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frameioclient/download.py b/frameioclient/download.py index b5402c47..bafea792 100644 --- a/frameioclient/download.py +++ b/frameioclient/download.py @@ -23,7 +23,7 @@ def get_download_key(self): resolution_map.update({ resolution: download_url }) - except Exception: + except ValueError: continue # Grab the highest resolution now From 59e23fff8716e4d07ea00b6e9c6c73ffc4dda8b7 Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 25 Aug 2020 12:51:09 -0700 Subject: [PATCH 04/11] =?UTF-8?q?Bump=20version:=200.8.1=20=E2=86=92=200.8?= =?UTF-8?q?.2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .bumpversion.cfg | 2 +- setup.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.bumpversion.cfg b/.bumpversion.cfg index aa84069b..23cc1546 100644 --- a/.bumpversion.cfg +++ b/.bumpversion.cfg @@ -1,5 +1,5 @@ [bumpversion] -current_version = 0.8.1 +current_version = 0.8.2 commit = True tag = True diff --git a/setup.py b/setup.py index bb1d0456..70f4a2bd 100644 --- a/setup.py +++ b/setup.py @@ -4,7 +4,7 @@ from setuptools.command.install import install -version='0.8.1' +version='0.8.2' with open("README.md", "r") as f: long_description = f.read() From 0e080e541827b68a40dea07be9f523ca9cf876ae Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 25 Aug 2020 12:51:48 -0700 Subject: [PATCH 05/11] Change codeowners to DevRel --- .github/CODEOWNERS | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index ebedb07e..870b172f 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -7,4 +7,4 @@ # Order is important; the last matching pattern takes the most # precedence. When someone opens a pull request that only # modifies Python files. -*.py jmeggesto@frame.io billy@frame.io zach@frame.io jay@frame.io \ No newline at end of file +*.py @devrel \ No newline at end of file From 62b5edb58f3af06f4ad4096e93f5a4f308efa801 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 12 Oct 2020 18:21:35 -0700 Subject: [PATCH 06/11] Add testing outline for WMID --- tests/test_wmid.py | 41 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 tests/test_wmid.py diff --git a/tests/test_wmid.py b/tests/test_wmid.py new file mode 100644 index 00000000..e101e45e --- /dev/null +++ b/tests/test_wmid.py @@ -0,0 +1,41 @@ +import pytest +from frameioclient import FrameioClient + + +regular_asset = { + "is_hls_required": False, + "is_session_watermarked": False, + "downloads": { + "h264_720": "some-s3-url", + "h264_1080_best": "some-other-s3-url" + }, + "h264_720": "some-s3-url", + "h264_1080_best": "some-other-s3-url" + "original": "some-s3-url", + "hls_manifest": "hls-url" +} + +watermarked_asset_download_allowed: { + "is_hls_required": True, + "is_session_watermarked": True, + "downloads": { + "h264_720": "download-stream-service-url", + "h264_1080_best": "download-stream-service-url" + }, + "hls_manifest": "hls-url" +} + +watermarked_asset_no_download = { + "is_hls_required": True, + "is_session_watermarked": True, + "hls_manifest": "hls-url" +} + +no_download_allowed = { + "is_hls_required": True, + "is_session_watermarked": False, + "hls_manifest": "hls-url" +} + +def test_FrameioClient(frameioclient): + assert type(frameioclient) == FrameioClient From 3f5782d2341d01272f2340cc57a611a72441c090 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 12 Oct 2020 19:49:18 -0700 Subject: [PATCH 07/11] Fixes per Lezou's comments --- frameioclient/download.py | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/frameioclient/download.py b/frameioclient/download.py index bafea792..afd5ee60 100644 --- a/frameioclient/download.py +++ b/frameioclient/download.py @@ -14,20 +14,19 @@ def get_download_key(self): url = self.asset['original'] except KeyError: if self.asset['is_session_watermarked'] == True: - resolution_map = dict() + resolution_list = list() for resolution_key, download_url in sorted(self.asset['downloads'].items()): resolution = resolution_key.split("_")[1] # Grab the item at index 1 (resolution) try: resolution = int(resolution) - if download_url is not None: - resolution_map.update({ - resolution: download_url - }) except ValueError: continue - # Grab the highest resolution now - url = resolution_map.values()[0] + if download_url is not None: + resolution_list.append(download_url) + + # Grab the highest resolution (first item) now + url = resolution_list[0] else: raise DownloadException From 018ff8afd993c149afe27454497038ab60fc9d1e Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 12 Oct 2020 19:51:54 -0700 Subject: [PATCH 08/11] Small tweak to conftest.py --- tests/conftest.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/conftest.py b/tests/conftest.py index 6ff505e3..52a3b1dc 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,15 @@ +import os import pytest from frameioclient import FrameioClient + @pytest.fixture def frameioclient(token): return FrameioClient("aaaabbbbccccddddeeee") + +token = os.getenv('FRAME_IO_TOKEN') + +@pytest.fixture() +def setup_client(): + client = FrameioClient(token) + return client From 8544131a641fffe075f3a5ea4e4f4af4330ea314 Mon Sep 17 00:00:00 2001 From: Jeff Date: Mon, 12 Oct 2020 19:52:05 -0700 Subject: [PATCH 09/11] Add additional python version compatibility --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 70f4a2bd..40063dce 100644 --- a/setup.py +++ b/setup.py @@ -47,9 +47,11 @@ def run(self): 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', ], description='Client library for the Frame.io API', long_description=long_description, From 9e464d2b2479233ea4c4cc1929bee6ee77786521 Mon Sep 17 00:00:00 2001 From: Jeff Date: Tue, 13 Oct 2020 14:47:25 -0700 Subject: [PATCH 10/11] Improved tests --- tests/conftest.py | 8 ++++---- tests/test_frameioclient.py | 6 +++--- tests/test_wmid.py | 5 +---- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/conftest.py b/tests/conftest.py index 52a3b1dc..c32947be 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -2,12 +2,12 @@ import pytest from frameioclient import FrameioClient +token = os.getenv('FRAME_IO_TOKEN') -@pytest.fixture -def frameioclient(token): - return FrameioClient("aaaabbbbccccddddeeee") +# @pytest.fixture +# def frameioclient(token): +# return FrameioClient("aaaabbbbccccddddeeee") -token = os.getenv('FRAME_IO_TOKEN') @pytest.fixture() def setup_client(): diff --git a/tests/test_frameioclient.py b/tests/test_frameioclient.py index e60490a8..f885333b 100644 --- a/tests/test_frameioclient.py +++ b/tests/test_frameioclient.py @@ -1,5 +1,5 @@ -import pytest from frameioclient import FrameioClient -def test_FrameioClient(frameioclient): - assert type(frameioclient) == FrameioClient +def test_FrameioClient(setup_client): + client = setup_client + assert type(client) == FrameioClient \ No newline at end of file diff --git a/tests/test_wmid.py b/tests/test_wmid.py index e101e45e..efca88dd 100644 --- a/tests/test_wmid.py +++ b/tests/test_wmid.py @@ -10,7 +10,7 @@ "h264_1080_best": "some-other-s3-url" }, "h264_720": "some-s3-url", - "h264_1080_best": "some-other-s3-url" + "h264_1080_best": "some-other-s3-url", "original": "some-s3-url", "hls_manifest": "hls-url" } @@ -36,6 +36,3 @@ "is_session_watermarked": False, "hls_manifest": "hls-url" } - -def test_FrameioClient(frameioclient): - assert type(frameioclient) == FrameioClient From e0585a475de208dabf86672e3f5bdda030f581c8 Mon Sep 17 00:00:00 2001 From: Jeff Date: Wed, 14 Oct 2020 11:38:57 -0700 Subject: [PATCH 11/11] Improved testing! --- frameioclient/client.py | 3 +- frameioclient/download.py | 29 +++++++++-------- tests/test_frameiodownloader.py | 56 +++++++++++++++++++++++++++++++++ tests/test_wmid.py | 38 ---------------------- 4 files changed, 73 insertions(+), 53 deletions(-) create mode 100644 tests/test_frameiodownloader.py delete mode 100644 tests/test_wmid.py diff --git a/frameioclient/client.py b/frameioclient/client.py index 14480381..29e411dc 100644 --- a/frameioclient/client.py +++ b/frameioclient/client.py @@ -351,8 +351,7 @@ def copy_asset(self, destination_folder_id, **kwargs): return self._api_call('post', endpoint, kwargs) def bulk_copy_assets(self, destination_folder_id, asset_list=[], copy_comments=False): - """ - Bulk copy assets + """Bulk copy assets :Args: destination_folder_id (string): The id of the folder you want to copy into. diff --git a/frameioclient/download.py b/frameioclient/download.py index afd5ee60..8fdcc41e 100644 --- a/frameioclient/download.py +++ b/frameioclient/download.py @@ -12,21 +12,24 @@ def __init__(self, asset, download_folder): def get_download_key(self): try: url = self.asset['original'] - except KeyError: + except KeyError as e: if self.asset['is_session_watermarked'] == True: resolution_list = list() - for resolution_key, download_url in sorted(self.asset['downloads'].items()): - resolution = resolution_key.split("_")[1] # Grab the item at index 1 (resolution) - try: - resolution = int(resolution) - except ValueError: - continue - - if download_url is not None: - resolution_list.append(download_url) - - # Grab the highest resolution (first item) now - url = resolution_list[0] + try: + for resolution_key, download_url in sorted(self.asset['downloads'].items()): + resolution = resolution_key.split("_")[1] # Grab the item at index 1 (resolution) + try: + resolution = int(resolution) + except ValueError: + continue + + if download_url is not None: + resolution_list.append(download_url) + + # Grab the highest resolution (first item) now + url = resolution_list[0] + except KeyError: + raise DownloadException else: raise DownloadException diff --git a/tests/test_frameiodownloader.py b/tests/test_frameiodownloader.py new file mode 100644 index 00000000..b7caea7c --- /dev/null +++ b/tests/test_frameiodownloader.py @@ -0,0 +1,56 @@ +import pytest +from frameioclient.download import FrameioDownloader +from frameioclient.exceptions import DownloadException + + +regular_asset = { + "is_hls_required": False, + "is_session_watermarked": False, + "downloads": { + "h264_720": "some-720-url", + "h264_1080_best": "some-1080-url" + }, + "h264_720": "some-720-url", + "h264_1080_best": "some-1080-url", + "original": "some-original-url", + "hls_manifest": "some-hls-url" +} + +watermarked_asset_download_allowed = { + "is_hls_required": True, + "is_session_watermarked": True, + "downloads": { + "h264_720": "download-stream-service-url", + "h264_1080_best": "download-stream-service-url" + }, + "hls_manifest": "hls-url" +} + +watermarked_asset_no_download = { + "is_hls_required": True, + "is_session_watermarked": True, + "hls_manifest": "hls-url" +} + +no_download_allowed = { + "is_hls_required": True, + "is_session_watermarked": False, + "hls_manifest": "hls-url" +} + +def test_get_download_key_returns_original(): + url = FrameioDownloader(regular_asset, './').get_download_key() + assert url == regular_asset['original'] + +def test_get_download_key_returns_watermarked_download(): + url = FrameioDownloader(watermarked_asset_download_allowed, './').get_download_key() + assert url == watermarked_asset_download_allowed['downloads']['h264_1080_best'] + +def test_get_download_key_fails_gracefully_on_watermarked_asset(): + with pytest.raises(DownloadException): + FrameioDownloader(watermarked_asset_no_download, './').get_download_key() + +def test_get_download_key_fails_gracefully_when_downloads_disallowed(): + with pytest.raises(DownloadException): + FrameioDownloader(no_download_allowed, './').get_download_key() + diff --git a/tests/test_wmid.py b/tests/test_wmid.py deleted file mode 100644 index efca88dd..00000000 --- a/tests/test_wmid.py +++ /dev/null @@ -1,38 +0,0 @@ -import pytest -from frameioclient import FrameioClient - - -regular_asset = { - "is_hls_required": False, - "is_session_watermarked": False, - "downloads": { - "h264_720": "some-s3-url", - "h264_1080_best": "some-other-s3-url" - }, - "h264_720": "some-s3-url", - "h264_1080_best": "some-other-s3-url", - "original": "some-s3-url", - "hls_manifest": "hls-url" -} - -watermarked_asset_download_allowed: { - "is_hls_required": True, - "is_session_watermarked": True, - "downloads": { - "h264_720": "download-stream-service-url", - "h264_1080_best": "download-stream-service-url" - }, - "hls_manifest": "hls-url" -} - -watermarked_asset_no_download = { - "is_hls_required": True, - "is_session_watermarked": True, - "hls_manifest": "hls-url" -} - -no_download_allowed = { - "is_hls_required": True, - "is_session_watermarked": False, - "hls_manifest": "hls-url" -}