diff --git a/hvpy/api_groups/movies/__init__.py b/hvpy/api_groups/movies/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hvpy/api_groups/movies/queue_movie.py b/hvpy/api_groups/movies/queue_movie.py new file mode 100644 index 0000000..c74f08d --- /dev/null +++ b/hvpy/api_groups/movies/queue_movie.py @@ -0,0 +1,143 @@ +from typing import Optional +from datetime import datetime + +from pydantic import validator + +from hvpy.io import HvpyParameters, OutputType +from hvpy.utils import convert_date_to_isoformat + + +class queueMovieInputParameters(HvpyParameters): + """ + Handles the input parameters of the ``queueMovie`` API. + + Attributes + ---------- + {Shared} + startTime + Datetime of the first frame of the movie. + endTime + Datetime of the final frame of the movie. + layers + Image datasource layers to include in the movie. + events + List of feature/event types and FRMs to use to annotate the movie. + eventsLabels + Boolean to indicate if the event labels should be included in the movie. + imageScale + Image scale in arcseconds per pixel. + format + Movie format (mp4, webm, flv). + Default value is "mp4", optional. + frameRate + Movie frames per second. + Default value is 15 frames per second, optional. + maxFrames + Maximum number of frames in the movie, can be capped by the server. + Default value is `None`, optional. + scale + Overlay an image scale indicator. + Default value is `None`, optional. + scaleType + Set the image scale indicator. + Default value is `None`, optional. + scaleX + Horizontal offset of the image scale indicator in arcseconds with respect to the center of the Sun. + Default value is `None`, optional. + scaleY + Vertical offset of the image scale indicator in arcseconds with respect to the center of the Sun. + Default value is `None`, optional. + movieLength + movie length in seconds. + Default value is `None`, optional. + watermark + Optionally overlay a Helioviewer.org watermark image. + Default value is `True`, optional. + width + Width of the field of view in pixels. (Used in conjunction width `x0`,`y0`, and height). + Default value is `None`, optional. + height + Height of the field of view in pixels. (Used in conjunction width `x0`,`y0`, and width). + Default value is `None`, optional. + x0 + The horizontal offset of the center of the field of view from the center of the Sun. Used in conjunction with `y0`, width, and height. + Default value is `None`, optional. + y0 + The vertical offset of the center of the field of view from the center of the Sun. Used in conjunction with `x0`, width, and height. + Default value is `None`, optional. + x1 + The horizontal offset of the top-left corner of the field of view with respect to the center of the Sun (in arcseconds). + Used in conjunction with `y1`, `x2`, and `y2`. + Default value is `None`, optional. + y1 + The vertical offset of the top-left corner of the field of view with respect to the center of the Sun (in arcseconds). + Used in conjunction with `x1`, `x2`, and `y2`. + Default value is `None`, optional. + x2 + The horizontal offset of the bottom-right corner of the field of view with respect to the center of the Sun (in arcseconds). + Used in conjunction with `x1`, `y1`, and `y2`. + Default value is `None`, optional. + y2 + The vertical offset of the bottom-right corner of the field of view with respect to the center of the Sun (in arcseconds). + Used in conjunction with `x1`, `y1`, and `x2`. + Default value is `None`, optional. + callback + Wrap the response object in a function call of your choosing. + Default value is `None`, optional. + size + Scale video to preset size. + Default value is 0, optional. + movieIcons + Display other user generated movies on the video. + Default value is `None`, optional. + followViewport + Rotate field of view of movie with Sun. + Default value is `None`, optional. + reqObservationDate + Viewport datetime. + Used when 'followViewport' enabled to shift viewport area to correct coordinates + Default value is `None`, optional. + + References + ---------- + * ``__ + {Shared} + """ + + startTime: datetime + endTime: datetime + layers: str + events: str + eventsLabels: bool + imageScale: float + format: Optional[str] = "mp4" + frameRate: Optional[str] = "15" + maxFrames: Optional[str] = None + scale: Optional[bool] = None + scaleType: Optional[str] = None + scaleX: Optional[float] = None + scaleY: Optional[float] = None + movieLength: Optional[float] = None + watermark: Optional[bool] = True + width: Optional[str] = None + height: Optional[str] = None + x0: Optional[str] = None + y0: Optional[str] = None + x1: Optional[str] = None + y1: Optional[str] = None + x2: Optional[str] = None + y2: Optional[str] = None + callback: Optional[str] = None + size: Optional[int] = 0 + movieIcons: Optional[int] = None + followViewport: Optional[int] = None + reqObservationDate: Optional[datetime] = None + _date_validator = validator("startTime", "endTime", "reqObservationDate", allow_reuse=True)( + convert_date_to_isoformat + ) + + def get_output_type(self) -> OutputType: + """ + Returns the output type of the API call. + """ + return OutputType.JSON diff --git a/hvpy/api_groups/movies/tests/__init__.py b/hvpy/api_groups/movies/tests/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hvpy/api_groups/movies/tests/test_queue_movie.py b/hvpy/api_groups/movies/tests/test_queue_movie.py new file mode 100644 index 0000000..44a04e3 --- /dev/null +++ b/hvpy/api_groups/movies/tests/test_queue_movie.py @@ -0,0 +1,44 @@ +from datetime import datetime + +import pytest + +from hvpy import queueMovie +from hvpy.api_groups.movies.queue_movie import queueMovieInputParameters + + +def test_json_response(): + response = queueMovie( + startTime=datetime(2022, 7, 20, 12, 12, 12), + endTime=datetime(2022, 7, 21, 12, 12, 12), + layers="[12,7,22],[13,7,22]", + events="[AR,HMI_HARP;SPoCA,1],[CH,all,1]", + eventsLabels=False, + imageScale=1, + ) + assert response["id"] is not None + assert response["eta"] is not None + assert response["queue"] is not None + assert response["token"] is not None + + +def test_error_handling(): + with pytest.raises(TypeError, match="missing 1 required positional argument: 'imageScale'"): + queueMovie( + startTime=datetime(2022, 7, 20, 12, 12, 12), + endTime=datetime(2022, 7, 21, 12, 12, 12), + layers="[12,7,22],[13,7,22]", + events="[AR,HMI_HARP;SPoCA,1],[CH,all,1]", + eventsLabels=False, + ) + + +def test_url_property(): + params = queueMovieInputParameters( + startTime=datetime(2022, 7, 20, 12, 12, 12), + endTime=datetime(2022, 7, 21, 12, 12, 12), + layers="[12,7,22],[13,7,22]", + events="[AR,HMI_HARP;SPoCA,1],[CH,all,1]", + eventsLabels=False, + imageScale=1, + ) + assert params.url == "https://api.helioviewer.org/v2/queueMovie/" diff --git a/hvpy/facade.py b/hvpy/facade.py index 9b3cf21..b3b1bd9 100644 --- a/hvpy/facade.py +++ b/hvpy/facade.py @@ -15,6 +15,7 @@ "getDataSources", "takeScreenshot", "downloadScreenshot", + "queueMovie", ] @@ -298,3 +299,86 @@ def downloadScreenshot(id: int) -> Union[bytes, str, Dict[str, Any]]: """ params = downloadScreenshotInputParameters(id=id) return execute_api_call(input_parameters=params) + + +@add_shared_docstring(queueMovieInputParameters) +def queueMovie( + startTime: datetime, + endTime: datetime, + layers: str, + events: str, + eventsLabels: bool, + imageScale: float, + format: Optional[str] = "mp4", + frameRate: Optional[str] = "15", + maxFrames: Optional[str] = None, + scale: Optional[bool] = None, + scaleType: Optional[str] = None, + scaleX: Optional[float] = None, + scaleY: Optional[float] = None, + movieLength: Optional[float] = None, + watermark: Optional[bool] = True, + width: Optional[str] = None, + height: Optional[str] = None, + x0: Optional[str] = None, + y0: Optional[str] = None, + x1: Optional[str] = None, + y1: Optional[str] = None, + x2: Optional[str] = None, + y2: Optional[str] = None, + callback: Optional[str] = None, + size: Optional[int] = None, + movieIcons: Optional[int] = None, + followViewport: Optional[int] = None, + reqObservationDate: Optional[datetime] = None, +) -> Union[bytes, str, Dict[str, Any]]: + """ + Queue a movie for download from the helioviewer.org API. + + Parameters + ---------- + {Insert} + Examples + -------- + >>> from hvpy import queueMovie + >>> queueMovie( + ... startTime=datetime(2022, 7, 21, 12, 12, 12), + ... endTime=datetime(2022, 7, 22, 12, 12, 12), + ... layers="[12,7,22],[13,7,11]", + ... events="[AR,HMI_HARP;SPoCA,1],[CH,all,1]", + ... eventsLabels=False, + ... imageScale=2.44, + ... ) + {'id': ...} + """ + params = queueMovieInputParameters( + startTime=startTime, + endTime=endTime, + layers=layers, + events=events, + eventsLabels=eventsLabels, + imageScale=imageScale, + format=format, + frameRate=frameRate, + maxFrames=maxFrames, + scale=scale, + scaleType=scaleType, + scaleX=scaleX, + scaleY=scaleY, + movieLength=movieLength, + watermark=watermark, + width=width, + height=height, + x0=x0, + y0=y0, + x1=x1, + y1=y1, + x2=x2, + y2=y2, + callback=callback, + size=size, + movieIcons=movieIcons, + followViewport=followViewport, + reqObservationDate=reqObservationDate, + ) + return execute_api_call(input_parameters=params) diff --git a/hvpy/parameters.py b/hvpy/parameters.py index 2b6bfd1..8dda465 100644 --- a/hvpy/parameters.py +++ b/hvpy/parameters.py @@ -3,6 +3,7 @@ from hvpy.api_groups.jpeg2000.get_jpx import getJPXInputParameters from hvpy.api_groups.jpeg2000.get_jpx_closest_to_mid_point import getJPXClosestToMidPointInputParameters from hvpy.api_groups.jpeg2000.get_status import getStatusInputParameters +from hvpy.api_groups.movies.queue_movie import queueMovieInputParameters from hvpy.api_groups.official_clients.get_closest_image import getClosestImageInputParameters from hvpy.api_groups.official_clients.get_data_sources import getDataSourcesInputParameters from hvpy.api_groups.screenshots.download_screenshot import downloadScreenshotInputParameters @@ -18,4 +19,5 @@ "getDataSourcesInputParameters", "takeScreenshotInputParameters", "downloadScreenshotInputParameters", + "queueMovieInputParameters", ] diff --git a/hvpy/utils.py b/hvpy/utils.py index c6e9d27..9c53667 100644 --- a/hvpy/utils.py +++ b/hvpy/utils.py @@ -19,7 +19,8 @@ def convert_date_to_isoformat(v: datetime) -> str: """ Converts the date from a datetime object to a string in the ISO format. """ - return v.isoformat() + "Z" + if v is not None: + return v.isoformat() + "Z" def convert_date_to_unix(v: list) -> str: