Skip to content
Open
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
2 changes: 1 addition & 1 deletion .release-please-manifest.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
{
".": "0.57.0"
".": "0.58.0"
}
4 changes: 2 additions & 2 deletions .stats.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
configured_endpoints: 112
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/profound/profound-149b8a08095a18bf3fb737d6be9225c2fe1f493e6c7a9c05292cd6fd7279831f.yml
openapi_spec_hash: 666ac2325673e3d2ecf32cfa3d800a3b
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/profound/profound-2d6576d56fa9d77f7287d063cbbe9600ffcf13398448233220e0b4fec452da2e.yml
openapi_spec_hash: 9fb5ec5196a26e0f6f18129f586189eb
config_hash: 5c89b9e84ab75df8b9d40d3e90f1d9a0
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## 0.58.0 (2026-08-07)

Full Changelog: [v0.57.0...v0.58.0](https://github.com/cooper-square-technologies/profound-python-sdk/compare/v0.57.0...v0.58.0)

### Features

* **api:** api update ([784b5e9](https://github.com/cooper-square-technologies/profound-python-sdk/commit/784b5e900c45e763de1b2e04350ec98391c77afe))
* **api:** api update ([8fb4e3f](https://github.com/cooper-square-technologies/profound-python-sdk/commit/8fb4e3f5cdf323113785d5de87eda4c3ee3dc657))

## 0.57.0 (2026-08-05)

Full Changelog: [v0.56.0...v0.57.0](https://github.com/cooper-square-technologies/profound-python-sdk/compare/v0.56.0...v0.57.0)
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "profound"
version = "0.57.0"
version = "0.58.0"
description = "The official Python library for the profound API"
dynamic = ["readme"]
license = "Apache-2.0"
Expand Down
2 changes: 1 addition & 1 deletion src/profound/_version.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

__title__ = "profound"
__version__ = "0.57.0" # x-release-please-version
__version__ = "0.58.0" # x-release-please-version
26 changes: 18 additions & 8 deletions src/profound/resources/reports/social/youtube.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,8 @@ def get_channels(
`["video_category"]` ranks content categories; `["source_type"]` ranks source
types; `["channel", "video_category"]`, `["channel", "source_type"]` and
`["channel", "model"]` return cross-tabs — a row per channel per category, or
per answer engine. `limit` counts channels in every case, so ten channels across
nine engines is ten channels and ninety rows.
per answer engine. `limit` counts leading channels in every case, so ten
channels across nine engines is ten channels and ninety rows.

interval: Return a time series instead of window totals: one row per entity per period,
each carrying `date`. `citation_share` is then relative to that period, so the
Expand All @@ -90,7 +90,9 @@ def get_channels(
limit: Page size; default 10, max 50.

source_types: Limit results to YouTube source types: `video`, `short`, `channel`, `playlist`,
or `other`. Omit to include every source type.
or `other`. Omit to include `video`, `short`, `channel`, and `playlist`; `other`
is excluded because those citations have no channel. Requests containing `other`
are rejected.

extra_headers: Send extra headers

Expand Down Expand Up @@ -206,7 +208,10 @@ def get_videos(
limit: Page size; default 10, max 50.

source_types: Limit results to YouTube source types: `video`, `short`, `channel`, `playlist`,
or `other`. Omit to include every source type.
or `other`. Omit to include `video` and `short` with the default
`attribution='attributed'`; `unattributed` and `all` widen the default to all
five source types. Requests containing `other` with `attribution='attributed'`
are rejected.

extra_headers: Send extra headers

Expand Down Expand Up @@ -292,8 +297,8 @@ async def get_channels(
`["video_category"]` ranks content categories; `["source_type"]` ranks source
types; `["channel", "video_category"]`, `["channel", "source_type"]` and
`["channel", "model"]` return cross-tabs — a row per channel per category, or
per answer engine. `limit` counts channels in every case, so ten channels across
nine engines is ten channels and ninety rows.
per answer engine. `limit` counts leading channels in every case, so ten
channels across nine engines is ten channels and ninety rows.

interval: Return a time series instead of window totals: one row per entity per period,
each carrying `date`. `citation_share` is then relative to that period, so the
Expand All @@ -302,7 +307,9 @@ async def get_channels(
limit: Page size; default 10, max 50.

source_types: Limit results to YouTube source types: `video`, `short`, `channel`, `playlist`,
or `other`. Omit to include every source type.
or `other`. Omit to include `video`, `short`, `channel`, and `playlist`; `other`
is excluded because those citations have no channel. Requests containing `other`
are rejected.

extra_headers: Send extra headers

Expand Down Expand Up @@ -418,7 +425,10 @@ async def get_videos(
limit: Page size; default 10, max 50.

source_types: Limit results to YouTube source types: `video`, `short`, `channel`, `playlist`,
or `other`. Omit to include every source type.
or `other`. Omit to include `video` and `short` with the default
`attribution='attributed'`; `unattributed` and `all` widen the default to all
five source types. Requests containing `other` with `attribution='attributed'`
are rejected.

extra_headers: Send extra headers

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,8 @@ class YoutubeGetChannelsParams(TypedDict, total=False):
categories; `["source_type"]` ranks source types;
`["channel", "video_category"]`, `["channel", "source_type"]` and
`["channel", "model"]` return cross-tabs — a row per channel per category, or
per answer engine. `limit` counts channels in every case, so ten channels across
nine engines is ten channels and ninety rows.
per answer engine. `limit` counts leading channels in every case, so ten
channels across nine engines is ten channels and ninety rows.
"""

interval: Optional[Literal["day", "week", "month"]]
Expand All @@ -46,7 +46,9 @@ class YoutubeGetChannelsParams(TypedDict, total=False):
source_types: Optional[List[Literal["video", "short", "channel", "playlist", "other"]]]
"""
Limit results to YouTube source types: `video`, `short`, `channel`, `playlist`,
or `other`. Omit to include every source type.
or `other`. Omit to include `video`, `short`, `channel`, and `playlist`; `other`
is excluded because those citations have no channel. Requests containing `other`
are rejected.
"""


Expand Down
160 changes: 156 additions & 4 deletions src/profound/types/reports/social/youtube_get_channels_response.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,165 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Dict, List
from typing import TYPE_CHECKING, Dict, List, Optional
from typing_extensions import Literal

from pydantic import Field as FieldInfo

from ...._models import BaseModel

__all__ = ["YoutubeGetChannelsResponse"]
__all__ = ["YoutubeGetChannelsResponse", "Data", "DataModel", "Info"]


class DataModel(BaseModel):
"""An ``{id, name}`` reference for a grouped dimension value."""

id: Optional[str] = None

name: Optional[str] = None


class Data(BaseModel):
"""One channel (or video category) row, optionally sliced."""

citation_share: float
"""
Share of every YouTube citation in the window (attributed and unattributed
alike), or the period when `interval` is set, regardless of `source_types`. An
unnarrowed complete ranking sums to slightly less than 1 because unattributed
citations cannot appear in channel rows; a narrowed ranking sums to its slice's
share.
"""

count: int
"""Citations attributed to this row."""

name: str
"""
Channel title when grouped by channel, or the handle when no title resolved;
category name when grouped by `["video_category"]`; source type when grouped by
`["source_type"]`.
"""

rank: int
"""
Leading channel's 1-based position in the full ranked set, continuing across
pages; repeated across that channel's cross-tab rows rather than numbering rows.
"""

videos: int
"""Distinct videos of this channel that were cited."""

date: Optional[str] = None
"""Period start. Present when `interval` is set."""

handle: Optional[str] = None
"""Channel handle without the `@`, and the identifier this API exposes.

Pass it to /videos as `channel_handle`. Null for the rare channel whose handle
did not resolve.
"""

model: Optional[DataModel] = None
"""An `{id, name}` reference for a grouped dimension value."""

source_type: Optional[Literal["video", "short", "channel", "playlist", "other"]] = None
"""
YouTube source type, present when grouped by source type, including as the
second dimension of a cross-tab.
"""

url: Optional[str] = None
"""Openable channel URL. Null for video-category rows."""

video_category: Optional[str] = None
"""
Populated for a secondary video-category slice; with group_by
`["video_category"]`, the category is returned in `name` instead. An unresolved
category is returned as an empty string.
"""

if TYPE_CHECKING:
# Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a
# value to this field, so for compatibility we avoid doing it at runtime.
__pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]

# Stub to indicate that arbitrary properties are accepted.
# To access properties that are not valid identifiers you can use `getattr`, e.g.
# `getattr(obj, '$type')`
def __getattr__(self, attr: str) -> object: ...
else:
__pydantic_extra__: Dict[str, object]


class Info(BaseModel):
"""Channel report metadata, including effective paging and grouping settings."""

category_id: str
"""Echoed category id this report covers."""

count: int
"""Number of rows returned in `data` for this page."""

end_date: str
"""Echoed request end date (YYYY-MM-DD, ET)."""

group_by: List[str]
"""Echoed dimensions that define a row.

Channel reports echo `["channel"]` when group_by is omitted.
"""

limit: int
"""Effective page size in leading channels, not returned rows."""

models: List[str]
"""Display names of the models the report covers."""

source_types: List[Literal["video", "short", "channel", "playlist", "other"]]
"""Source types this report covers.

Derived from the request, not returned rows, so a listed type may have no rows.
"""

start_date: str
"""Echoed request start date (YYYY-MM-DD, ET)."""

total_results: int
"""
Distinct leading channels matching the window; this can differ from the number
of rows returned.
"""

cursor: Optional[str] = None
"""Echoed request cursor; omitted on the first page."""

filter: Optional[Dict[str, object]] = None
"""Echoed normalized filter tree, or null when no filter was sent."""

interval: Optional[Literal["day", "week", "month"]] = None
"""
Effective channel time-series interval, or null when the channel report covers
the full window.
"""

next_cursor: Optional[str] = None
"""Opaque cursor for the next page; null on the last page."""

if TYPE_CHECKING:
# Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a
# value to this field, so for compatibility we avoid doing it at runtime.
__pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]

# Stub to indicate that arbitrary properties are accepted.
# To access properties that are not valid identifiers you can use `getattr`, e.g.
# `getattr(obj, '$type')`
def __getattr__(self, attr: str) -> object: ...
else:
__pydantic_extra__: Dict[str, object]


class YoutubeGetChannelsResponse(BaseModel):
data: List[Dict[str, object]]
data: List[Data]

info: Dict[str, object]
info: Info
"""Channel report metadata, including effective paging and grouping settings."""
62 changes: 58 additions & 4 deletions src/profound/types/reports/social/youtube_get_summary_response.py
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.

from typing import Dict, Optional
from typing import TYPE_CHECKING, Dict, List, Optional
from typing_extensions import Literal

from pydantic import Field as FieldInfo

from ...._models import BaseModel

__all__ = ["YoutubeGetSummaryResponse", "Data"]
__all__ = ["YoutubeGetSummaryResponse", "Data", "Info"]


class Data(BaseModel):
"""How much of youtube.com the rollups can speak for."""

attributed_citations: Optional[int] = None
"""Citations that resolve to a channel; the ranking denominator."""
"""
Citations that resolve to a channel, so can appear in the channel and video
rankings. NOT the citation_share divisor — that is total_youtube_citations, so a
complete channel ranking's shares sum to slightly less than 1.
"""

citations_channel: Optional[int] = None
"""Citations pointing at a channel page rather than a video."""
Expand Down Expand Up @@ -47,8 +54,55 @@ class Data(BaseModel):
"""


class Info(BaseModel):
"""Summary report metadata."""

category_id: str
"""Echoed category id this report covers."""

count: int
"""Number of rows returned in `data` for this page."""

end_date: str
"""Echoed request end date (YYYY-MM-DD, ET)."""

models: List[str]
"""Display names of the models the report covers."""

source_types: List[Literal["video", "short", "channel", "playlist", "other"]]
"""
All five YouTube source types; this endpoint has no source_types request field
and cannot be narrowed.
"""

start_date: str
"""Echoed request start date (YYYY-MM-DD, ET)."""

filter: Optional[Dict[str, object]] = None
"""Echoed normalized filter tree, or null when no filter was sent."""

next_cursor: Optional[str] = None
"""Opaque cursor for the next page; null on the last page."""

total_results: Optional[int] = None
"""Total rows matching the query before pagination (null when not computed)."""

if TYPE_CHECKING:
# Some versions of Pydantic <2.8.0 have a bug and don’t allow assigning a
# value to this field, so for compatibility we avoid doing it at runtime.
__pydantic_extra__: Dict[str, object] = FieldInfo(init=False) # pyright: ignore[reportIncompatibleVariableOverride]

# Stub to indicate that arbitrary properties are accepted.
# To access properties that are not valid identifiers you can use `getattr`, e.g.
# `getattr(obj, '$type')`
def __getattr__(self, attr: str) -> object: ...
else:
__pydantic_extra__: Dict[str, object]


class YoutubeGetSummaryResponse(BaseModel):
data: Data
"""How much of youtube.com the rollups can speak for."""

info: Dict[str, object]
info: Info
"""Summary report metadata."""
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,10 @@ class YoutubeGetVideosParams(TypedDict, total=False):
source_types: Optional[List[Literal["video", "short", "channel", "playlist", "other"]]]
"""
Limit results to YouTube source types: `video`, `short`, `channel`, `playlist`,
or `other`. Omit to include every source type.
or `other`. Omit to include `video` and `short` with the default
`attribution='attributed'`; `unattributed` and `all` widen the default to all
five source types. Requests containing `other` with `attribution='attributed'`
are rejected.
"""


Expand Down
Loading
Loading