From 86755f07eede78a16140533e125ac4caed8e6476 Mon Sep 17 00:00:00 2001 From: Runs Date: Sun, 11 Oct 2026 03:14:36 +0000 Subject: [PATCH] fix: namespace automatic downloads by project id --- README.md | 2 ++ magic_hour/helpers/download.py | 16 +++++++++++++--- magic_hour/resources/v1/audio_projects/client.py | 2 ++ magic_hour/resources/v1/face_detection/client.py | 2 ++ magic_hour/resources/v1/image_projects/client.py | 2 ++ magic_hour/resources/v1/video_projects/client.py | 2 ++ 6 files changed, 23 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ba805ce..cfe10af 100644 --- a/README.md +++ b/README.md @@ -102,6 +102,8 @@ The `generate()` function provides a complete end-to-end solution: - `download_outputs` (bool, default True): Whether to download the generated files - `download_directory` (str, optional): Directory to save downloaded files (defaults to current directory) +Automatic downloads use filenames prefixed with the project ID. Use `response.downloaded_paths` to find saved files; downloading the same project again may overwrite its previous files. + ```python # Generate function - handles everything automatically response = client.v1.ai_image_generator.generate( diff --git a/magic_hour/helpers/download.py b/magic_hour/helpers/download.py index 5c51f99..defb1e0 100644 --- a/magic_hour/helpers/download.py +++ b/magic_hour/helpers/download.py @@ -10,10 +10,14 @@ def _compute_download_path( - url: str, download_directory: Union[str, None] = None + url: str, + download_directory: Union[str, None] = None, + project_id: Union[str, None] = None, ) -> str: url_path = urlparse(url).path filename = Path(url_path).name + if project_id: + filename = f"{Path(project_id).name}-{filename}" if download_directory: return os.path.join(download_directory, filename) return filename @@ -26,6 +30,7 @@ def download_files_sync( List[models.V1AudioProjectsGetResponseDownloadsItem], ], download_directory: Union[str, None] = None, + project_id: Union[str, None] = None, ) -> List[str]: downloaded_paths: List[str] = [] @@ -35,7 +40,9 @@ def download_files_sync( download_response.raise_for_status() download_path = _compute_download_path( - download.url, download_directory=download_directory + download.url, + download_directory=download_directory, + project_id=project_id, ) with open(download_path, "wb") as f: @@ -55,6 +62,7 @@ async def download_files_async( List[models.V1AudioProjectsGetResponseDownloadsItem], ], download_directory: Union[str, None] = None, + project_id: Union[str, None] = None, ) -> List[str]: downloaded_paths: List[str] = [] @@ -64,7 +72,9 @@ async def download_files_async( download_response.raise_for_status() download_path = _compute_download_path( - download.url, download_directory=download_directory + download.url, + download_directory=download_directory, + project_id=project_id, ) with open(download_path, "wb") as f: diff --git a/magic_hour/resources/v1/audio_projects/client.py b/magic_hour/resources/v1/audio_projects/client.py index 33d7ce3..a8cfc4d 100644 --- a/magic_hour/resources/v1/audio_projects/client.py +++ b/magic_hour/resources/v1/audio_projects/client.py @@ -85,6 +85,7 @@ def check_result( downloaded_paths = download_files_sync( downloads=api_response.downloads, download_directory=download_directory, + project_id=api_response.id, ) return V1AudioProjectsGetResponseWithDownloads( @@ -225,6 +226,7 @@ async def check_result( downloaded_paths = await download_files_async( downloads=api_response.downloads, download_directory=download_directory, + project_id=api_response.id, ) return V1AudioProjectsGetResponseWithDownloads( diff --git a/magic_hour/resources/v1/face_detection/client.py b/magic_hour/resources/v1/face_detection/client.py index 53a81b4..00b6d24 100644 --- a/magic_hour/resources/v1/face_detection/client.py +++ b/magic_hour/resources/v1/face_detection/client.py @@ -108,6 +108,7 @@ def generate( downloaded_paths = download_files_sync( downloads=face_downloads, download_directory=download_directory, + project_id=api_response.id, ) return V1FaceDetectionGetResponseWithDownloads( @@ -283,6 +284,7 @@ async def generate( downloaded_paths = await download_files_async( downloads=face_downloads, download_directory=download_directory, + project_id=api_response.id, ) return V1FaceDetectionGetResponseWithDownloads( diff --git a/magic_hour/resources/v1/image_projects/client.py b/magic_hour/resources/v1/image_projects/client.py index c248dd4..e42f7bf 100644 --- a/magic_hour/resources/v1/image_projects/client.py +++ b/magic_hour/resources/v1/image_projects/client.py @@ -86,6 +86,7 @@ def check_result( downloaded_paths = download_files_sync( downloads=api_response.downloads, download_directory=download_directory, + project_id=api_response.id, ) return V1ImageProjectsGetResponseWithDownloads( @@ -226,6 +227,7 @@ async def check_result( downloaded_paths = await download_files_async( downloads=api_response.downloads, download_directory=download_directory, + project_id=api_response.id, ) return V1ImageProjectsGetResponseWithDownloads( diff --git a/magic_hour/resources/v1/video_projects/client.py b/magic_hour/resources/v1/video_projects/client.py index 528f7ae..2167098 100644 --- a/magic_hour/resources/v1/video_projects/client.py +++ b/magic_hour/resources/v1/video_projects/client.py @@ -85,6 +85,7 @@ def check_result( downloaded_paths = download_files_sync( downloads=api_response.downloads, download_directory=download_directory, + project_id=api_response.id, ) return V1VideoProjectsGetResponseWithDownloads( @@ -225,6 +226,7 @@ async def check_result( downloaded_paths = await download_files_async( downloads=api_response.downloads, download_directory=download_directory, + project_id=api_response.id, ) return V1VideoProjectsGetResponseWithDownloads(