Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ Global **`--timeout`** (seconds, default **`60`**) applies to API calls and to *
Run without an installed script:

```bash
python -m gopro_api.cli search --start 2026-03-01 --end 2026-03-02
python -m gopro_api.cli search --start 2026-03-01 --end 2026-03-03
python -m gopro_api.cli info MEDIA_ID
python -m gopro_api.cli pull MEDIA_ID ./out
python -m gopro_api.cli pull MEDIA_ID ./out --height 720
Expand Down Expand Up @@ -143,7 +143,7 @@ async def main() -> None:
params = GoProMediaSearchParams(
captured_range=CapturedRange(
start=datetime.fromisoformat("2026-03-01"),
end=datetime.fromisoformat("2026-03-02"),
end=datetime.fromisoformat("2026-03-03"),
),
per_page=50,
page=1,
Expand Down Expand Up @@ -173,7 +173,7 @@ def main() -> None:
params = GoProMediaSearchParams(
captured_range=CapturedRange(
start=datetime.fromisoformat("2026-03-01"),
end=datetime.fromisoformat("2026-03-02"),
end=datetime.fromisoformat("2026-03-03"),
),
per_page=50,
page=1,
Expand Down
2 changes: 1 addition & 1 deletion docs/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ gopro-api auth --tsv
## Running without an installed entry point

```bash
python -m gopro_api.cli search --start 2026-03-01 --end 2026-03-02
python -m gopro_api.cli search --start 2026-03-01 --end 2026-03-03
python -m gopro_api.cli info MEDIA_ID
python -m gopro_api.cli pull MEDIA_ID ./out
python -m gopro_api.cli pull MEDIA_ID ./out --height 720
Expand Down
8 changes: 4 additions & 4 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,8 @@ gopro-api auth
After installing, `gopro-api` is available on your `PATH`:

```bash
# List media captured on a specific day
gopro-api search --start 2026-03-01 --end 2026-03-02
# List media captured on a specific day (start and end are inclusive)
gopro-api search --start 2026-03-01 --end 2026-03-01

# Show download metadata for a single media item
gopro-api info MEDIA_ID
Expand All @@ -79,7 +79,7 @@ from gopro_api.api.models import CapturedRange, GoProMediaSearchParams
params = GoProMediaSearchParams(
captured_range=CapturedRange(
start=datetime.fromisoformat("2026-03-01"),
end=datetime.fromisoformat("2026-03-02"),
end=datetime.fromisoformat("2026-03-03"),
),
per_page=50,
page=1,
Expand All @@ -104,7 +104,7 @@ from gopro_api.api.models import CapturedRange, GoProMediaSearchParams
params = GoProMediaSearchParams(
captured_range=CapturedRange(
start=datetime.fromisoformat("2026-03-01"),
end=datetime.fromisoformat("2026-03-02"),
end=datetime.fromisoformat("2026-03-03"),
),
per_page=50,
page=1,
Expand Down
22 changes: 16 additions & 6 deletions gopro_api/api/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from __future__ import annotations

from datetime import datetime
from datetime import date, datetime, timedelta
from typing import Any, List, Optional

from pydantic import BaseModel, ConfigDict, Field, field_serializer, model_serializer
Expand Down Expand Up @@ -44,11 +44,13 @@ class CapturedRange(BaseModel):
"""Inclusive capture date window used in search queries.

Serialized to a single ``captured_range`` query string with fixed
``T00:00:00.000Z`` suffixes, as required by the cloud API.
``T00:00:00.000Z`` suffixes, as required by the cloud API. The API treats
that range as half-open ``[start, end)``, so the serialized end date is the
calendar day after ``end`` (unless ``end`` is already ``date.max``).

Attributes:
start: Range start (date portion used in the wire format).
end: Range end (date portion used in the wire format).
start: Inclusive range start (date portion used in the wire format).
end: Inclusive range end (date portion used in the wire format).
"""

start: datetime
Expand All @@ -58,12 +60,20 @@ class CapturedRange(BaseModel):
def _serialize_captured_range(self) -> str:
"""Serialize this range for the ``captured_range`` query parameter.

Uses calendar dates only and advances the end by one day so a same-day
filter such as ``2024-01-07``…``2024-01-07`` becomes
``2024-01-07T00:00:00.000Z,2024-01-08T00:00:00.000Z``.

Returns:
Comma-separated ISO date pair with ``Z`` UTC suffixes.
"""
start_day = self.start.date()
end_day = self.end.date()
if end_day < date.max:
end_day = end_day + timedelta(days=1)
return (
f"{self.start.isoformat()}T00:00:00.000Z,"
f"{self.end.isoformat()}T00:00:00.000Z"
f"{start_day.isoformat()}T00:00:00.000Z,"
f"{end_day.isoformat()}T00:00:00.000Z"
)


Expand Down
16 changes: 8 additions & 8 deletions gopro_api/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ def iter_nonempty_search_pages(
"""Yield search result pages until one returns an empty ``_embedded.media``.

Args:
start_date: Capture range start (inclusive semantics per API).
end_date: Capture range end.
start_date: Capture range start (inclusive calendar day).
end_date: Capture range end (inclusive calendar day).
per_page: Items per page; defaults to ``self.page_size``.
start_page: First page number to request (1-indexed).

Expand All @@ -170,8 +170,8 @@ def list_media_items(
"""Collect media rows across pages up to ``max_items``.

Args:
start_date: Capture range start.
end_date: Capture range end.
start_date: Capture range start (inclusive calendar day).
end_date: Capture range end (inclusive calendar day).

Returns:
Up to ``self.max_items`` ``GoProMediaSearchItem`` instances.
Expand Down Expand Up @@ -356,8 +356,8 @@ async def iter_nonempty_search_pages(
"""Yield search pages until one returns an empty ``_embedded.media``.

Args:
start_date: Capture range start (inclusive semantics per API).
end_date: Capture range end.
start_date: Capture range start (inclusive calendar day).
end_date: Capture range end (inclusive calendar day).
per_page: Items per page; defaults to ``self.page_size``.
start_page: First page number to request (1-indexed).

Expand All @@ -384,8 +384,8 @@ async def list_media_items(
"""Collect media rows across pages up to ``max_items``.

Args:
start_date: Capture range start.
end_date: Capture range end.
start_date: Capture range start (inclusive calendar day).
end_date: Capture range end (inclusive calendar day).

Returns:
Up to ``self.max_items`` ``GoProMediaSearchItem`` instances.
Expand Down
Loading