public async Task NowPlaying(Audio item, LastfmUser user)
        {
            var request = new NowPlayingRequest
            {
                Track  = item.Name,
                Album  = item.Album,
                Artist = item.Artists.First(),

                ApiKey = Strings.Keys.LastfmApiKey,
                Method = Strings.Methods.NowPlaying,
                SessionKey = user.SessionKey
            };

            //Add duration
            if (item.RunTimeTicks != null)
                request.Duration = Convert.ToInt32(TimeSpan.FromTicks((long)item.RunTimeTicks).TotalSeconds);

            var response = await Post<NowPlayingRequest, ScrobbleResponse>(request);

            if (response != null && !response.IsError())
            {
                Plugin.Logger.Info("{0} is now playing '{1}' - {2} - {3}", user.Username, request.Track, request.Album, request.Artist);
                return;
            }

            Plugin.Logger.Error("Failed to send now playing for track: {0}", item.Name);
        }
Exemple #2
0
        public async Task NowPlaying(Audio item, LastfmUser user)
        {
            var request = new NowPlayingRequest
            {
                Track  = item.Name,
                Album  = item.Album,
                Artist = item.Artists.First(),

                ApiKey     = Strings.Keys.LastfmApiKey,
                Method     = Strings.Methods.NowPlaying,
                SessionKey = user.SessionKey
            };

            //Add duration
            if (item.RunTimeTicks != null)
            {
                request.Duration = Convert.ToInt32(TimeSpan.FromTicks((long)item.RunTimeTicks).TotalSeconds);
            }

            var response = await Post <NowPlayingRequest, ScrobbleResponse>(request);

            if (response != null && !response.IsError())
            {
                Plugin.Logger.Info("{0} is now playing '{1}' - {2} - {3}", user.Username, request.Track, request.Album, request.Artist);
                return;
            }

            Plugin.Logger.Error("Failed to send now playing for track: {0}", item.Name);
        }
Exemple #3
0
        /// <summary>
        /// Returns a list of a target user's loved tracks from the Last.FM API. See https://www.last.fm/api/show/user.getLovedTracks
        /// </summary>
        /// <param name="lastfmUser"></param>
        /// <param name="progress"></param>
        /// <param name="cancellationToken"></param>
        /// <param name="maxProgress"></param>
        /// <param name="progressOffset"></param>
        private async Task <List <LastfmLovedTrack> > GetLovedTracksLibrary(LastfmUser lastfmUser, IProgress <double> progress, CancellationToken cancellationToken, double maxProgress, double progressOffset)
        {
            var  tracks = new List <LastfmLovedTrack>();
            int  page   = 1;
            bool moreTracks;

            do
            {
                cancellationToken.ThrowIfCancellationRequested();

                var response = await _apiClient.GetLovedTracks(lastfmUser, cancellationToken, page ++).ConfigureAwait(false);

                if (response == null || !response.HasLovedTracks())
                {
                    break;
                }

                tracks.AddRange(response.LovedTracks.Tracks);

                moreTracks = !response.LovedTracks.Metadata.IsLastPage();

                // Only report progress in download because it will be 90% of the time taken
                var currentProgress = ((double)response.LovedTracks.Metadata.Page / response.LovedTracks.Metadata.TotalPages) * (maxProgress - progressOffset) + progressOffset;

                _logger.LogDebug("Progress: " + currentProgress * 100);

                progress.Report(currentProgress * 100);
            } while (moreTracks);
            _logger.LogInformation("Retrieved {0} lovedTracks from LastFM for user {1}", tracks.Count(), lastfmUser.Username);
            return(tracks);
        }
Exemple #4
0
        private async Task <List <LastfmTrack> > GetUsersLibrary(LastfmUser lastfmUser, IProgress <double> progress, CancellationToken cancellationToken, double maxProgress, double progressOffset)
        {
            var  tracks = new List <LastfmTrack>();
            var  page   = 1; //Page 0 = 1
            bool moreTracks;

            do
            {
                cancellationToken.ThrowIfCancellationRequested();

                var response = await _apiClient.GetTracks(lastfmUser, cancellationToken, page ++).ConfigureAwait(false);

                if (response == null || !response.HasTracks())
                {
                    break;
                }

                tracks.AddRange(response.Tracks.Tracks);

                moreTracks = !response.Tracks.Metadata.IsLastPage();

                //Only report progress in download because it will be 90% of the time taken
                var currentProgress = ((double)response.Tracks.Metadata.Page / response.Tracks.Metadata.TotalPages) * (maxProgress - progressOffset) + progressOffset;

                Plugin.Logger.Debug("Progress: " + currentProgress * 100);

                progress.Report(currentProgress * 100);
            } while (moreTracks);

            return(tracks);
        }
Exemple #5
0
        /// <summary>
        /// Loves or unloves a track
        /// </summary>
        /// <param name="item">The track</param>
        /// <param name="user">The Lastfm User</param>
        /// <param name="love">If the track is loved or not</param>
        /// <returns></returns>
        public async Task <bool> LoveTrack(Audio item, LastfmUser user, bool love = true)
        {
            var request = new TrackLoveRequest
            {
                Artist = item.Artists.FirstOrDefault(),
                Track  = item.Name,

                ApiKey     = Strings.Keys.LastfmApiKey,
                Method     = love ? Strings.Methods.TrackLove : Strings.Methods.TrackUnlove,
                SessionKey = user.SessionKey,
            };

            try
            {
                //Send the request
                var response = await Post <TrackLoveRequest, BaseResponse>(request);

                if (response != null && !response.IsError())
                {
                    _logger.LogInformation("{0} {2}loved track '{1}'", user.Username, item.Name, (love ? "" : "un"));
                    return(true);
                }

                _logger.LogError("{0} Failed to love = {3} track '{1}' - {2}", user.Username, item.Name, response.Message, love);
                return(false);
            }
            catch (Exception ex)
            {
                _logger.LogError("{0} Failed to love = {2} track '{1}'", ex, user.Username, item.Name, love);
                return(false);
            }
        }
        public async Task Scrobble(Audio item, LastfmUser user)
        {
            if (string.IsNullOrWhiteSpace(item.Name))
            {
                Plugin.Logger.Error("Cannot scrobble track: {0}, no name", item.Id);
                return;
            }

            var artist = item.Artists?.FirstOrDefault();

            if (string.IsNullOrWhiteSpace(artist))
            {
                Plugin.Logger.Error("Cannot scrobble track: {0} ({1}), no artist found", item.Id, item.Name);
                return;
            }

            var request = new ScrobbleRequest
            {
                Track      = item.Name,
                Album      = item.Album,
                Artist     = artist,
                Timestamp  = Helpers.CurrentTimestamp(),
                SessionKey = user.SessionKey
            };

            var response = await Post <ScrobbleRequest, ScrobbleResponse>(request).ConfigureAwait(false);

            if (response != null && !response.IsError())
            {
                Plugin.Logger.Info("{0} played '{1}' - {2} - {3}", user.Username, request.Track, request.Album, request.Artist);
                return;
            }

            Plugin.Logger.Error("Failed to Scrobble track: {0}", item.Name);
        }
Exemple #7
0
        public async Task <LovedTracksResponse> GetLovedTracks(LastfmUser user)
        {
            var request = new GetLovedTracksRequest
            {
                User   = user.Username,
                ApiKey = Strings.Keys.LastfmApiKey,
                Method = Strings.Methods.GetLovedTracks
            };

            return(await Get <GetLovedTracksRequest, LovedTracksResponse>(request));
        }
Exemple #8
0
        public async Task <GetTracksResponse> GetTracks(LastfmUser user, MusicArtist artist, CancellationToken cancellationToken)
        {
            var request = new GetTracksRequest
            {
                User   = user.Username,
                Artist = artist.Name,
                ApiKey = Strings.Keys.LastfmApiKey,
                Method = Strings.Methods.GetTracks,
                Limit  = 1000
            };

            return(await Get <GetTracksRequest, GetTracksResponse>(request, cancellationToken));
        }
