[GH-ISSUE #308] Update metadata endpoint #204

Closed
opened 2026-02-27 19:29:23 +03:00 by kerem · 7 comments
Owner

Originally created by @ashthespy on GitHub (Mar 15, 2019).
Original GitHub issue: https://github.com/librespot-org/librespot/issues/308

Opening up this issue so it's easier to track than gitter ;-)
Currently we still use the hm://metadata/3/xx endpoints, whereas the official clients use 4.
Updating to the v4 endpoint will be a prerequisite for podcast support.
I have extracted the following definitions from the official client.

metadata.proto
syntax = "proto2";

package spotify.metadata.proto;
message Artist {
    optional bytes gid = 1;
    optional string name = 2;
    optional sint32 popularity = 3;
    repeated TopTracks top_track = 4;
    repeated AlbumGroup album_group = 5;
    repeated AlbumGroup single_group = 6;
    repeated AlbumGroup compilation_group = 7;
    repeated AlbumGroup appears_on_group = 8;
    repeated string genre = 9;
    repeated ExternalId external_id = 10;
    repeated Image portrait = 11;
    repeated Biography biography = 12;
    repeated ActivityPeriod activity_period = 13;
    repeated Restriction restriction = 14;
    repeated Artist related = 15;
    optional bool is_portrait_album_cover = 16;
    optional ImageGroup portrait_group = 17;
    repeated SalePeriod sale_period = 18;
    repeated Availability availability = 20;
}

message Album {
    optional bytes gid = 1;
    optional string name = 2;
    repeated Artist artist = 3;
    
    optional Type type = 4;
    enum Type {
        ALBUM = 1;
        SINGLE = 2;
        COMPILATION = 3;
        EP = 4;
        AUDIOBOOK = 5;
        PODCAST = 6;
    }
    
    optional string label = 5;
    optional Date date = 6;
    optional sint32 popularity = 7;
    repeated string genre = 8;
    repeated Image cover = 9;
    repeated ExternalId external_id = 10;
    repeated Disc disc = 11;
    repeated string review = 12;
    repeated Copyright copyright = 13;
    repeated Restriction restriction = 14;
    repeated Album related = 15;
    repeated SalePeriod sale_period = 16;
    optional ImageGroup cover_group = 17;
    optional string original_title = 18;
    optional string version_title = 19;
    optional string type_str = 20;
    repeated Availability availability = 23;
}

message Track {
    optional bytes gid = 1;
    optional string name = 2;
    optional Album album = 3;
    repeated Artist artist = 4;
    optional sint32 number = 5;
    optional sint32 disc_number = 6;
    optional sint32 duration = 7;
    optional sint32 popularity = 8;
    optional bool explicit = 9;
    repeated ExternalId external_id = 10;
    repeated Restriction restriction = 11;
    repeated AudioFile file = 12;
    repeated Track alternative = 13;
    repeated SalePeriod sale_period = 14;
    repeated AudioFile preview = 15;
    repeated string tags = 16;
    optional int64 earliest_live_timestamp = 17;
    optional bool has_lyrics = 18;
    repeated Availability availability = 19;
    optional Licensor licensor = 21;
}

message Show {
    optional bytes gid = 1;
    optional string name = 2;
    optional string description = 64;
    optional sint32 deprecated_popularity = 65 [deprecated = true];
    optional string publisher = 66;
    optional string language = 67;
    optional bool explicit = 68;
    optional ImageGroup cover_image = 69;
    repeated Episode episode = 70;
    repeated Copyright copyright = 71;
    repeated Restriction restriction = 72;
    repeated string keyword = 73;
    
    optional MediaType media_type = 74;
    enum MediaType {
        MIXED = 0;
        AUDIO = 1;
        VIDEO = 2;
    }
    
    optional ConsumptionOrder consumption_order = 75;
    enum ConsumptionOrder {
        SEQUENTIAL = 1;
        EPISODIC = 2;
        RECENT = 3;
    }
    
    repeated Availability availability = 78;
}

message Episode {
    optional bytes gid = 1;
    optional string name = 2;
    optional sint32 duration = 7;
    repeated AudioFile audio = 12;
    optional string description = 64;
    optional sint32 number = 65;
    optional Date publish_time = 66;
    optional sint32 deprecated_popularity = 67 [deprecated = true];
    optional ImageGroup cover_image = 68;
    optional string language = 69;
    optional bool explicit = 70;
    optional Show show = 71;
    repeated VideoFile video = 72;
    repeated VideoFile video_preview = 73;
    repeated AudioFile audio_preview = 74;
    repeated Restriction restriction = 75;
    optional ImageGroup freeze_frame = 76;
    repeated string keyword = 77;
    optional bool allow_background_playback = 81;
    repeated Availability availability = 82;
    optional string external_url = 83;
}

message Licensor {
    optional bytes uuid = 1;
}

message TopTracks {
    optional string country = 1;
    repeated Track track = 2;
}

message ActivityPeriod {
    optional sint32 start_year = 1;
    optional sint32 end_year = 2;
    optional sint32 decade = 3;
}

message AlbumGroup {
    repeated Album album = 1;
}

message Date {
    optional sint32 year = 1;
    optional sint32 month = 2;
    optional sint32 day = 3;
    optional sint32 hour = 4;
    optional sint32 minute = 5;
}

message Image {
    optional bytes file_id = 1;
    
    optional Size size = 2;
    enum Size {
        DEFAULT = 0;
        SMALL = 1;
        LARGE = 2;
        XLARGE = 3;
    }
    
    optional sint32 width = 3;
    optional sint32 height = 4;
}

message ImageGroup {
    repeated Image image = 1;
}

message Biography {
    optional string text = 1;
    repeated Image portrait = 2;
    repeated ImageGroup portrait_group = 3;
}

message Disc {
    optional sint32 number = 1;
    optional string name = 2;
    repeated Track track = 3;
}

message Copyright {
    optional Type type = 1;
    enum Type {
        P = 0;
        C = 1;
    }
    
    optional string text = 2;
}

message Restriction {
    repeated Catalogue catalogue = 1;
    enum Catalogue {
        AD = 0;
        SUBSCRIPTION = 1;
        CATALOGUE_ALL = 2;
        SHUFFLE = 3;
        COMMERCIAL = 4;
    }
    
    optional Type type = 4;
    enum Type {
        STREAMING = 0;
    }
    
    repeated string catalogue_str = 5;
    
    oneof country_restriction {
        string countries_allowed = 2;
        string countries_forbidden = 3;
    }
}

message Availability {
    repeated string catalogue_str = 1;
    optional Date start = 2;
}

message SalePeriod {
    repeated Restriction restriction = 1;
    optional Date start = 2;
    optional Date end = 3;
}

message ExternalId {
    optional string type = 1;
    optional string id = 2;
}

message AudioFile {
    optional bytes file_id = 1;
    
    optional Format format = 2;
    enum Format {
        OGG_VORBIS_96 = 0;
        OGG_VORBIS_160 = 1;
        OGG_VORBIS_320 = 2;
        MP3_256 = 3;
        MP3_320 = 4;
        MP3_160 = 5;
        MP3_96 = 6;
        MP3_160_ENC = 7;
        AAC_24 = 8;
        AAC_48 = 9;
    }
}

message VideoFile {
    optional bytes file_id = 1;
}

Originally created by @ashthespy on GitHub (Mar 15, 2019). Original GitHub issue: https://github.com/librespot-org/librespot/issues/308 Opening up this issue so it's easier to track than gitter ;-) Currently we still use the `hm://metadata/3/xx` endpoints, whereas the official clients use `4`. Updating to the v4 endpoint will be a prerequisite for podcast support. I have extracted the following definitions from the official client. <details> <summary>metadata.proto</summary> ```protobuf syntax = "proto2"; package spotify.metadata.proto; message Artist { optional bytes gid = 1; optional string name = 2; optional sint32 popularity = 3; repeated TopTracks top_track = 4; repeated AlbumGroup album_group = 5; repeated AlbumGroup single_group = 6; repeated AlbumGroup compilation_group = 7; repeated AlbumGroup appears_on_group = 8; repeated string genre = 9; repeated ExternalId external_id = 10; repeated Image portrait = 11; repeated Biography biography = 12; repeated ActivityPeriod activity_period = 13; repeated Restriction restriction = 14; repeated Artist related = 15; optional bool is_portrait_album_cover = 16; optional ImageGroup portrait_group = 17; repeated SalePeriod sale_period = 18; repeated Availability availability = 20; } message Album { optional bytes gid = 1; optional string name = 2; repeated Artist artist = 3; optional Type type = 4; enum Type { ALBUM = 1; SINGLE = 2; COMPILATION = 3; EP = 4; AUDIOBOOK = 5; PODCAST = 6; } optional string label = 5; optional Date date = 6; optional sint32 popularity = 7; repeated string genre = 8; repeated Image cover = 9; repeated ExternalId external_id = 10; repeated Disc disc = 11; repeated string review = 12; repeated Copyright copyright = 13; repeated Restriction restriction = 14; repeated Album related = 15; repeated SalePeriod sale_period = 16; optional ImageGroup cover_group = 17; optional string original_title = 18; optional string version_title = 19; optional string type_str = 20; repeated Availability availability = 23; } message Track { optional bytes gid = 1; optional string name = 2; optional Album album = 3; repeated Artist artist = 4; optional sint32 number = 5; optional sint32 disc_number = 6; optional sint32 duration = 7; optional sint32 popularity = 8; optional bool explicit = 9; repeated ExternalId external_id = 10; repeated Restriction restriction = 11; repeated AudioFile file = 12; repeated Track alternative = 13; repeated SalePeriod sale_period = 14; repeated AudioFile preview = 15; repeated string tags = 16; optional int64 earliest_live_timestamp = 17; optional bool has_lyrics = 18; repeated Availability availability = 19; optional Licensor licensor = 21; } message Show { optional bytes gid = 1; optional string name = 2; optional string description = 64; optional sint32 deprecated_popularity = 65 [deprecated = true]; optional string publisher = 66; optional string language = 67; optional bool explicit = 68; optional ImageGroup cover_image = 69; repeated Episode episode = 70; repeated Copyright copyright = 71; repeated Restriction restriction = 72; repeated string keyword = 73; optional MediaType media_type = 74; enum MediaType { MIXED = 0; AUDIO = 1; VIDEO = 2; } optional ConsumptionOrder consumption_order = 75; enum ConsumptionOrder { SEQUENTIAL = 1; EPISODIC = 2; RECENT = 3; } repeated Availability availability = 78; } message Episode { optional bytes gid = 1; optional string name = 2; optional sint32 duration = 7; repeated AudioFile audio = 12; optional string description = 64; optional sint32 number = 65; optional Date publish_time = 66; optional sint32 deprecated_popularity = 67 [deprecated = true]; optional ImageGroup cover_image = 68; optional string language = 69; optional bool explicit = 70; optional Show show = 71; repeated VideoFile video = 72; repeated VideoFile video_preview = 73; repeated AudioFile audio_preview = 74; repeated Restriction restriction = 75; optional ImageGroup freeze_frame = 76; repeated string keyword = 77; optional bool allow_background_playback = 81; repeated Availability availability = 82; optional string external_url = 83; } message Licensor { optional bytes uuid = 1; } message TopTracks { optional string country = 1; repeated Track track = 2; } message ActivityPeriod { optional sint32 start_year = 1; optional sint32 end_year = 2; optional sint32 decade = 3; } message AlbumGroup { repeated Album album = 1; } message Date { optional sint32 year = 1; optional sint32 month = 2; optional sint32 day = 3; optional sint32 hour = 4; optional sint32 minute = 5; } message Image { optional bytes file_id = 1; optional Size size = 2; enum Size { DEFAULT = 0; SMALL = 1; LARGE = 2; XLARGE = 3; } optional sint32 width = 3; optional sint32 height = 4; } message ImageGroup { repeated Image image = 1; } message Biography { optional string text = 1; repeated Image portrait = 2; repeated ImageGroup portrait_group = 3; } message Disc { optional sint32 number = 1; optional string name = 2; repeated Track track = 3; } message Copyright { optional Type type = 1; enum Type { P = 0; C = 1; } optional string text = 2; } message Restriction { repeated Catalogue catalogue = 1; enum Catalogue { AD = 0; SUBSCRIPTION = 1; CATALOGUE_ALL = 2; SHUFFLE = 3; COMMERCIAL = 4; } optional Type type = 4; enum Type { STREAMING = 0; } repeated string catalogue_str = 5; oneof country_restriction { string countries_allowed = 2; string countries_forbidden = 3; } } message Availability { repeated string catalogue_str = 1; optional Date start = 2; } message SalePeriod { repeated Restriction restriction = 1; optional Date start = 2; optional Date end = 3; } message ExternalId { optional string type = 1; optional string id = 2; } message AudioFile { optional bytes file_id = 1; optional Format format = 2; enum Format { OGG_VORBIS_96 = 0; OGG_VORBIS_160 = 1; OGG_VORBIS_320 = 2; MP3_256 = 3; MP3_320 = 4; MP3_160 = 5; MP3_96 = 6; MP3_160_ENC = 7; AAC_24 = 8; AAC_48 = 9; } } message VideoFile { optional bytes file_id = 1; } ``` </details>
kerem closed this issue 2026-02-27 19:29:24 +03:00
Author
Owner

@sashahilton00 commented on GitHub (Mar 16, 2019):

@ashthespy have you added this in a branch of yours that you're planning to merge, or shall I just add it and create a pr? I believe there were some other proto defs that we could update as well whilst we're at it

<!-- gh-comment-id:473531021 --> @sashahilton00 commented on GitHub (Mar 16, 2019): @ashthespy have you added this in a branch of yours that you're planning to merge, or shall I just add it and create a pr? I believe there were some other proto defs that we could update as well whilst we're at it
Author
Owner

@ashthespy commented on GitHub (Mar 21, 2019):

I will have to look - I recall updating it while playing around with podcast support. I also recall that restrictions are handled differently on this endpoint, and needed some investigating. Will look at it when I get home this weekend..

<!-- gh-comment-id:475385314 --> @ashthespy commented on GitHub (Mar 21, 2019): I will have to look - I recall updating it while playing around with podcast support. I also recall that restrictions are handled differently on this endpoint, and needed some investigating. Will look at it when I get home this weekend..
Author
Owner

@ashthespy commented on GitHub (Mar 24, 2019):

Some findings so far: https://gist.github.com/ashthespy/b748a5e0538b2e405c04dcb66fb3cd54
tl;dr
v4 doesn't give you any restrictions or alternatives - either it gives you the file list or not.

<!-- gh-comment-id:475968191 --> @ashthespy commented on GitHub (Mar 24, 2019): Some findings so far: https://gist.github.com/ashthespy/b748a5e0538b2e405c04dcb66fb3cd54 tl;dr `v4` doesn't give you any `restrictions` or `alternatives` - either it gives you the file list or not.
Author
Owner

@mainrs commented on GitHub (Jul 2, 2019):

Out of curiosity, how do you guys get access to the protocols? :)

<!-- gh-comment-id:507662176 --> @mainrs commented on GitHub (Jul 2, 2019): Out of curiosity, how do you guys get access to the protocols? :)
Author
Owner

@devgianlu commented on GitHub (Jul 2, 2019):

We dump them from the executables.

<!-- gh-comment-id:507662499 --> @devgianlu commented on GitHub (Jul 2, 2019): We dump them from the executables.
Author
Owner

@mainrs commented on GitHub (Jul 2, 2019):

@devgianlu you mean the desktop client? Aren't those written using electron? I thought that proto files get somehow converted to JS and mangled too...

<!-- gh-comment-id:507662981 --> @mainrs commented on GitHub (Jul 2, 2019): @devgianlu you mean the desktop client? Aren't those written using electron? I thought that proto files get somehow converted to JS and mangled too...
Author
Owner

@devgianlu commented on GitHub (Jul 2, 2019):

The desktop client is written in C (++, I think) and you can totally salvage the proto files with this tool.

<!-- gh-comment-id:507663307 --> @devgianlu commented on GitHub (Jul 2, 2019): The desktop client is written in C (++, I think) and you can totally salvage the proto files with [this tool](https://github.com/HearthSim/proto-extractor#binary-proto-extraction).
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/librespot#204
No description provided.