getSongCredits method
- String browseId
Get credits for a song. Top-level entries are limited to performed_by,
written_by, produced_by and music_metadata_provided_by.
If YouTube returns additional data, it will be returned in other_sections.
browseIdbrowseIdfor the credits of a song, for example returned ascreditsBrowseIdin the tracks of getAlbum Returns a Map with credit sections.
Example::
{
"performed_by": {
"localized_title": "Performed by",
"data":
"Eminem",
"Beyoncé"
},
"written_by": {
"localized_title": "Written by",
"data":
"Marshall Mathers",
"Beyoncé Knowles",
"Holly Hafermann"
},
"produced_by": {
"localized_title": "Produced by",
"data":
"Rick Rubin"
},
"music_metadata_provided_by": {
"localized_title": "Music metadata provided by"
"data":
"Eminem Catalog PS"
},
"other_sections": [
{
"localized_title": "Piano",
"data":
"Skylar Grey"
}
]
}
Implementation
Future<JsonMap> getSongCredits(String browseId) async {
if (browseId.isEmpty || !browseId.startsWith('MPTC')) {
throw Exception(
'Invalid song credits browseId provided, must start with MPTC.',
);
}
final body = {'browseId': browseId};
const endpoint = 'browse';
final response = await sendRequest(endpoint, body);
final credits = <String, dynamic>{'other_sections': []};
final sections = List<JsonMap>.from(
nav(response, CREDITS_SECTIONS) as List,
);
final localizedSectionMap = parser.getSongCreditSectionMap();
for (final section in sections) {
final sectionContent = section['dismissableDialogContentSectionRenderer'];
final sectionLocalName = nav(sectionContent, TITLE_TEXT);
final sectionSnakeCaseName =
localizedSectionMap[sectionLocalName] as String?;
final subtitleRuns = List<JsonMap>.from(
nav(sectionContent, SUBTITLE_RUNS) as List? ?? [],
);
final sectionData = {
'localized_title': sectionLocalName,
'data': [
for (var i = 0; i < subtitleRuns.length; i += 2)
subtitleRuns[i]['text'],
],
};
if (sectionSnakeCaseName != null) {
credits[sectionSnakeCaseName] = sectionData;
} else {
(credits['other_sections'] as List).add(sectionData);
}
}
return credits;
}