Exemple #9
0
        public async Task <GetTracksResponse> GetTracks(LastfmUser user, CancellationToken cancellationToken, int page = 0, int limit = 200)
        {
            var request = new GetTracksRequest
            {
                User   = user.Username,
                ApiKey = Strings.Keys.LastfmApiKey,
                Method = Strings.Methods.GetTracks,
                Limit  = limit,
                Page   = page
            };

            return(await Get <GetTracksRequest, GetTracksResponse>(request, cancellationToken));
        }
        public async Task <LovedTracksResponse> GetLovedTracks(LastfmUser user, CancellationToken cancellationToken, int page)
        {
            var request = new GetLovedTracksRequest
            {
                User   = user.Username,
                ApiKey = Strings.Keys.LastfmApiKey,
                Method = Strings.Methods.GetLovedTracks,
                Limit  = 1000, // {"error":6,"message":"limit param out of bounds (1-1000)"}
                Page   = page,
                Secure = true
            };

            return(await Get <GetLovedTracksRequest, LovedTracksResponse>(request, cancellationToken));
        }
Exemple #11
0
        public async Task NowPlaying(Audio item, LastfmUser user)
        {
            var request = new NowPlayingRequest
            {
                Track  = item.Name,
                Artist = item.Artists.First(),

                ApiKey     = Strings.Keys.LastfmApiKey,
                Method     = Strings.Methods.NowPlaying,
                SessionKey = user.SessionKey,
                Secure     = true
            };


            if (!string.IsNullOrWhiteSpace(item.Album))
            {
                request.Album = item.Album;
            }
            if (item.ProviderIds.ContainsKey("MusicBrainzTrack"))
            {
                request.MbId = item.ProviderIds["MusicBrainzTrack"];
            }

            // Add duration
            if (item.RunTimeTicks != null)
            {
                request.Duration = Convert.ToInt32(TimeSpan.FromTicks((long)item.RunTimeTicks).TotalSeconds);
            }

            try
            {
                var response = await Post <NowPlayingRequest, ScrobbleResponse>(request);

                if (response != null && !response.IsError())
                {
                    _logger.LogInformation("{0} is now playing artist={1}, track={2}, album={3}", user.Username, request.Artist, request.Track, request.Album);
                    return;
                }

                _logger.LogError("Failed to send now playing for track: {0}", item.Name);
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to send now playing for track: ex={0}, name={1}, track={2}, artist={3}, album={4}, mbid={5}", ex, item.Name, request.Track, request.Artist, request.Album, request.MbId);
            }
        }
        public async Task Scrobble(Audio item, LastfmUser user)
        {
            // API docs -> https://www.last.fm/api/show/track.scrobble
            var request = new ScrobbleRequest
            {
                Track     = item.Name,
                Artist    = item.Artists.First(),
                Timestamp = Helpers.CurrentTimestamp(),

                ApiKey     = Strings.Keys.LastfmApiKey,
                Method     = Strings.Methods.Scrobble,
                SessionKey = user.SessionKey,
                Secure     = true
            };

            if (!string.IsNullOrWhiteSpace(item.Album))
            {
                request.Album = item.Album;
            }
            if (item.ProviderIds.ContainsKey("MusicBrainzTrack"))
            {
                request.MbId = item.ProviderIds["MusicBrainzTrack"];
            }

            try
            {
                // Send the request
                var response = await Post <ScrobbleRequest, ScrobbleResponse>(request);

                if (response != null && !response.IsError())
                {
                    _logger.LogInformation("{0} played artist={1}, track={2}, album={3}", user.Username, request.Artist, request.Track, request.Album);
                    return;
                }

                _logger.LogError("Failed to Scrobble track: {0}", item.Name);
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to Scrobble track: track: ex={0}, name={1}, track={2}, artist={3}, album={4}, mbid={5}", ex, item.Name, request.Track, request.Artist, request.Album, request.MbId);
            }
        }
