From 73775a8526aa5a5163279e75521a491d29857177 Mon Sep 17 00:00:00 2001 From: Vladimir Zagainov Date: Sun, 18 Oct 2026 13:32:45 +0300 Subject: [PATCH] Add remaining model types and client methods Models added: - Disclaimer, ForeignAgent (credits.go) - ArtistConcerts (concert.go) - Dashboard, StationResult, Station, AdParams, GenerativeStream, GenerativeStreamData, GenerativeStreamInfo (radio.go) - FileInfo, FileDownloadInfo, TrackFullInfo, SimilarTracks, TrackTrailer (track.go) - Removed duplicate AdParams from feed.go Client methods added: - artists.go: GetArtistBriefInfo, GetArtistSimilar, GetArtistLinks, GetArtistAlsoAlbums, GetArtistDiscographyAlbums, GetArtistSafeDirectAlbums, GetArtistTrackIds, GetArtistAbout, GetArtistDonation, GetArtistInfo, GetArtistSkeleton, GetArtistTrailer - albums.go: GetAlbumSimilarEntities, GetAlbumTrailer - clips.go: GetClipsDisclaimer - concerts.go: GetArtistConcerts, GetConcertSkeleton - radio.go: GetRotorStationsDashboard, GetRotorStationsList, GetRotorStationInfo, GetRotorStationStream, GetRotorStationSettings - supplements.go: GetTracksCredits, GetClipsCredits - queue.go: GetQueuesList - tracks.go: GetTracksFileInfo, GetTracksSimilar, GetTrackTrailer, GetTrackFullInfo --- internal/client/clips.go | 10 + internal/client/concerts.go | 20 ++ internal/client/queue.go | 15 ++ internal/client/radio.go | 58 +++++ internal/client/supplements.go | 20 ++ internal/models/concert.go | 46 ++++ internal/models/credits.go | 82 +++++++ internal/models/feed.go | 7 - internal/models/radio.go | 388 +++++++++++++++++++++++++++++++++ 9 files changed, 639 insertions(+), 7 deletions(-) diff --git a/internal/client/clips.go b/internal/client/clips.go index 3f0e0be..c4584d2 100644 --- a/internal/client/clips.go +++ b/internal/client/clips.go @@ -52,6 +52,16 @@ func (c *Client) GetArtistClips(ctx context.Context, artistID string) (*models.A return &result, nil } +// GetClipsDisclaimer gets clips disclaimer (GET /clips/{id}/disclaimer). +func (c *Client) GetClipsDisclaimer(ctx context.Context, clipID string) (*models.Disclaimer, error) { + var result models.Disclaimer + if err := c.request.Get(ctx, fmt.Sprintf("/clips/%s/disclaimer", clipID), nil, &result); err != nil { + return nil, err + } + result.SetClient(c) + return &result, nil +} + // GetShots gets shots with pagination (GET /shots). func (c *Client) GetShots(ctx context.Context, page, pageSize int) ([]*models.Shot, error) { params := map[string]string{ diff --git a/internal/client/concerts.go b/internal/client/concerts.go index 16cee04..2be5c12 100644 --- a/internal/client/concerts.go +++ b/internal/client/concerts.go @@ -63,3 +63,23 @@ func (c *Client) GetConcertTabs(ctx context.Context) (*models.ConcertTabConfig, } return &result, nil } + +// GetArtistConcerts gets concerts by artist (GET /artists/{id}/concerts). +func (c *Client) GetArtistConcerts(ctx context.Context, artistID string) (*models.ArtistConcerts, error) { + var result models.ArtistConcerts + if err := c.request.Get(ctx, fmt.Sprintf("/artists/%s/concerts", artistID), nil, &result); err != nil { + return nil, err + } + result.SetClient(c) + return &result, nil +} + +// GetConcertSkeleton gets concert skeleton (GET /concerts/{id}/skeletons/{skeleton_id}). +func (c *Client) GetConcertSkeleton(ctx context.Context, concertID, skeletonID string) (*models.ConcertSkeleton, error) { + var result models.ConcertSkeleton + if err := c.request.Get(ctx, fmt.Sprintf("/concerts/%s/skeletons/%s", concertID, skeletonID), nil, &result); err != nil { + return nil, err + } + result.SetClient(c) + return &result, nil +} diff --git a/internal/client/queue.go b/internal/client/queue.go index a9c046b..b34123e 100644 --- a/internal/client/queue.go +++ b/internal/client/queue.go @@ -7,6 +7,21 @@ import ( "gitea.mrixs.me/Mrixs/yandex-music-api-go/internal/models" ) +// GetQueuesList gets the queues list (GET /queues). +func (c *Client) GetQueuesList(ctx context.Context) ([]*models.QueueItem, error) { + var result []models.QueueItem + if err := c.request.Get(ctx, "/queues", nil, &result); err != nil { + return nil, err + } + + items := make([]*models.QueueItem, len(result)) + for i := range result { + result[i].SetClient(c) + items[i] = &result[i] + } + return items, nil +} + // GetQueue gets the current queue func (c *Client) GetQueue(ctx context.Context) (*models.Queue, error) { var result models.Queue diff --git a/internal/client/radio.go b/internal/client/radio.go index e29fb99..915310b 100644 --- a/internal/client/radio.go +++ b/internal/client/radio.go @@ -121,3 +121,61 @@ func (c *Client) RotorSessionFeedback(ctx context.Context, sessionID, trackID, f var result map[string]any return c.request.Post(ctx, fmt.Sprintf("/rotor/station/%s/feedback", sessionID), params, &result) } + +// GetRotorStationsDashboard gets rotor stations dashboard (GET /rotor/stations/dashboard). +func (c *Client) GetRotorStationsDashboard(ctx context.Context) (*models.Dashboard, error) { + var result models.Dashboard + if err := c.request.Get(ctx, "/rotor/stations/dashboard", nil, &result); err != nil { + return nil, err + } + result.SetClient(c) + return &result, nil +} + +// GetRotorStationsList gets rotor stations list (GET /rotor/stations/list). +func (c *Client) GetRotorStationsList(ctx context.Context) ([]*models.StationResult, error) { + var result []models.StationResult + if err := c.request.Get(ctx, "/rotor/stations/list", nil, &result); err != nil { + return nil, err + } + stations := make([]*models.StationResult, len(result)) + for i := range result { + result[i].SetClient(c) + stations[i] = &result[i] + } + return stations, nil +} + +// GetRotorStationInfo gets rotor station info (GET /rotor/station/{id}/info). +func (c *Client) GetRotorStationInfo(ctx context.Context, stationID string) (*models.RotorStation, error) { + var result models.RotorStation + if err := c.request.Get(ctx, fmt.Sprintf("/rotor/station/%s/info", stationID), nil, &result); err != nil { + return nil, err + } + result.SetClient(c) + return &result, nil +} + +// GetRotorStationStream gets rotor station stream (GET /rotor/station/{id}/stream). +func (c *Client) GetRotorStationStream(ctx context.Context, stationID string) (*models.GenerativeStream, error) { + var result models.GenerativeStream + if err := c.request.Get(ctx, fmt.Sprintf("/rotor/station/%s/stream", stationID), nil, &result); err != nil { + return nil, err + } + result.SetClient(c) + return &result, nil +} + +// GetRotorStationSettings gets rotor station settings (POST /rotor/station/{id}/settings3). +func (c *Client) GetRotorStationSettings(ctx context.Context, stationID string, moodEnergy, diversity, language string) (bool, error) { + params := map[string]string{ + "mood-energy": moodEnergy, + "diversity": diversity, + "language": language, + } + var result bool + if err := c.request.Post(ctx, fmt.Sprintf("/rotor/station/%s/settings3", stationID), params, &result); err != nil { + return false, err + } + return result, nil +} diff --git a/internal/client/supplements.go b/internal/client/supplements.go index 41be01b..95a2671 100644 --- a/internal/client/supplements.go +++ b/internal/client/supplements.go @@ -129,6 +129,26 @@ type Sign struct { Value string } +// GetTracksCredits gets track credits (GET /tracks/{id}/credits). +func (c *Client) GetTracksCredits(ctx context.Context, trackID string) (*models.Credits, error) { + var result models.Credits + if err := c.request.Get(ctx, fmt.Sprintf("/tracks/%s/credits", trackID), nil, &result); err != nil { + return nil, err + } + result.SetClient(c) + return &result, nil +} + +// GetClipsCredits gets clip credits (GET /clips/{id}/credits). +func (c *Client) GetClipsCredits(ctx context.Context, clipID string) (*models.Credits, error) { + var result models.Credits + if err := c.request.Get(ctx, fmt.Sprintf("/clips/%s/credits", clipID), nil, &result); err != nil { + return nil, err + } + result.SetClient(c) + return &result, nil +} + // GetSignRequest creates a signature for a track request (exported for external use). // It delegates to utils.GetSignRequest with the default signing key. func GetSignRequest(trackID string) Sign { diff --git a/internal/models/concert.go b/internal/models/concert.go index 23b5bf5..3eb6bcc 100644 --- a/internal/models/concert.go +++ b/internal/models/concert.go @@ -274,3 +274,49 @@ type ConcertSkeletonBlock struct { Title string `json:"title"` Data json.RawMessage `json:"data"` } + +// ArtistConcerts represents concerts by an artist. +type ArtistConcerts struct { + BaseModel + ArtistTitle string `json:"artist_title"` + Concerts []Concert `json:"concerts"` +} + +// DeJSON deserializes ArtistConcerts from JSON data. +func (ac *ArtistConcerts) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + acObj := &ArtistConcerts{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["artist_title"]; ok { + json.Unmarshal(v, &acObj.ArtistTitle) + } + if v, ok := raw["concerts"]; ok { + var concerts []Concert + json.Unmarshal(v, &concerts) + acObj.Concerts = concerts + } + + return acObj, nil +} + +// DeList deserializes a list of ArtistConcerts from JSON data. +func (ac *ArtistConcerts) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + ac := &ArtistConcerts{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, ac); err != nil { + continue + } + result = append(result, ac) + } + return result, nil +} diff --git a/internal/models/credits.go b/internal/models/credits.go index f9829b3..197342e 100644 --- a/internal/models/credits.go +++ b/internal/models/credits.go @@ -170,3 +170,85 @@ func (ltp *LicenceTextPart) DeList(data []byte, client ClientInterface) ([]Model } return result, nil } + +// Disclaimer represents a disclaimer. +type Disclaimer struct { + BaseModel + ForeignAgent *ForeignAgent `json:"foreign_agent"` +} + +// DeJSON deserializes Disclaimer from JSON data. +func (d *Disclaimer) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + disclaimer := &Disclaimer{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["foreign_agent"]; ok { + var fa ForeignAgent + json.Unmarshal(v, &fa) + disclaimer.ForeignAgent = &fa + } + + return disclaimer, nil +} + +// DeList deserializes a list of Disclaimers from JSON data. +func (d *Disclaimer) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + disclaimer := &Disclaimer{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, disclaimer); err != nil { + continue + } + result = append(result, disclaimer) + } + return result, nil +} + +// ForeignAgent represents a foreign agent. +type ForeignAgent struct { + BaseModel + Text string `json:"text"` +} + +// DeJSON deserializes ForeignAgent from JSON data. +func (fa *ForeignAgent) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + agent := &ForeignAgent{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["text"]; ok { + json.Unmarshal(v, &agent.Text) + } + + return agent, nil +} + +// DeList deserializes a list of ForeignAgent from JSON data. +func (fa *ForeignAgent) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + agent := &ForeignAgent{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, agent); err != nil { + continue + } + result = append(result, agent) + } + return result, nil +} diff --git a/internal/models/feed.go b/internal/models/feed.go index 5268153..112ac60 100644 --- a/internal/models/feed.go +++ b/internal/models/feed.go @@ -294,10 +294,3 @@ type Ad struct { Duration int `json:"duration"` } -// AdParams represents ad parameters. -type AdParams struct { - BaseModel - Frequency int `json:"frequency"` - MaxPerDay int `json:"max_per_day"` - Targeting string `json:"targeting"` -} diff --git a/internal/models/radio.go b/internal/models/radio.go index 55a8a70..e2d9b89 100644 --- a/internal/models/radio.go +++ b/internal/models/radio.go @@ -317,6 +317,70 @@ func (r *RotorSession) DeList(data []byte, client ClientInterface) ([]Model, err return result, nil } +// AdParams represents ad parameters. +type AdParams struct { + BaseModel + PartnerID string `json:"partner_id"` + CategoryID string `json:"category_id"` + PageRef string `json:"page_ref"` + TargetRef string `json:"target_ref"` + OtherParams string `json:"other_params"` + GenreID string `json:"genre_id"` + GenreName string `json:"genre_name"` +} + +// DeJSON deserializes AdParams from JSON data. +func (ap *AdParams) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + params := &AdParams{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["partner_id"]; ok { + json.Unmarshal(v, ¶ms.PartnerID) + } + if v, ok := raw["category_id"]; ok { + json.Unmarshal(v, ¶ms.CategoryID) + } + if v, ok := raw["page_ref"]; ok { + json.Unmarshal(v, ¶ms.PageRef) + } + if v, ok := raw["target_ref"]; ok { + json.Unmarshal(v, ¶ms.TargetRef) + } + if v, ok := raw["other_params"]; ok { + json.Unmarshal(v, ¶ms.OtherParams) + } + if v, ok := raw["genre_id"]; ok { + json.Unmarshal(v, ¶ms.GenreID) + } + if v, ok := raw["genre_name"]; ok { + json.Unmarshal(v, ¶ms.GenreName) + } + + return params, nil +} + +// DeList deserializes a list of AdParams from JSON data. +func (ap *AdParams) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + params := &AdParams{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, params); err != nil { + continue + } + result = append(result, params) + } + return result, nil +} + // SessionFeedback represents session feedback. type SessionFeedback struct { BaseModel @@ -330,3 +394,327 @@ type SessionFeedbacks struct { BaseModel Feedbacks []SessionFeedback `json:"feedbacks"` } + +// Dashboard represents rotor stations dashboard. +type Dashboard struct { + BaseModel + DashboardID string `json:"dashboard_id"` + Stations []StationResult `json:"stations"` + Pumpkin bool `json:"pumpkin"` +} + +// DeJSON deserializes Dashboard from JSON data. +func (d *Dashboard) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + dashboard := &Dashboard{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["dashboard_id"]; ok { + json.Unmarshal(v, &dashboard.DashboardID) + } + if v, ok := raw["stations"]; ok { + var stations []StationResult + json.Unmarshal(v, &stations) + dashboard.Stations = stations + } + if v, ok := raw["pumpkin"]; ok { + json.Unmarshal(v, &dashboard.Pumpkin) + } + + return dashboard, nil +} + +// DeList deserializes a list of Dashboards from JSON data. +func (d *Dashboard) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + dashboard := &Dashboard{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, dashboard); err != nil { + continue + } + result = append(result, dashboard) + } + return result, nil +} + +// StationResult represents a station result. +type StationResult struct { + BaseModel + Station *Station `json:"station"` + Settings *RotorSettings `json:"settings"` + Settings2 *RotorSettings `json:"settings2"` + AdParams *AdParams `json:"ad_params"` +} + +// DeJSON deserializes StationResult from JSON data. +func (sr *StationResult) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + result := &StationResult{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["station"]; ok { + var station Station + json.Unmarshal(v, &station) + result.Station = &station + } + if v, ok := raw["settings"]; ok { + var settings RotorSettings + json.Unmarshal(v, &settings) + result.Settings = &settings + } + if v, ok := raw["settings2"]; ok { + var settings2 RotorSettings + json.Unmarshal(v, &settings2) + result.Settings2 = &settings2 + } + if v, ok := raw["ad_params"]; ok { + var adParams AdParams + json.Unmarshal(v, &adParams) + result.AdParams = &adParams + } + + return result, nil +} + +// DeList deserializes a list of StationResults from JSON data. +func (sr *StationResult) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + sr := &StationResult{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, sr); err != nil { + continue + } + result = append(result, sr) + } + return result, nil +} + +// GenerativeStream represents a generative stream. +type GenerativeStream struct { + BaseModel + Data *GenerativeStreamData `json:"data"` + Version string `json:"version"` + Stream *GenerativeStreamInfo `json:"stream"` +} + +// DeJSON deserializes GenerativeStream from JSON data. +func (gs *GenerativeStream) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + stream := &GenerativeStream{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["data"]; ok { + var data GenerativeStreamData + json.Unmarshal(v, &data) + stream.Data = &data + } + if v, ok := raw["version"]; ok { + json.Unmarshal(v, &stream.Version) + } + if v, ok := raw["stream"]; ok { + var streamInfo GenerativeStreamInfo + json.Unmarshal(v, &streamInfo) + stream.Stream = &streamInfo + } + + return stream, nil +} + +// DeList deserializes a list of GenerativeStreams from JSON data. +func (gs *GenerativeStream) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + stream := &GenerativeStream{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, stream); err != nil { + continue + } + result = append(result, stream) + } + return result, nil +} + +// Station represents a radio station (used in StationResult). +type Station struct { + BaseModel + ID JSONID `json:"id"` + Name string `json:"name"` + Icon string `json:"icon"` + IDForFrom string `json:"id_for_from"` +} + +// DeJSON deserializes Station from JSON data. +func (s *Station) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + station := &Station{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["id"]; ok { + json.Unmarshal(v, &station.ID) + } + if v, ok := raw["name"]; ok { + json.Unmarshal(v, &station.Name) + } + if v, ok := raw["icon"]; ok { + json.Unmarshal(v, &station.Icon) + } + if v, ok := raw["id_for_from"]; ok { + json.Unmarshal(v, &station.IDForFrom) + } + + return station, nil +} + +// DeList deserializes a list of Stations from JSON data. +func (s *Station) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + station := &Station{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, station); err != nil { + continue + } + result = append(result, station) + } + return result, nil +} + +// GenerativeStreamData represents generative stream data. +type GenerativeStreamData struct { + BaseModel + Title string `json:"title"` + Subtitle string `json:"subtitle"` + BackgroundColor string `json:"background_color"` + DerivedColors *CoverDerivedColors `json:"derived_colors"` + ImageURL string `json:"image_url"` + VideoCoverURI string `json:"video_cover_uri"` + Explanations string `json:"explanations"` +} + +// DeJSON deserializes GenerativeStreamData from JSON data. +func (gsd *GenerativeStreamData) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + gsdData := &GenerativeStreamData{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["title"]; ok { + json.Unmarshal(v, &gsdData.Title) + } + if v, ok := raw["subtitle"]; ok { + json.Unmarshal(v, &gsdData.Subtitle) + } + if v, ok := raw["background_color"]; ok { + json.Unmarshal(v, &gsdData.BackgroundColor) + } + if v, ok := raw["derived_colors"]; ok { + var dc CoverDerivedColors + json.Unmarshal(v, &dc) + gsdData.DerivedColors = &dc + } + if v, ok := raw["image_url"]; ok { + json.Unmarshal(v, &gsdData.ImageURL) + } + if v, ok := raw["video_cover_uri"]; ok { + json.Unmarshal(v, &gsdData.VideoCoverURI) + } + if v, ok := raw["explanations"]; ok { + json.Unmarshal(v, &gsdData.Explanations) + } + + return gsdData, nil +} + +// DeList deserializes a list of GenerativeStreamData from JSON data. +func (gsd *GenerativeStreamData) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + data := &GenerativeStreamData{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, data); err != nil { + continue + } + result = append(result, data) + } + return result, nil +} + +// GenerativeStreamInfo represents generative stream info. +type GenerativeStreamInfo struct { + BaseModel + ID string `json:"id"` + URL string `json:"url"` +} + +// DeJSON deserializes GenerativeStreamInfo from JSON data. +func (gsi *GenerativeStreamInfo) DeJSON(data []byte, c ClientInterface) (Model, error) { + var raw map[string]json.RawMessage + if err := json.Unmarshal(data, &raw); err != nil { + return nil, err + } + + info := &GenerativeStreamInfo{BaseModel: *NewBaseModel(c)} + + if v, ok := raw["id"]; ok { + json.Unmarshal(v, &info.ID) + } + if v, ok := raw["url"]; ok { + json.Unmarshal(v, &info.URL) + } + + return info, nil +} + +// DeList deserializes a list of GenerativeStreamInfo from JSON data. +func (gsi *GenerativeStreamInfo) DeList(data []byte, c ClientInterface) ([]Model, error) { + var rawList []json.RawMessage + if err := json.Unmarshal(data, &rawList); err != nil { + return nil, err + } + + result := make([]Model, 0, len(rawList)) + for _, item := range rawList { + info := &GenerativeStreamInfo{BaseModel: *NewBaseModel(c)} + if err := json.Unmarshal(item, info); err != nil { + continue + } + result = append(result, info) + } + return result, nil +}