getSong method
Returns metadata and streaming information about a song or video.
videoId
Video id.signatureTimestamp
Provide the current YouTubesignatureTimestamp
. If not provided, a default value will be used, which might result in invalid streaming URLs.
Returns Map with song metadata.
Example:
{
"playabilityStatus": {
"status": "OK",
"playableInEmbed": true,
"audioOnlyPlayability": {
"audioOnlyPlayabilityRenderer": {
"trackingParams": "CAEQx2kiEwiuv9X5i5H1AhWBvlUKHRoZAHk=",
"audioOnlyAvailability": "FEATURE_AVAILABILITY_ALLOWED"
}
},
"miniplayer": {
"miniplayerRenderer": {
"playbackMode": "PLAYBACK_MODE_ALLOW"
}
},
"contextParams": "Q0FBU0FnZ0M="
},
"streamingData": {
"expiresInSeconds": "21540",
"adaptiveFormats": [
{
"itag": 140,
"url": "https://rr1---sn-h0jelnez.c.youtube.com/videoplayback?expire=1641080272...",
"mimeType": "audio/mp4; codecs=\"mp4a.40.2\"",
"bitrate": 131007,
"initRange": {
"start": "0",
"end": "667"
},
"indexRange": {
"start": "668",
"end": "999"
},
"lastModified": "1620321966927796",
"contentLength": "3967382",
"quality": "tiny",
"projectionType": "RECTANGULAR",
"averageBitrate": 129547,
"highReplication": true,
"audioQuality": "AUDIO_QUALITY_MEDIUM",
"approxDurationMs": "245000",
"audioSampleRate": "44100",
"audioChannels": 2,
"loudnessDb": -1.3000002
}
]
},
"playbackTracking": {
"videostatsPlaybackUrl": {
"baseUrl": "https://s.youtube.com/api/stats/playback?cl=491307275&docid=AjXQiKP5kMs&ei=Nl2HY-6MH5WE8gPjnYnoDg&fexp=1714242%2C9405963%2C23804281%2C23858057%2C23880830%2C23880833%2C23882685%2C23918597%2C23934970%2C23946420%2C23966208%2C23983296%2C23998056%2C24001373%2C24002022%2C24002025%2C24004644%2C24007246%2C24034168%2C24036947%2C24077241%2C24080738%2C24120820%2C24135310%2C24135692%2C24140247%2C24161116%2C24162919%2C24164186%2C24169501%2C24175560%2C24181174%2C24187043%2C24187377%2C24187854%2C24191629%2C24197450%2C24199724%2C24200839%2C24209349%2C24211178%2C24217535%2C24219713%2C24224266%2C24241378%2C24248091%2C24248956%2C24255543%2C24255545%2C24262346%2C24263796%2C24265426%2C24267564%2C24268142%2C24279196%2C24280220%2C24283426%2C24283493%2C24287327%2C24288045%2C24290971%2C24292955%2C24293803%2C24299747%2C24390674%2C24391018%2C24391537%2C24391709%2C24392268%2C24392363%2C24392401%2C24401557%2C24402891%2C24403794%2C24406605%2C24407200%2C24407665%2C24407914%2C24408220%2C24411766%2C24413105%2C24413820%2C24414162%2C24415866%2C24416354%2C24420756%2C24421162%2C24425861%2C24428962%2C24590921%2C39322504%2C39322574%2C39322694%2C39322707&ns=yt&plid=AAXusD4TIOMjS5N4&el=detailpage&len=246&of=Jx1iRksbq-rB9N1KSijZLQ&osid=MWU2NzBjYTI%3AAOeUNAagU8UyWDUJIki5raGHy29-60-yTA&uga=29&vm=CAEQABgEOjJBUEV3RWxUNmYzMXNMMC1MYVpCVnRZTmZWMWw1OWVZX2ZOcUtCSkphQ245VFZwOXdTQWJbQVBta0tETEpWNXI1SlNIWEJERXdHeFhXZVllNXBUemt5UHR4WWZEVzFDblFUSmdla3BKX2R0dXk3bzFORWNBZmU5YmpYZnlzb3doUE5UU0FoVGRWa0xIaXJqSWgB",
"headers": [
{
"headerType": "USER_AUTH"
},
{
"headerType": "VISITOR_ID"
},
{
"headerType": "PLUS_PAGE_ID"
}
]
},
"videostatsDelayplayUrl": { (as above) },
"videostatsWatchtimeUrl": { (as above) },
"ptrackingUrl": { (as above) },
"qoeUrl": { (as above) },
"atrUrl": { (as above) },
"videostatsScheduledFlushWalltimeSeconds": [10, 20, 30],
"videostatsDefaultFlushIntervalSeconds": 40
},
"videoDetails": {
"videoId": "AjXQiKP5kMs",
"title": "Sparks",
"lengthSeconds": "245",
"channelId": "UCvCk2zFqkCYzpnSgWfx0qOg",
"isOwnerViewing": false,
"isCrawlable": false,
"thumbnail": {
"thumbnails": []
},
"allowRatings": true,
"viewCount": "12",
"author": "Thomas Bergersen",
"isPrivate": true,
"isUnpluggedCorpus": false,
"musicVideoType": "MUSIC_VIDEO_TYPE_PRIVATELY_OWNED_TRACK",
"isLiveContent": false
},
"microformat": {
"microformatDataRenderer": {
"urlCanonical": "https://music.youtube.com/watch?v=AjXQiKP5kMs",
"title": "Sparks - YouTube Music",
"description": "Uploaded to YouTube via YouTube Music Sparks",
"thumbnail": {
"thumbnails": [
{
"url": "https://i.ytimg.com/vi/AjXQiKP5kMs/hqdefault.jpg",
"width": 480,
"height": 360
}
]
},
"siteName": "YouTube Music",
"appName": "YouTube Music",
"androidPackage": "com.google.android.apps.youtube.music",
"iosAppStoreId": "1017492454",
"iosAppArguments": "https://music.youtube.com/watch?v=AjXQiKP5kMs",
"ogType": "video.other",
"urlApplinksIos": "vnd.youtube.music://music.youtube.com/watch?v=AjXQiKP5kMs&feature=applinks",
"urlApplinksAndroid": "vnd.youtube.music://music.youtube.com/watch?v=AjXQiKP5kMs&feature=applinks",
"urlTwitterIos": "vnd.youtube.music://music.youtube.com/watch?v=AjXQiKP5kMs&feature=twitter-deep-link",
"urlTwitterAndroid": "vnd.youtube.music://music.youtube.com/watch?v=AjXQiKP5kMs&feature=twitter-deep-link",
"twitterCardType": "player",
"twitterSiteHandle": "@YouTubeMusic",
"schemaDotOrgType": "http://schema.org/VideoObject",
"noindex": true,
"unlisted": true,
"paid": false,
"familySafe": true,
"pageOwnerDetails": {
"name": "Music Library Uploads",
"externalChannelId": "UCvCk2zFqkCYzpnSgWfx0qOg",
"youtubeProfileUrl": "http://www.youtube.com/channel/UCvCk2zFqkCYzpnSgWfx0qOg"
},
"videoDetails": {
"externalVideoId": "AjXQiKP5kMs",
"durationSeconds": "246",
"durationIso8601": "PT4M6S"
},
"linkAlternates": [
{
"hrefUrl": "android-app://com.google.android.youtube/http/youtube.com/watch?v=AjXQiKP5kMs"
},
{
"hrefUrl": "ios-app://544007664/http/youtube.com/watch?v=AjXQiKP5kMs"
},
{
"hrefUrl": "https://www.youtube.com/oembed?format=json&url=https%3A%2F%2Fmusic.youtube.com%2Fwatch%3Fv%3DAjXQiKP5kMs",
"title": "Sparks",
"alternateType": "application/json+oembed"
},
{
"hrefUrl": "https://www.youtube.com/oembed?format=xml&url=https%3A%2F%2Fmusic.youtube.com%2Fwatch%3Fv%3DAjXQiKP5kMs",
"title": "Sparks",
"alternateType": "text/xml+oembed"
}
],
"viewCount": "12",
"publishDate": "1969-12-31",
"category": "Music",
"uploadDate": "1969-12-31"
}
}
}
Implementation
Future<JsonMap> getSong(String videoId, {int? signatureTimestamp}) async {
const endpoint = 'player';
signatureTimestamp ??= getDatestamp() - 1;
final params = <String, dynamic>{
'playbackContext': {
'contentPlaybackContext': {'signatureTimestamp': signatureTimestamp},
},
'video_id': videoId,
};
final response = await sendRequest(endpoint, params);
response.keys
.where(
(k) =>
![
'videoDetails',
'playabilityStatus',
'streamingData',
'microformat',
'playbackTracking',
].contains(k),
)
.toList()
.forEach(response.remove);
return response;
}