Exemple #13
0
        public async Task Scrobble(Audio item, LastfmUser user)
        {
            var request = new ScrobbleRequest
            {
                Track     = item.Name,
                Artist    = item.Artists.FirstOrDefault(),
                Timestamp = Helpers.CurrentTimestamp(),

                ApiKey     = Strings.Keys.LastfmApiKey,
                Method     = Strings.Methods.Scrobble,
                SessionKey = user.SessionKey
            };

            if (!string.IsNullOrWhiteSpace(item.Album))
            {
                request.Album = item.Album;
            }

            if (item.ProviderIds.ContainsKey("MusicBrainzTrack"))
            {
                request.MbId = item.ProviderIds["MusicBrainzTrack"];
            }

            try
            {
                //Send the request
                var response = await Post <ScrobbleRequest, ScrobbleResponse>(request);

                if (response != null && !response.IsError())
                {
                    Plugin.Logger.Info("{0} played '{1}' - {2} - {3}", user.Username, request.Track, request.Album, request.Artist);
                    return;
                }

                Plugin.Logger.Error("Failed to Scrobble track: {0}", item.Name);
            }
            catch (Exception ex)
            {
                Plugin.Logger.ErrorException("Failed to Scrobble track: {0}", ex, item.Name);
            }
        }
        /// <summary>
        /// Loves or unloves a track
        /// </summary>
        /// <param name="item">The track</param>
        /// <param name="user">The Lastfm User</param>
        /// <param name="love">If the track is loved or not</param>
        /// <returns></returns>
        public async Task <bool> LoveTrack(Audio item, LastfmUser user, bool love = true)
        {
            var request = new TrackLoveRequest(love)
            {
                Artist     = item.Artists.First(),
                Track      = item.Name,
                SessionKey = user.SessionKey,
            };

            //Send the request
            var response = await Post <TrackLoveRequest, BaseResponse>(request).ConfigureAwait(false);

            if (response == null || response.IsError())
            {
                Plugin.Logger.Error("{0} Failed to love = {3} track '{1}' - {2}", user.Username, item.Name, response?.Message ?? "empty response", love);
                return(false);
            }

            Plugin.Logger.Info("{0} {2}loved track '{1}'", user.Username, item.Name, love ? "" : "un");
            return(true);
        }
        public async Task NowPlaying(Audio item, LastfmUser user)
        {
            if (string.IsNullOrWhiteSpace(item.Name))
            {
                Plugin.Logger.Error("Cannot set now playing for track: {0}, no name", item.Id);
                return;
            }

            var artist = item.Artists?.FirstOrDefault();

            if (string.IsNullOrWhiteSpace(artist))
            {
                Plugin.Logger.Error("Cannot set now playing for track: {0} ({1}), no artist found", item.Id, item.Name);
                return;
            }

            var request = new NowPlayingRequest
            {
                Track      = item.Name,
                Artist     = artist,
                Album      = item.Album,
                SessionKey = user.SessionKey
            };

            //Add duration
            if (item.RunTimeTicks != null)
            {
                request.Duration = Convert.ToInt32(TimeSpan.FromTicks((long)item.RunTimeTicks).TotalSeconds);
            }

            var response = await Post <NowPlayingRequest, ScrobbleResponse>(request).ConfigureAwait(false);

            if (response != null && !response.IsError())
            {
                Plugin.Logger.Info("{0} is now playing '{1}' - {2} - {3}", user.Username, request.Track, request.Album, request.Artist);
                return;
            }

            Plugin.Logger.Error("Failed to send now playing for track: {0}", item.Name);
        }
Exemple #16
0
        public async Task Scrobble(Audio item, LastfmUser user)
        {
            var request = new ScrobbleRequest
            {
                Track     = item.Name,
                Album     = item.Album,
                Artist    = item.Artists.First(),
                Timestamp = Helpers.CurrentTimestamp(),

                ApiKey     = Strings.Keys.LastfmApiKey,
                Method     = Strings.Methods.Scrobble,
                SessionKey = user.SessionKey
            };

            var response = await Post <ScrobbleRequest, ScrobbleResponse>(request);

            if (response != null && !response.IsError())
            {
                Plugin.Logger.Info("{0} played '{1}' - {2} - {3}", user.Username, request.Track, request.Album, request.Artist);
                return;
            }

            Plugin.Logger.Error("Failed to Scrobble track: {0}", item.Name);
        }
