Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
FelipeYslaoker committed Jul 25, 2024
0 parents commit 0131e7e
Show file tree
Hide file tree
Showing 22 changed files with 3,140 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://dart.dev/guides/libraries/private-files
# Created by `dart pub`
.dart_tool/
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
## 1.0.0

- Initial version.
674 changes: 674 additions & 0 deletions LICENSE

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Ported from [ts-npm-music-api](https://github.com/zS1L3NT/ts-npm-ytmusic-api)
30 changes: 30 additions & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
# This file configures the static analysis results for your project (errors,
# warnings, and lints).
#
# This enables the 'recommended' set of lints from `package:lints`.
# This set helps identify many issues that may lead to problems when running
# or consuming Dart code, and enforces writing Dart using a single, idiomatic
# style and format.
#
# If you want a smaller set of lints you can change this to specify
# 'package:lints/core.yaml'. These are just the most critical lints
# (the recommended set includes the core lints).
# The core lints are also what is used by pub.dev for scoring packages.

include: package:lints/recommended.yaml

# Uncomment the following section to specify additional rules.

# linter:
# rules:
# - camel_case_types

# analyzer:
# exclude:
# - path/to/excluded/files/**

# For more information about the core and recommended set of lints, see
# https://dart.dev/go/core-lints

# For additional information about configuring this file, see
# https://dart.dev/guides/language/analysis-options
136 changes: 136 additions & 0 deletions example/main.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import 'package:dart_ytmusic_api/yt_music.dart';

void main() async {
// Create an instance of the YouTube Music API
final ytmusic = YTMusic();

// Initialize the API
await ytmusic.initialize();

await searchSongs(ytmusic);
}

// Search Methods
/// Searches for search suggestions by the given query and prints the results.
Future<void> getSearchSuggestions(YTMusic ytmusic) async {
final results = await ytmusic.getSearchSuggestions('The Sco');
for (final suggestion in results) {
print(suggestion);
}
}

/// Searches for songs by the given query and prints the results.
Future<void> searchSongs(YTMusic ytmusic) async {
final results = await ytmusic.searchSongs('Aurora Runaway');
for (final result in results) {
print(
'${result.name} - ${result.artist.name} (${result.artist.artistId}) - ${result.videoId}');
}
}

/// Searches for albums by the given query and prints the results.
Future<void> searchAlbums(YTMusic ytmusic) async {
final results = await ytmusic.searchAlbums('bastille');
for (final result in results) {
print('${result.name} - ${result.artist.name} - ${result.albumId}');
}
}

/// Searches for artists by the given query and prints the results.
Future<void> searchArtists(YTMusic ytmusic) async {
final results = await ytmusic.searchArtists('Aurora');
for (final result in results) {
print('${result.name} - ${result.artistId}');
}
}

/// Searches for videos by the given query and prints the results.
Future<void> searchVideos(YTMusic ytmusic) async {
final results = await ytmusic.searchVideos('Aurora Runaway');
for (final result in results) {
print('${result.name} - ${result.videoId}');
}
}

/// Searches for playlists by the given query and prints the results.
Future<void> searchPlaylists(YTMusic ytmusic) async {
final results = await ytmusic.searchPlaylists('Global Songs');
for (final result in results) {
print('${result.name} - ${result.playlistId}');
}
}

// Specific Data Retrieval Methods
/// Retrieves details of a song by its ID and prints the result.
Future<void> getSong(YTMusic ytmusic) async {
final result = await ytmusic.getSong('LDY4Bf8Zwn8');
print('${result.name} - ${result.videoId}');
}

/// Retrieves details of a video by its ID and prints the result.
Future<void> getVideo(YTMusic ytmusic) async {
final result = await ytmusic.getVideo('LDY4Bf8Zwn8');
print('${result.name} - ${result.artist.artistId}');
}

/// Retrieves lyrics of a song by its video ID and prints the result.
Future<void> getLyrics(YTMusic ytmusic) async {
final result = await ytmusic.getLyrics('LDY4Bf8Zwn8');
print('$result');
}

/// Retrieves albums of an artist by the artist's ID and prints the results.
Future<void> getArtistAlbums(YTMusic ytmusic) async {
// The Score - UCdQICt_YIo4FEOaLtTOi4RA
// Aurora - UC4G-AJa7kn8oumI6TT2WXYw
final results = await ytmusic.getArtistAlbums('UC4G-AJa7kn8oumI6TT2WXYw');
for (final result in results) {
print('${result.name} - ${result.artist.artistId}');
}
}

Future<void> getArtistSingles(YTMusic ytmusic) async {
// The Score - UCdQICt_YIo4FEOaLtTOi4RA
// Aurora - UC4G-AJa7kn8oumI6TT2WXYw
final results = await ytmusic.getArtistSingles('UC4G-AJa7kn8oumI6TT2WXYw');
for (final result in results) {
print('${result.name} - ${result.artist.artistId}');
}
}

/// Retrieves videos of a playlist by the playlist's ID and prints the results.
Future<void> getPlaylistVideos(YTMusic ytmusic) async {
final results = await ytmusic
.getPlaylistVideos('RDCLAK5uy_nfs_t4FUu00E5ED6lveEBBX1VMYe1mFjk');
for (final result in results) {
print('${result.name} - ${result.videoId}');
}
}

/// Retrieves details of an album by its ID and prints the result.
Future<void> getAlbum(YTMusic ytmusic) async {
final result = await ytmusic.getAlbum('UC4G-AJa7kn8oumI6TT2WXYw');
print('${result.name} - ${result.artist.name}');
}

/// Retrieves details of an artist by their ID and prints the result.
Future<void> getArtist(YTMusic ytmusic) async {
final result = await ytmusic.getArtist('UC4G-AJa7kn8oumI6TT2WXYw');
print('${result.name} - ${result.artistId}');
}

Future<void> getArtistSongs(YTMusic ytmusic) async {
final songs = await ytmusic.getArtistSongs('UCdQICt_YIo4FEOaLtTOi4RA');
for (final song in songs) {
print('${song.name} - ${song.artist.artistId}');
}
}

// General Data Retrieval Methods
/// Retrieves home sections and prints the results.
Future<void> getHomeSections(YTMusic ytmusic) async {
final results = await ytmusic.getHomeSections();
for (final result in results) {
print('${result.title} - ${result.contents}');
}
}
14 changes: 14 additions & 0 deletions lib/dart_ytmusic_api.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
library dart_ytmusic_api;

export './yt_music.dart';
export './enums.dart';
export './types.dart';
export './utils/filters.dart';
export './utils/traverse.dart';
export './parsers/album_parser.dart';
export './parsers/artist_parser.dart';
export './parsers/parser.dart';
export './parsers/playlist_parser.dart';
export './parsers/search_parser.dart';
export './parsers/song_parser.dart';
export './parsers/video_parser.dart';
18 changes: 18 additions & 0 deletions lib/enums.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
enum PageType {
musicPageTypeAlbum,
musicPageTypePlaylist,
musicVideoTypeOmv;

static string(PageType pageType) {
switch (pageType) {
case PageType.musicPageTypeAlbum:
return 'MUSIC_PAGE_TYPE_ALBUM';
case PageType.musicPageTypePlaylist:
return 'MUSIC_PAGE_TYPE_PLAYLIST';
case PageType.musicVideoTypeOmv:
return 'MUSIC_VIDEO_TYPE_OMV';
}
}
}

const String feMusicHome = "FEmusic_home";
133 changes: 133 additions & 0 deletions lib/parsers/album_parser.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
import 'package:dart_ytmusic_api/parsers/song_parser.dart';
import 'package:dart_ytmusic_api/types.dart';
import 'package:dart_ytmusic_api/utils/filters.dart';
import 'package:dart_ytmusic_api/utils/traverse.dart';

class AlbumParser {
static AlbumFull parse(dynamic data, String albumId) {
final albumBasic = AlbumBasic(
albumId: albumId,
name: traverseString(data, ["tabs", "title", "text"]) ?? '',
);

final artistData = traverse(data, ["tabs", "straplineTextOne", "runs"]);
final artistBasic = ArtistBasic(
artistId: traverseString(artistData, ["browseId"]),
name: traverseString(artistData, ["text"]) ?? '',
);

final thumbnails = traverseList(data, ["background", "thumbnails"])
.map((item) => ThumbnailFull.fromMap(item))
.toList();

return AlbumFull(
name: albumBasic.name,
type: "ALBUM",
albumId: albumId,
playlistId:
traverseString(data, ["musicPlayButtonRenderer", "playlistId"]) ?? '',
artist: artistBasic,
year: processYear(
traverseList(data, ["tabs", "subtitle", "text"]).last,
),
thumbnails: thumbnails,
songs: traverseList(data, ["musicResponsiveListItemRenderer"])
.map(
(item) => SongParser.parseAlbumSong(
item,
artistBasic,
albumBasic,
thumbnails,
),
)
.toList(),
);
}

static AlbumDetailed parseSearchResult(dynamic item) {
final columns = traverseList(item, ["flexColumns", "runs"])
.expand((e) => e is List ? e : [e])
.toList();

// No specific way to identify the title
final title = columns[0];
final artist = columns.firstWhere(isArtist, orElse: () => columns[3]);
final playlistId = traverseString(item, ["overlay", "playlistId"]) ??
traverseString(item, ["thumbnailOverlay", "playlistId"]);

return AlbumDetailed(
type: "ALBUM",
albumId: traverseList(item, ["browseId"]).last,
playlistId: playlistId ?? '',
artist: ArtistBasic(
name: traverseString(artist, ["text"]) ?? '',
artistId: traverseString(artist, ["browseId"]),
),
year: processYear(columns.last?['text']),
name: traverseString(title, ["text"]) ?? '',
thumbnails: traverseList(item, ["thumbnails"])
.map((item) => ThumbnailFull.fromMap(item))
.toList(),
);
}

static AlbumDetailed parseArtistAlbum(dynamic item, ArtistBasic artistBasic) {
return AlbumDetailed(
type: "ALBUM",
albumId: traverseList(item, ["browseId"])
.where((element) => element != artistBasic.artistId)
.firstOrNull ??
'',
playlistId:
traverseString(item, ["thumbnailOverlay", "playlistId"]) ?? '',
name: traverseString(item, ["title", "text"]) ?? '',
artist: artistBasic,
year: processYear(traverseList(item, ["subtitle", "text"]).last),
thumbnails: traverseList(item, ["thumbnails"])
.map((item) => ThumbnailFull.fromMap(item))
.toList(),
);
}

static AlbumDetailed parseArtistTopAlbum(
dynamic item, ArtistBasic artistBasic) {
return AlbumDetailed(
type: "ALBUM",
albumId: traverseList(item, ["browseId"]).last,
playlistId:
traverseString(item, ["musicPlayButtonRenderer", "playlistId"]) ?? '',
name: traverseString(item, ["title", "text"]) ?? '',
artist: artistBasic,
year: processYear(traverseList(item, ["subtitle", "text"]).last),
thumbnails: traverseList(item, ["thumbnails"])
.map((item) => ThumbnailFull.fromMap(item))
.toList(),
);
}

static AlbumDetailed parseHomeSection(dynamic item) {
final artist = traverse(item, ["subtitle", "runs"]).last;

return AlbumDetailed(
type: "ALBUM",
albumId: traverseString(item, ["title", "browseId"]) ?? '',
playlistId:
traverseString(item, ["thumbnailOverlay", "playlistId"]) ?? '',
name: traverseString(item, ["title", "text"]) ?? '',
artist: ArtistBasic(
name: traverseString(artist, ["text"]) ?? '',
artistId: traverseString(artist, ["browseId"]) ?? '',
),
year: null,
thumbnails: traverseList(item, ["thumbnails"])
.map((item) => ThumbnailFull.fromMap(item))
.toList(),
);
}

static int? processYear(String? year) {
return year != null && RegExp(r"^\d{4}$").hasMatch(year)
? int.parse(year)
: null;
}
}
Loading

0 comments on commit 0131e7e

Please sign in to comment.