Comments (13)
Sorry, I didnt have time to try those changes, but yes, can be clossed as completed. Thanks.
from spotify-dart.
Seems like you hit a quota and got rate limited. But maybe we need to think about some library level handling of such a situation.
What it means for you right now is, that you need to wait until you can make a request again. In the Developer Dashboard you should be able to see your current volume.
from spotify-dart.
Its probably that i hitted a quota because I tried a lot of things yesterday, but my question is if I deploy an app how can I handle these type of problems? Maybe creating another app and changing between them?
from spotify-dart.
@addreeh You could show the user a message, that the app is currently not usable and that he/she should try it again later. I suggest to check the code for unnecessary requests (sometimes they are done in some for
-loops) and look for alternatives (e.g. instead of requesting all albums for each artist, you could collect each albumId
for each artist and do a getSeveralAlbums
request). That way you would reduce requests.
from spotify-dart.
Mmmm yes, is so probably that i am doing request that are unnecessary, I would glad if you could check my code and tell me if I can resume or delete something, if you don't have time close the issue, I understand that this is not the place for that. Thanks for the support.
Pasted Code
_initApp() async {
try {
playlistSongs.clear();
playlistArtists = [];
playlistArtistsFull = [];
playlistObject = await _getPlaylist(widget.playlistUrl);
playlistDominantColor = await _getPlaylistDominantColor();
_checkDominantColor();
playlistDominantColorLight = _getLighterPlaylistDominantColor();
playlistSongs = await _getPlaylistSongs();
playlistDuration = _getPlaylistDuration();
playlistArtists = await _getArtists();
playlistArtistsFull = await _getFullArtist();
playlistStatistics = _getArtistStatistics();
setState(() {
isLoading = false;
});
} catch (e) {
print("Error al obtener canciones: $e");
setState(() {
isLoading = false;
});
}
}
String _extractPlaylistId(String spotifyLink) {
RegExp regExp = RegExp(r'/playlist/([a-zA-Z0-9]+)');
Match? match = regExp.firstMatch(spotifyLink);
if (match != null && match.groupCount >= 1) {
return match.group(1)!;
} else {
return "";
}
}
Future<spotify.Playlist> _getPlaylist(String url) async {
var playlist = await spotifyApi.playlists.get(_extractPlaylistId(url));
return playlist;
}
void _checkDominantColor() {
// Comparar los componentes de playlistDominantColor (rojo, verde y azul) con un umbral
int umbral = 150;
if (playlistDominantColor.red > umbral &&
playlistDominantColor.green > umbral &&
playlistDominantColor.blue > umbral) {
bannerTextColor = Colors.black;
} else {
bannerTextColor = Colors.white;
}
}
Future _getPlaylistDominantColor() async {
try {
var paletteGenerator = await PaletteGenerator.fromImageProvider(
Image.network(playlistObject.images!.first.url!).image,
);
return paletteGenerator.dominantColor!.color;
} catch (e) {
return const Color(0xFF000000);
}
}
_getLighterPlaylistDominantColor() {
try {
final hslColor = HSLColor.fromColor(playlistDominantColor);
playlistDominantColorLight = hslColor
.withLightness((hslColor.lightness).clamp(0.20, 0.51))
.toColor();
return playlistDominantColorLight;
} catch (e) {
return const Color(0xFF000000);
}
}
Future<List<dynamic>> _getPlaylistSongs() async {
List<dynamic> songs = [];
int offset = 0;
int limit = 100;
int cont = 1;
while (true) {
try {
var tracks = await spotifyApi.playlists
.getTracksByPlaylistId(playlistObject.id)
.getPage(limit, offset);
if (tracks.items != null && tracks.items!.isNotEmpty) {
try {
for (var track in tracks.items!) {
songs.add(track);
cont++;
}
offset += limit;
} catch (e) {
cont++;
offset = cont;
}
} else {
break;
}
} catch (e) {
print(e);
showTopSnackBar(
Overlay.of(context),
const CustomSnackBar.error(
message: "Something went wrong. Try it again later.",
),
);
}
}
return songs;
}
String _getPlaylistDuration() {
num duration = 0;
var uniqueArtists = <String>{};
for (var song in playlistSongs) {
duration += song.durationMs;
for (var artist in song.artists) {
if (artist.id != null && artist.name != null) {
uniqueArtists.add(artist.id);
}
}
}
int seconds = (duration / 1000).round();
int hours = seconds ~/ 3600;
int minutes = (seconds % 3600) ~/ 60;
String formattedDuration = hours > 0
? '$hours h ${minutes.toString().padLeft(2, '0')} min'
: '$minutes min';
return formattedDuration;
}
_getArtists() async {
var artistIds =
<String>{}; // Conjunto para almacenar IDs únicos de artistas
var uniqueArtists =
<spotify.Artist>[]; // Lista para almacenar artistas únicos
for (var song in playlistSongs) {
for (var artist in song.artists) {
if (artist.id != null && artist.name != null) {
if (!artistIds.contains(artist.id)) {
// Si el ID del artista no está en el conjunto, agrega el artista
artistIds.add(artist.id);
uniqueArtists.add(artist);
}
}
}
}
return uniqueArtists;
}
_getFullArtist() async {
List<spotify.Artist> artists = [];
for (var artist in playlistArtists) {
try {
var newArtist = await spotifyApi.artists.get(artist.id);
artists.add(newArtist);
} catch (e) {
print(e);
showTopSnackBar(
Overlay.of(context),
const CustomSnackBar.error(
message: "Something went wrong. Try it again later.",
),
);
}
}
return artists;
}
List<ArtistResult> _getArtistStatistics() {
List<ArtistResult> artistStatistics = [];
for (var artist in playlistArtistsFull) {
var artistTracks = <spotify.Track>[];
for (var song in playlistSongs) {
for (var songArtist in song.artists) {
if (songArtist.id == artist.id) {
artistTracks.add(song);
break;
}
}
}
double percentage = double.parse(
(artistTracks.length / playlistSongs.length * 100)
.toStringAsFixed(2));
ArtistResult result = ArtistResult(
artist,
artistTracks,
artistTracks.length,
percentage,
// color,
);
artistStatistics.add(result);
}
artistStatistics.sort((a, b) => sortByPercentageAscending
? a.percentage.compareTo(b.percentage)
: b.percentage.compareTo(a.percentage));
return artistStatistics;
}
from spotify-dart.
while (true) {
try {
var tracks = await spotifyApi.playlists
.getTracksByPlaylistId(playlistObject.id)
.getPage(limit, offset);
...
}
- So one thing, that looks suspicious is that you fetch all playlist items. If - let's say - a playlist has 300 tracks, but only - let's say - 15 are displayed, then it is indeed a waste of requests. As far as I understand your code, you want to display tracks from a playlist in a list (?). You could reduce requests by only
GET
ting onePage
at a time. This could be done withListView
s that allow to fetch more data once the end of the list is reached. Unfortunately I forgot the proper name of those lists, but with a quich search you would be able to find it.
_getFullArtist() async {
List<spotify.Artist> artists = [];
for (var artist in playlistArtists) {
try {
var newArtist = await spotifyApi.artists.get(artist.id);
artists.add(newArtist);
} catch (e) { ... }
return artists;
}
- You could use
spotify.artists.list()
here instead of requesting each artist individually. So in your case it would look like this:
_getFullArtist() async {
// converting list of artists into list of artist id's
var artistIds = playlistArtists.map((artist) => artist.id);
// bulk retrieve artist information saving you the for-loop
return await spotifyApi.artists.list(artistIds);
}
Hope it helps :)
from spotify-dart.
Seems like you hit a quota and got rate limited. But maybe we need to think about some library level handling of such a situation.
@rinukkusu Maybe tracking the number of requests?
from spotify-dart.
My purpose is to do an app to track a playlist, it shows the percentage of songs that each artist has, because of that I have to get all the tracks and then I have to get each artist of each song, because of that i have to use a lot of loops that makes the app slow, but Im sure that if I would know all the methods of the library it will be faster jajaja
Pasted Code
// ignore_for_file: library_private_types_in_public_api, use_build_context_synchronously
import 'package:flutter/material.dart';
import 'package:loading_animation_widget/loading_animation_widget.dart';
import 'package:spotify/spotify.dart' as spotify;
import 'package:top_snackbar_flutter/custom_snack_bar.dart';
import 'package:top_snackbar_flutter/top_snack_bar.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:transformable_list_view/transformable_list_view.dart';
import 'package:expansion_tile_card/expansion_tile_card.dart';
import 'package:responsive_builder/responsive_builder.dart';
import 'package:palette_generator/palette_generator.dart';
final credentials = spotify.SpotifyApiCredentials(
"", "");
var spotifyApi = spotify.SpotifyApi(credentials);
class ArtistResult {
final spotify.Artist artist;
final List<spotify.Track> tracks;
final int total;
final double percentage;
// final Color color;
ArtistResult(this.artist, this.tracks, this.total, this.percentage);
}
class Trackerfy extends StatefulWidget {
final String playlistUrl;
const Trackerfy(this.playlistUrl, {super.key});
@override
_TrackerfyState createState() => _TrackerfyState();
}
class _TrackerfyState extends State<Trackerfy> {
bool showLoadingAnimation = true;
var playlistObject;
var playlistSongs = [];
var playlistDuration = "";
var playlistArtists = [];
var playlistArtistsFull = [];
bool isLoading = true;
bool sortByPercentageAscending = false;
final TextEditingController _searchController = TextEditingController();
final bool _isSearching = false;
var _filteredArtists = [];
var playlistStatistics = [];
Color playlistDominantColor = const Color(0xFF000000);
Color playlistDominantColorLight = const Color(0xFF000000);
Color bannerTextColor = Colors.white;
@override
void initState() {
super.initState();
_initApp();
// Después de 5 segundos, oculta la animación de carga
Future.delayed(const Duration(seconds: 5), () {
setState(() {
showLoadingAnimation = false;
});
});
}
_initApp() async {
try {
playlistSongs.clear();
playlistArtists = [];
playlistArtistsFull = [];
playlistObject = await _getPlaylist(widget.playlistUrl);
playlistDominantColor = await _getPlaylistDominantColor();
_checkDominantColor();
playlistDominantColorLight = _getLighterPlaylistDominantColor();
playlistSongs = await _getPlaylistSongs();
playlistDuration = _getPlaylistDuration();
playlistArtists = await _getArtists();
playlistArtistsFull = await _getFullArtist();
playlistStatistics = _getArtistStatistics();
setState(() {
isLoading = false;
});
} catch (e) {
print("Error al obtener canciones: $e");
setState(() {
isLoading = false;
});
}
}
String _extractPlaylistId(String spotifyLink) {
RegExp regExp = RegExp(r'/playlist/([a-zA-Z0-9]+)');
Match? match = regExp.firstMatch(spotifyLink);
if (match != null && match.groupCount >= 1) {
return match.group(1)!;
} else {
return "";
}
}
Future<spotify.Playlist> _getPlaylist(String url) async {
var playlist = await spotifyApi.playlists.get(_extractPlaylistId(url));
return playlist;
}
void _checkDominantColor() {
// Comparar los componentes de playlistDominantColor (rojo, verde y azul) con un umbral
int umbral = 150;
if (playlistDominantColor.red > umbral &&
playlistDominantColor.green > umbral &&
playlistDominantColor.blue > umbral) {
bannerTextColor = Colors.black;
} else {
bannerTextColor = Colors.white;
}
}
Future _getPlaylistDominantColor() async {
try {
var paletteGenerator = await PaletteGenerator.fromImageProvider(
Image.network(playlistObject.images!.first.url!).image,
);
return paletteGenerator.dominantColor!.color;
} catch (e) {
return const Color(0xFF000000);
}
}
_getLighterPlaylistDominantColor() {
try {
final hslColor = HSLColor.fromColor(playlistDominantColor);
playlistDominantColorLight = hslColor
.withLightness((hslColor.lightness).clamp(0.20, 0.51))
.toColor();
return playlistDominantColorLight;
} catch (e) {
return const Color(0xFF000000);
}
}
Future<List<dynamic>> _getPlaylistSongs() async {
List<dynamic> songs = [];
int offset = 0;
int limit = 100;
int cont = 1;
while (true) {
try {
var tracks = await spotifyApi.playlists
.getTracksByPlaylistId(playlistObject.id)
.getPage(limit, offset);
if (tracks.items != null && tracks.items!.isNotEmpty) {
try {
for (var track in tracks.items!) {
songs.add(track);
cont++;
}
offset += limit;
} catch (e) {
cont++;
offset = cont;
}
} else {
break;
}
} catch (e) {
print(e);
showTopSnackBar(
Overlay.of(context),
const CustomSnackBar.error(
message: "Something went wrong. Try it again later.",
),
);
}
}
return songs;
}
String _getPlaylistDuration() {
num duration = 0;
var uniqueArtists = <String>{};
for (var song in playlistSongs) {
duration += song.durationMs;
for (var artist in song.artists) {
if (artist.id != null && artist.name != null) {
uniqueArtists.add(artist.id);
}
}
}
int seconds = (duration / 1000).round();
int hours = seconds ~/ 3600;
int minutes = (seconds % 3600) ~/ 60;
String formattedDuration = hours > 0
? '$hours h ${minutes.toString().padLeft(2, '0')} min'
: '$minutes min';
return formattedDuration;
}
_getArtists() async {
var artistIds =
<String>{}; // Conjunto para almacenar IDs únicos de artistas
var uniqueArtists =
<spotify.Artist>[]; // Lista para almacenar artistas únicos
for (var song in playlistSongs) {
for (var artist in song.artists) {
if (artist.id != null && artist.name != null) {
if (!artistIds.contains(artist.id)) {
// Si el ID del artista no está en el conjunto, agrega el artista
artistIds.add(artist.id);
uniqueArtists.add(artist);
}
}
}
}
return uniqueArtists;
}
_getFullArtist() async {
List<spotify.Artist> artists = [];
for (var artist in playlistArtists) {
try {
var newArtist = await spotifyApi.artists.get(artist.id);
artists.add(newArtist);
} catch (e) {
print(e);
showTopSnackBar(
Overlay.of(context),
const CustomSnackBar.error(
message: "Something went wrong. Try it again later.",
),
);
}
}
return artists;
}
List<ArtistResult> _getArtistStatistics() {
List<ArtistResult> artistStatistics = [];
for (var artist in playlistArtistsFull) {
var artistTracks = <spotify.Track>[];
for (var song in playlistSongs) {
for (var songArtist in song.artists) {
if (songArtist.id == artist.id) {
artistTracks.add(song);
break;
}
}
}
double percentage = double.parse(
(artistTracks.length / playlistSongs.length * 100)
.toStringAsFixed(2));
ArtistResult result = ArtistResult(
artist,
artistTracks,
artistTracks.length,
percentage,
// color,
);
artistStatistics.add(result);
}
artistStatistics.sort((a, b) => sortByPercentageAscending
? a.percentage.compareTo(b.percentage)
: b.percentage.compareTo(a.percentage));
return artistStatistics;
}
Matrix4 getTransformMatrix(TransformableListItem item) {
const endScaleBound = 0.3;
final animationProgress = item.visibleExtent / item.size.height;
final paintTransform = Matrix4.identity();
if (item.position != TransformableListItemPosition.middle) {
final scale = endScaleBound + ((1 - endScaleBound) * animationProgress);
paintTransform
..translate(item.size.width / 2)
..scale(scale)
..translate(-item.size.width / 2);
}
return paintTransform;
}
_launchURL(url) async {
final Uri uri = Uri.parse(url);
if (!await launchUrl(uri)) {
throw Exception('Could not launch $uri');
}
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: const Color(0xFF121212),
body: ResponsiveBuilder(
builder: (context, sizingInformation) {
return Center(
child: SizedBox(
width: sizingInformation.isMobile
? MediaQuery.of(context).size.width
: 450.0,
child: showLoadingAnimation
? Center(
child: LoadingAnimationWidget.horizontalRotatingDots(
color: Colors.white, size: 50),
)
: NestedScrollView(
headerSliverBuilder:
(BuildContext context, bool innerBoxIsScrolled) {
return <Widget>[
SliverAppBar(
shadowColor: playlistDominantColorLight,
automaticallyImplyLeading: false,
backgroundColor: playlistDominantColor,
title: Padding(
padding: const EdgeInsets.only(left: 5),
child: Text(
playlistObject.name ?? "Playlist",
style: TextStyle(
fontFamily: "Circular Sp",
fontSize: 18.0,
fontWeight: FontWeight.bold,
color: bannerTextColor,
),
),
),
expandedHeight: 253,
floating: true,
pinned: true,
flexibleSpace: FlexibleSpaceBar(
background: Center(
child: Column(
children: [
SizedBox(
height:
sizingInformation.isMobile ? 85 : 65,
),
Row(
mainAxisAlignment:
MainAxisAlignment.center,
children: [
const SizedBox(width: 20),
Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(10.0),
boxShadow: [
BoxShadow(
color:
playlistDominantColorLight,
spreadRadius: 2,
blurRadius: 5,
),
],
),
child: ClipRRect(
borderRadius:
BorderRadius.circular(10.0),
child: Image.network(
playlistObject.images!.first.url!,
width: 120,
height: 120,
fit: BoxFit.cover,
),
),
),
const SizedBox(width: 20),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.center,
children: [
Text(
playlistObject.description!,
style: TextStyle(
fontFamily: "Circular Sp",
fontSize: 12.0,
fontWeight: FontWeight.normal,
color: bannerTextColor,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
Text(
"Owner ➜${playlistObject.owner!.displayName!}",
style: TextStyle(
fontFamily: "Circular Sp",
fontSize: 15.0,
fontWeight: FontWeight.normal,
color: bannerTextColor,
),
textAlign: TextAlign.center,
),
const SizedBox(height: 10),
Text(
playlistStatistics.isEmpty &&
playlistDuration == ""
? "${playlistObject.tracks!.total} songs"
: playlistStatistics
.isEmpty &&
playlistDuration !=
""
? "${playlistObject.tracks!.total} songs ┃ $playlistDuration"
: "${playlistObject.tracks!.total} songs ┃ $playlistDuration ┃ ${playlistStatistics.length} artists",
style: TextStyle(
fontFamily: "Circular Sp",
fontSize: 12.0,
fontWeight: FontWeight.normal,
color: bannerTextColor,
),
textAlign: TextAlign.center,
),
],
),
),
const SizedBox(width: 20),
],
),
Row(
children: [
Expanded(
child: Padding(
padding: const EdgeInsets.fromLTRB(
8, 10, 8, 0),
child: TextField(
cursorColor: bannerTextColor,
controller: _searchController,
style: TextStyle(
fontFamily: "Circular Sp",
color: bannerTextColor,
),
decoration: InputDecoration(
hintText: 'Search Artist ...',
hintStyle: TextStyle(
fontFamily: "Circular Sp",
color: bannerTextColor,
),
focusedBorder:
const OutlineInputBorder(
borderSide: BorderSide.none,
),
enabledBorder:
const OutlineInputBorder(
borderSide: BorderSide.none,
),
suffixIcon: Visibility(
visible: _searchController
.text.isNotEmpty,
child: InkWell(
onTap: () {
setState(() {
_searchController
.clear();
_filteredArtists = [];
});
},
focusNode: FocusNode(
skipTraversal: true),
child: Padding(
padding:
const EdgeInsets.all(
8.0),
child: Icon(
Icons.close,
color: bannerTextColor,
size: 20,
),
),
),
),
),
onChanged: (value) {
setState(() {
_filteredArtists =
playlistStatistics
.where((artist) => artist
.artist.name
.toLowerCase()
.contains(value
.toLowerCase()))
.toList();
});
},
),
),
),
Visibility(
visible: !_searchController
.text.isNotEmpty &&
!_isSearching &&
!isLoading,
child: IconButton(
onPressed: () async {
setState(() {
sortByPercentageAscending =
!sortByPercentageAscending;
isLoading = true;
playlistStatistics =
_getArtistStatistics();
});
Future.delayed(
const Duration(seconds: 2),
() {
setState(() {
isLoading = false;
});
});
},
icon: Icon(
sortByPercentageAscending
? Icons.arrow_upward
: Icons.arrow_downward,
color: bannerTextColor,
),
),
),
IconButton(
onPressed: () {
_launchURL(
"https://open.spotify.com/playlist/${playlistObject.id}");
},
icon: Icon(
Icons.link,
color: bannerTextColor,
),
),
],
)
],
),
),
),
),
];
},
body: Column(
children: [
isLoading
? Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
children: [
LoadingAnimationWidget.threeRotatingDots(
color: Colors.white, size: 50),
const SizedBox(
height: 30,
),
const SizedBox(
width: 300,
child: Text(
"Please note that the waiting time will depend on the size of the playlist.",
style: TextStyle(
fontFamily: "Circular Sp",
fontSize: 17.0,
fontWeight: FontWeight.normal,
color: Colors.white,
),
textAlign: TextAlign.center,
),
),
],
),
)
: Expanded(
child: TransformableListView.builder(
padding: const EdgeInsets.fromLTRB(
20, 10, 20, 20),
getTransformMatrix: getTransformMatrix,
itemBuilder: (context, index) {
final GlobalKey<ExpansionTileCardState>
cardKey = GlobalKey();
final ArtistResult artist =
_filteredArtists.isNotEmpty
? _filteredArtists[index]
: playlistStatistics[index];
return Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0),
child: Container(
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(10),
boxShadow: [
BoxShadow(
color:
playlistDominantColorLight,
spreadRadius: 2,
blurRadius: 7.5,
),
],
),
child: ExpansionTileCard(
animateTrailing: true,
trailing: const Icon(
Icons.arrow_drop_down_rounded,
color: Color(0xFFD2D2D2),
),
baseColor: const Color(0xFF2a2a2a),
// baseColor: playlistStatistics[index].color,
expandedColor:
const Color(0xFF383838),
expandedTextColor:
const Color(0xFFD2D2D2),
shadowColor: playlistDominantColor,
key: cardKey,
leading: ClipOval(
child: FadeInImage.assetNetwork(
placeholder: "assets/load.png",
image: artist
.artist.images![0].url
.toString(),
width: 40.0,
height: 40.0,
),
),
// Dentro del itemBuilder del TransformableListView.builder
title: Text(
"${artist.artist.name} ➜ ${artist.percentage}% ",
style: const TextStyle(
fontFamily: "Circular Sp",
fontSize: 17.0,
fontWeight: FontWeight.normal,
color: Color(0xFFD2D2D2),
),
),
subtitle: Text(
"${artist.total} songs ┃ Expand to see them.",
style: const TextStyle(
fontFamily: "Circular Sp",
fontSize: 14.0,
fontWeight: FontWeight.normal,
color: Color(0xFFD2D2D2),
),
),
children: <Widget>[
Divider(
thickness: 2.0,
height: 1.0,
color:
playlistDominantColorLight,
),
Padding(
padding:
const EdgeInsets.all(13),
child: Container(
decoration: BoxDecoration(
border: Border.all(
color:
playlistDominantColorLight,
width: 0.5,
),
borderRadius:
BorderRadius.circular(
10),
color:
const Color(0xFF454545),
),
height: 150,
child: SingleChildScrollView(
padding:
const EdgeInsets.all(
10),
scrollDirection:
Axis.vertical,
child: Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: <Widget>[
for (var song in artist
.tracks) ...[
Column(
crossAxisAlignment:
CrossAxisAlignment
.start,
children: [
GestureDetector(
onTap:
() async {
_launchURL(
"https://open.spotify.com/track/${song.id}");
},
child: Row(
children: [
const Icon(
Icons
.music_note_rounded,
color: Color(
0xFFD2D2D2),
size:
18.0,
),
const SizedBox(
width:
5.0),
Flexible(
child:
Text(
"${song.name}",
style:
const TextStyle(
fontFamily:
"Circular Sp",
fontSize:
14.0,
fontWeight:
FontWeight.normal,
color:
Color(0xFFD2D2D2),
),
),
),
],
),
),
const SizedBox(
height: 4.0),
Text(
"Artists: ${song.artists?.map((a) => a.name).join(', ')}",
style:
const TextStyle(
fontFamily:
"Circular Sp",
fontSize:
14.0,
fontWeight:
FontWeight
.normal,
color: Colors
.grey,
),
),
const SizedBox(
height: 4,
),
Text(
"Album: ${song.album?.name}",
style:
const TextStyle(
fontFamily:
"Circular Sp",
fontSize:
14.0,
fontWeight:
FontWeight
.normal,
color: Colors
.grey,
),
),
const SizedBox(
height: 8.0),
],
),
],
],
),
),
),
),
ButtonBar(
alignment: MainAxisAlignment
.spaceAround,
buttonHeight: 52.0,
buttonMinWidth: 90.0,
children: <Widget>[
FloatingActionButton.extended(
backgroundColor:
playlistDominantColor,
onPressed: () {
_launchURL(
"https://open.spotify.com/artist/${playlistStatistics[index].artist.id}");
},
label: Text(
"Go to ${artist.artist.name}'s page",
style: TextStyle(
fontFamily:
"Circular Sp",
fontSize: 12.0,
fontWeight:
FontWeight.normal,
color:
bannerTextColor),
),
icon: Icon(
Icons
.person_search_rounded,
color: bannerTextColor,
),
),
],
),
const SizedBox(
height: 5,
),
],
),
),
);
},
itemCount: _filteredArtists.isNotEmpty
? _filteredArtists.length
: playlistStatistics.length,
),
),
],
),
),
),
);
},
),
);
}
}
from spotify-dart.
@addreeh You can check out the wiki-page, where all implemented endpoints are listed.
from spotify-dart.
ok, thank you, finally can you tell me if the way i get all the tracks of the playlist is the correct?
from spotify-dart.
I tried your app out, and retrieving each track and having a statistic like that, is also the only way I would come up with. But I think, you could optimize some of your for
loops, for example
...
int offset = 0;
int limit = 100;
while (true) {
try {
var tracks = await spotifyApi.playlists
.getTracksByPlaylistId(playlistObject?.id ?? '')
.getPage(limit, offset);
if (tracks.items != null && tracks.items!.isNotEmpty) {
try {
songs.addAll(tracks!.items); //<-- just use addAll instead of another for loop.
offset += limit;
} catch (e) {
offset = songs.length;
}
And you also could play around with the dart collection api. It has some methods that could make you remove some of your for
loops.
from spotify-dart.
I will try it, thank you.
from spotify-dart.
@addreeh can this issue be closed?
from spotify-dart.
Related Issues (20)
- Support `episode`s when retrieving items from playlist HOT 1
- Artist Info HOT 2
- startOrResume throws error code 400 (malformed json) HOT 5
- Add debug tools HOT 1
- Spotify Client Authentication HOT 4
- Log In Account HOT 13
- 404 Device not found (and unhandled exception) HOT 1
- Bug: `artists.get` throwing exception "type 'double' is not a subtype of type 'int?' in type cast" HOT 20
- An album play something else! HOT 4
- [Question]: Is it possible to have my flutter client read data from my own account HOT 1
- Include `BaseResponseWithUrl` HOT 1
- Expose `codeVerifier` when building `AuthorizationCodeGrant` HOT 4
- Bug: startWithTracks results in error 400 HOT 1
- Bug: `album.tracks` throwing exception "type 'double' is not a subtype of type 'int?' in type cast" HOT 3
- Enable `createToJson` for the models
- Better handling of list of IDs when there are more than 50 HOT 8
- Throw `ArgumentError`s when `assert`ions fail HOT 2
- Change TrackSimple to Track in PlayHistory object (i.e. when getting recently played tracks) HOT 1
- Getting "type 'Null' is not a subtype of type 'Map<String, dynamic>'" on missing audio feature
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from spotify-dart.