Exemple #17
0
        private async Task <List <LastfmArtistTrack> > GetArtistTracks(LastfmUser lastfmUser, MusicArtist artist, IProgress <double> progress, CancellationToken cancellationToken, double maxProgress, double progressOffset)
        {
            var  tracks = new List <LastfmArtistTrack>();
            var  page   = 1; //Page 0 = 1
            bool moreTracks;

            do
            {
                cancellationToken.ThrowIfCancellationRequested();

                var response = await _apiClient.GetArtistTracks(lastfmUser, artist, cancellationToken, page ++).ConfigureAwait(false);

                if (response == null || !response.HasTracks())
                {
                    break;
                }

                tracks.AddRange(response.ArtistTracks.Tracks);

                moreTracks = !response.ArtistTracks.Metadata.IsLastPage();
            } while (moreTracks);

            return(tracks);
        }
        public async Task Scrobble(Audio item, LastfmUser user)
        {
            var request = new ScrobbleRequest
            {
                Track      = item.Name,
                Album      = item.Album,
                Artist     = item.Artists.First(),
                Timestamp  = Helpers.CurrentTimestamp(),

                ApiKey     = Strings.Keys.LastfmApiKey,
                Method     = Strings.Methods.Scrobble,
                SessionKey = user.SessionKey
            };

            var response = await Post<ScrobbleRequest, ScrobbleResponse>(request);

            if (response != null && !response.IsError())
            {
                Plugin.Logger.Info("{0} played '{1}' - {2} - {3}", user.Username, request.Track, request.Album, request.Artist);
                return;
            }

            Plugin.Logger.Error("Failed to Scrobble track: {0}", item.Name);
        }
        /// <summary>
        /// Loves or unloves a track
        /// </summary>
        /// <param name="item">The track</param>
        /// <param name="user">The Lastfm User</param>
        /// <param name="love">If the track is loved or not</param>
        /// <returns></returns>
        public async Task<bool> LoveTrack(Audio item, LastfmUser user, bool love = true)
        {
            var request = new TrackLoveRequest
            {
                Artist = item.Artists.First(),
                Track  = item.Name,

                ApiKey     = Strings.Keys.LastfmApiKey,
                Method     = love ? Strings.Methods.TrackLove : Strings.Methods.TrackUnlove,
                SessionKey = user.SessionKey,
            };

            //Send the request
            var response = await Post<TrackLoveRequest, BaseResponse>(request);

            if (response != null && !response.IsError())
            {
                Plugin.Logger.Info("{0} {2}loved track '{1}'", user.Username, item.Name, (love ? "" : "un"));
                return true;
            }

            Plugin.Logger.Error("{0} Failed to love = {3} track '{1}' - {2}", user.Username, item.Name, response.Message, love);
            return false;
        }
Exemple #20
0
 /// <summary>
 /// Unlove a track. This is the same as LoveTrack with love as false
 /// </summary>
 /// <param name="item">The track</param>
 /// <param name="user">The Lastfm User</param>
 /// <returns></returns>
 public async Task <bool> UnloveTrack(Audio item, LastfmUser user)
 {
     return(await LoveTrack(item, user, false));
 }
 /// <summary>
 /// Unlove a track. This is the same as LoveTrack with love as false
 /// </summary>
 /// <param name="item">The track</param>
 /// <param name="user">The Lastfm User</param>
 /// <returns></returns>
 public async Task<bool> UnloveTrack(Audio item, LastfmUser user)
 {
     return await LoveTrack(item, user, false);
 }
Exemple #22
0
        private async Task SyncDataforUserByArtistBulk(User user, IProgress <double> progress, CancellationToken cancellationToken, double maxProgress, double progressOffset)
        {
            LastfmUser lastFmUser = UserHelpers.GetUser(user);

            if (!lastFmUser.Options.SyncFavourites)
            {
                return;
            }

            _logger.LogInformation("Syncing LastFM favourties for {0}", user.Username);

            List <MusicArtist> artists = _libraryManager.GetArtists(new InternalItemsQuery(user))
                                         .Items
                                         .Select(i => i.Item1)
                                         .Cast <MusicArtist>()
                                         .ToList();

            int matchedSongs = 0;

            // Fetch the user's loved tracks from LastFM API.
            List <LastfmLovedTrack> lovedTracks = await GetLovedTracksLibrary(lastFmUser, progress, cancellationToken, maxProgress, progressOffset);

            if (lovedTracks.Count == 0)
            {
                _logger.LogInformation("User {0} has no loved tracks in last.fm", user.Username);
                return;
            }

            // Group the list of loved tracks by artist
            List <IGrouping <string, LastfmLovedTrack> > groupedLovedTracks = lovedTracks.GroupBy(t => t.Artist.MusicBrainzId).ToList();

            // Iterate over each artist in user's library
            // iterate over each song by artist
            // for each song, compare against the list of song/track in the lastfm loved track list
            foreach (MusicArtist artist in artists)
            {
                cancellationToken.ThrowIfCancellationRequested();

                string artistMBid = Helpers.GetMusicBrainzArtistId(artist);
                if (artistMBid == null)
                {
                    continue;
                }

                if (groupedLovedTracks.FirstOrDefault(t => t.Key.Equals(artistMBid)) == null || !groupedLovedTracks.FirstOrDefault(t => t.Key.Equals(artistMBid)).Any())
                {
                    continue;
                }

                _logger.LogDebug("Found {0} LastFM lovedtracks for {1}",
                                 groupedLovedTracks.FirstOrDefault(t => t.Key.Equals(artistMBid)).ToList().Count,
                                 artist.Name);
                // Loop through each song
                foreach (Audio song in artist.GetTaggedItems(new InternalItemsQuery(user)
                {
                    IncludeItemTypes = new[] { "Audio" },
                    EnableTotalRecordCount = false
                }).OfType <Audio>().ToList())
                {
                    LastfmLovedTrack matchedSong = Helpers.FindMatchedLastfmSong(groupedLovedTracks.FirstOrDefault(t => t.Key.Equals(artistMBid)).ToList(), song);

                    if (matchedSong == null)
                    {
                        continue;
                    }

                    // We have found a match
                    matchedSongs++;

                    var userData = _userDataManager.GetUserData(user, song);
                    userData.IsFavorite = true;
                    _userDataManager.SaveUserData(user, song, userData, UserDataSaveReason.UpdateUserRating, cancellationToken);
                    _logger.LogDebug("Found library match for {0} = {1}", song.Name, matchedSong.Name);
                }
            }

            _logger.LogInformation("Finished Last.fm lovedTracks sync for {0}. Matched Songs: {2}", user.Username, matchedSongs);
        }
        public async Task<LovedTracksResponse> GetLovedTracks(LastfmUser user)
        {
            var request = new GetLovedTracksRequest
            {
                User   = user.Username,
                ApiKey = Strings.Keys.LastfmApiKey,
                Method = Strings.Methods.GetLovedTracks
            };

            return await Get<GetLovedTracksRequest, LovedTracksResponse>(request);
        }
        public async Task<GetTracksResponse> GetTracks(LastfmUser user, MusicArtist artist, CancellationToken cancellationToken)
        {
            var request = new GetTracksRequest
            {
                User   = user.Username,
                Artist = artist.Name,
                ApiKey = Strings.Keys.LastfmApiKey,
                Method = Strings.Methods.GetTracks,
                Limit  = 1000
            };

            return await Get<GetTracksRequest, GetTracksResponse>(request, cancellationToken);
        }
        public async Task<GetTracksResponse> GetTracks(LastfmUser user, CancellationToken cancellationToken, int page = 0, int limit = 200)
        {
            var request = new GetTracksRequest
            {
                User   = user.Username,
                ApiKey = Strings.Keys.LastfmApiKey,
                Method = Strings.Methods.GetTracks,
                Limit  = limit,
                Page   = page
            };

            return await Get<GetTracksRequest, GetTracksResponse>(request, cancellationToken);
        }
 /// <summary>
 /// Initializes a new instance of the <see cref="PluginConfiguration" /> class.
 /// </summary>
 public PluginConfiguration()
 {
     LastfmUsers = new LastfmUser[] { };
 }
        private async Task<List<LastfmTrack>> GetUsersLibrary(LastfmUser lastfmUser, IProgress<double> progress, CancellationToken cancellationToken, double maxProgress, double progressOffset)
        {
            var tracks     = new List<LastfmTrack>();
            var page       = 1; //Page 0 = 1
            bool moreTracks;

            do
            {
                cancellationToken.ThrowIfCancellationRequested();

                var response = await _apiClient.GetTracks(lastfmUser, cancellationToken, page++).ConfigureAwait(false);

                if (response == null || !response.HasTracks())
                    break;

                tracks.AddRange(response.Tracks.Tracks);

                moreTracks = !response.Tracks.Metadata.IsLastPage();

                //Only report progress in download because it will be 90% of the time taken
                var currentProgress = ((double)response.Tracks.Metadata.Page / response.Tracks.Metadata.TotalPages) * (maxProgress - progressOffset) + progressOffset;
                
                Plugin.Logger.Debug("Progress: " + currentProgress * 100);
                
                progress.Report(currentProgress * 100);
            } while (moreTracks);

            return tracks;
        }