private ItemsResult GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, Func <BaseItem, List <PersonInfo>, List <PersonInfo>, BaseItem, int> getSimilarityScore) { var user = !string.IsNullOrWhiteSpace(request.UserId) ? _userManager.GetUserById(request.UserId) : null; var item = string.IsNullOrEmpty(request.Id) ? (!string.IsNullOrWhiteSpace(request.UserId) ? user.RootFolder : _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); var inputItems = _libraryManager.GetArtists(user.RootFolder.GetRecursiveChildren(user, i => i is IHasArtist).OfType <IHasArtist>()); var list = inputItems.ToList(); var items = SimilarItemsHelper.GetSimilaritems(item, _libraryManager, list, getSimilarityScore).ToList(); IEnumerable <BaseItem> returnItems = items; if (request.Limit.HasValue) { returnItems = returnItems.Take(request.Limit.Value); } var dtoOptions = GetDtoOptions(request); var result = new ItemsResult { Items = _dtoService.GetBaseItemDtos(returnItems, dtoOptions, user).ToArray(), TotalRecordCount = items.Count }; return(result); }
/// <summary> /// Runs the specified progress. /// </summary> /// <param name="progress">The progress.</param> /// <param name="cancellationToken">The cancellation token.</param> /// <returns>Task.</returns> public async Task Run(IProgress <double> progress, CancellationToken cancellationToken) { var allSongs = _libraryManager.RootFolder .GetRecursiveChildren(i => !i.IsFolder && (i is IHasArtist)) .Cast <IHasArtist>() .ToList(); var allArtists = _libraryManager.GetArtists(allSongs).ToList(); var numComplete = 0; var numArtists = allArtists.Count; foreach (var artistItem in allArtists) { cancellationToken.ThrowIfCancellationRequested(); try { await artistItem.RefreshMetadata(cancellationToken).ConfigureAwait(false); } catch (IOException ex) { _logger.ErrorException("Error validating Artist {0}", ex, artistItem.Name); } // Update progress numComplete++; double percent = numComplete; percent /= numArtists; progress.Report(100 * percent); } }
private QueryResult <ServerItem> GetMusicArtists(BaseItem parent, User user, InternalItemsQuery query) { var artists = _libraryManager.GetArtists(new InternalItemsQuery(user) { AncestorIds = new[] { parent.Id.ToString("N") }, StartIndex = query.StartIndex, Limit = query.Limit }); var result = new QueryResult <BaseItem> { TotalRecordCount = artists.TotalRecordCount, Items = artists.Items.Select(i => i.Item1).ToArray(artists.Items.Length) }; return(ToResult(result)); }
private QueryResult <BaseItemDto> GetSimilarItemsResult(BaseGetSimilarItemsFromItem request, string[] includeItemTypes) { var user = !request.UserId.Equals(Guid.Empty) ? _userManager.GetUserById(request.UserId) : null; var item = string.IsNullOrEmpty(request.Id) ? (!request.UserId.Equals(Guid.Empty) ? _libraryManager.GetUserRootFolder() : _libraryManager.RootFolder) : _libraryManager.GetItemById(request.Id); var dtoOptions = GetDtoOptions(_authContext, request); var query = new InternalItemsQuery(user) { Limit = request.Limit, IncludeItemTypes = includeItemTypes, SimilarTo = item, DtoOptions = dtoOptions, EnableTotalRecordCount = false }; // ExcludeArtistIds if (!string.IsNullOrEmpty(request.ExcludeArtistIds)) { query.ExcludeArtistIds = BaseApiService.GetGuids(request.ExcludeArtistIds); } List <BaseItem> itemsResult; if (item is MusicArtist) { query.IncludeItemTypes = Array.Empty <string>(); itemsResult = _libraryManager.GetArtists(query).Items.Select(i => i.Item1).ToList(); } else { itemsResult = _libraryManager.GetItemList(query); } var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user); var result = new QueryResult <BaseItemDto> { Items = returnList, TotalRecordCount = itemsResult.Count }; return(result); }
public ActionResult <QueryResult <BaseItemDto> > GetArtists( [FromQuery] double?minCommunityRating, [FromQuery] int?startIndex, [FromQuery] int?limit, [FromQuery] string?searchTerm, [FromQuery] string?parentId, [FromQuery] string?fields, [FromQuery] string?excludeItemTypes, [FromQuery] string?includeItemTypes, [FromQuery] string?filters, [FromQuery] bool?isFavorite, [FromQuery] string?mediaTypes, [FromQuery] string?genres, [FromQuery] string?genreIds, [FromQuery] string?officialRatings, [FromQuery] string?tags, [FromQuery] string?years, [FromQuery] bool?enableUserData, [FromQuery] int?imageTypeLimit, [FromQuery] string?enableImageTypes, [FromQuery] string?person, [FromQuery] string?personIds, [FromQuery] string?personTypes, [FromQuery] string?studios, [FromQuery] string?studioIds, [FromQuery] Guid?userId, [FromQuery] string?nameStartsWithOrGreater, [FromQuery] string?nameStartsWith, [FromQuery] string?nameLessThan, [FromQuery] bool?enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request) .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); User? user = null; BaseItem parentItem; if (userId.HasValue && !userId.Equals(Guid.Empty)) { user = _userManager.GetUserById(userId.Value); parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.GetUserRootFolder() : _libraryManager.GetItemById(parentId); } else { parentItem = string.IsNullOrEmpty(parentId) ? _libraryManager.RootFolder : _libraryManager.GetItemById(parentId); } var excludeItemTypesArr = RequestHelpers.Split(excludeItemTypes, ',', true); var includeItemTypesArr = RequestHelpers.Split(includeItemTypes, ',', true); var mediaTypesArr = RequestHelpers.Split(mediaTypes, ',', true); var query = new InternalItemsQuery(user) { ExcludeItemTypes = excludeItemTypesArr, IncludeItemTypes = includeItemTypesArr, MediaTypes = mediaTypesArr, StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, NameLessThan = nameLessThan, NameStartsWith = nameStartsWith, NameStartsWithOrGreater = nameStartsWithOrGreater, Tags = RequestHelpers.Split(tags, ',', true), OfficialRatings = RequestHelpers.Split(officialRatings, ',', true), Genres = RequestHelpers.Split(genres, ',', true), GenreIds = RequestHelpers.GetGuids(genreIds), StudioIds = RequestHelpers.GetGuids(studioIds), Person = person, PersonIds = RequestHelpers.GetGuids(personIds), PersonTypes = RequestHelpers.Split(personTypes, ',', true), Years = RequestHelpers.Split(years, ',', true).Select(int.Parse).ToArray(), MinCommunityRating = minCommunityRating, DtoOptions = dtoOptions, SearchTerm = searchTerm, EnableTotalRecordCount = enableTotalRecordCount }; if (!string.IsNullOrWhiteSpace(parentId)) { if (parentItem is Folder) { query.AncestorIds = new[] { new Guid(parentId) }; } else { query.ItemIds = new[] { new Guid(parentId) }; } } // Studios if (!string.IsNullOrEmpty(studios)) { query.StudioIds = studios.Split('|').Select(i => { try { return(_libraryManager.GetStudio(i)); } catch { return(null); } }).Where(i => i != null).Select(i => i !.Id).ToArray(); } foreach (var filter in RequestHelpers.GetFilters(filters)) { switch (filter) { case ItemFilter.Dislikes: query.IsLiked = false; break; case ItemFilter.IsFavorite: query.IsFavorite = true; break; case ItemFilter.IsFavoriteOrLikes: query.IsFavoriteOrLiked = true; break; case ItemFilter.IsFolder: query.IsFolder = true; break; case ItemFilter.IsNotFolder: query.IsFolder = false; break; case ItemFilter.IsPlayed: query.IsPlayed = true; break; case ItemFilter.IsResumable: query.IsResumable = true; break; case ItemFilter.IsUnplayed: query.IsPlayed = false; break; case ItemFilter.Likes: query.IsLiked = true; break; } } var result = _libraryManager.GetArtists(query); var dtos = result.Items.Select(i => { var(baseItem, itemCounts) = i; var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user); if (!string.IsNullOrWhiteSpace(includeItemTypes)) { dto.ChildCount = itemCounts.ItemCount; dto.ProgramCount = itemCounts.ProgramCount; dto.SeriesCount = itemCounts.SeriesCount; dto.EpisodeCount = itemCounts.EpisodeCount; dto.MovieCount = itemCounts.MovieCount; dto.TrailerCount = itemCounts.TrailerCount; dto.AlbumCount = itemCounts.AlbumCount; dto.SongCount = itemCounts.SongCount; dto.ArtistCount = itemCounts.ArtistCount; } return(dto); }); return(new QueryResult <BaseItemDto> { Items = dtos.ToArray(), TotalRecordCount = result.TotalRecordCount }); }
private QueryResult <BaseItemDto> GetSimilarItemsResult( BaseItem item, string?excludeArtistIds, Guid?userId, int?limit, string?fields, string[] includeItemTypes, bool isMovie) { var user = userId.HasValue && !userId.Equals(Guid.Empty) ? _userManager.GetUserById(userId.Value) : null; var dtoOptions = new DtoOptions() .AddItemFields(fields) .AddClientFields(Request); var query = new InternalItemsQuery(user) { Limit = limit, IncludeItemTypes = includeItemTypes, IsMovie = isMovie, SimilarTo = item, DtoOptions = dtoOptions, EnableTotalRecordCount = !isMovie, EnableGroupByMetadataKey = isMovie }; // ExcludeArtistIds if (!string.IsNullOrEmpty(excludeArtistIds)) { query.ExcludeArtistIds = RequestHelpers.GetGuids(excludeArtistIds); } List <BaseItem> itemsResult; if (isMovie) { var itemTypes = new List <string> { nameof(MediaBrowser.Controller.Entities.Movies.Movie) }; if (_serverConfigurationManager.Configuration.EnableExternalContentInSuggestions) { itemTypes.Add(nameof(Trailer)); itemTypes.Add(nameof(LiveTvProgram)); } query.IncludeItemTypes = itemTypes.ToArray(); itemsResult = _libraryManager.GetArtists(query).Items.Select(i => i.Item1).ToList(); } else if (item is MusicArtist) { query.IncludeItemTypes = Array.Empty <string>(); itemsResult = _libraryManager.GetArtists(query).Items.Select(i => i.Item1).ToList(); } else { itemsResult = _libraryManager.GetItemList(query); } var returnList = _dtoService.GetBaseItemDtos(itemsResult, dtoOptions, user); var result = new QueryResult <BaseItemDto> { Items = returnList, TotalRecordCount = itemsResult.Count }; return(result); }
public ActionResult <QueryResult <BaseItemDto> > GetArtists( [FromQuery] double?minCommunityRating, [FromQuery] int?startIndex, [FromQuery] int?limit, [FromQuery] string?searchTerm, [FromQuery] Guid?parentId, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFields[] fields, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] excludeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] BaseItemKind[] includeItemTypes, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ItemFilter[] filters, [FromQuery] bool?isFavorite, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] mediaTypes, [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] genres, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] genreIds, [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] officialRatings, [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] tags, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] int[] years, [FromQuery] bool?enableUserData, [FromQuery] int?imageTypeLimit, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] ImageType[] enableImageTypes, [FromQuery] string?person, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] personIds, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] personTypes, [FromQuery, ModelBinder(typeof(PipeDelimitedArrayModelBinder))] string[] studios, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] Guid[] studioIds, [FromQuery] Guid?userId, [FromQuery] string?nameStartsWithOrGreater, [FromQuery] string?nameStartsWith, [FromQuery] string?nameLessThan, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] string[] sortBy, [FromQuery, ModelBinder(typeof(CommaDelimitedArrayModelBinder))] SortOrder[] sortOrder, [FromQuery] bool?enableImages = true, [FromQuery] bool enableTotalRecordCount = true) { var dtoOptions = new DtoOptions { Fields = fields } .AddClientFields(Request) .AddAdditionalDtoOptions(enableImages, enableUserData, imageTypeLimit, enableImageTypes); User? user = null; BaseItem parentItem = _libraryManager.GetParentItem(parentId, userId); if (userId.HasValue && !userId.Equals(Guid.Empty)) { user = _userManager.GetUserById(userId.Value); } var query = new InternalItemsQuery(user) { ExcludeItemTypes = excludeItemTypes, IncludeItemTypes = includeItemTypes, MediaTypes = mediaTypes, StartIndex = startIndex, Limit = limit, IsFavorite = isFavorite, NameLessThan = nameLessThan, NameStartsWith = nameStartsWith, NameStartsWithOrGreater = nameStartsWithOrGreater, Tags = tags, OfficialRatings = officialRatings, Genres = genres, GenreIds = genreIds, StudioIds = studioIds, Person = person, PersonIds = personIds, PersonTypes = personTypes, Years = years, MinCommunityRating = minCommunityRating, DtoOptions = dtoOptions, SearchTerm = searchTerm, EnableTotalRecordCount = enableTotalRecordCount, OrderBy = RequestHelpers.GetOrderBy(sortBy, sortOrder) }; if (parentId.HasValue) { if (parentItem is Folder) { query.AncestorIds = new[] { parentId.Value }; } else { query.ItemIds = new[] { parentId.Value }; } } // Studios if (studios.Length != 0) { query.StudioIds = studios.Select(i => { try { return(_libraryManager.GetStudio(i)); } catch { return(null); } }).Where(i => i != null).Select(i => i !.Id).ToArray(); } foreach (var filter in filters) { switch (filter) { case ItemFilter.Dislikes: query.IsLiked = false; break; case ItemFilter.IsFavorite: query.IsFavorite = true; break; case ItemFilter.IsFavoriteOrLikes: query.IsFavoriteOrLiked = true; break; case ItemFilter.IsFolder: query.IsFolder = true; break; case ItemFilter.IsNotFolder: query.IsFolder = false; break; case ItemFilter.IsPlayed: query.IsPlayed = true; break; case ItemFilter.IsResumable: query.IsResumable = true; break; case ItemFilter.IsUnplayed: query.IsPlayed = false; break; case ItemFilter.Likes: query.IsLiked = true; break; } } var result = _libraryManager.GetArtists(query); var dtos = result.Items.Select(i => { var(baseItem, itemCounts) = i; var dto = _dtoService.GetItemByNameDto(baseItem, dtoOptions, null, user); if (includeItemTypes.Length != 0) { dto.ChildCount = itemCounts.ItemCount; dto.ProgramCount = itemCounts.ProgramCount; dto.SeriesCount = itemCounts.SeriesCount; dto.EpisodeCount = itemCounts.EpisodeCount; dto.MovieCount = itemCounts.MovieCount; dto.TrailerCount = itemCounts.TrailerCount; dto.AlbumCount = itemCounts.AlbumCount; dto.SongCount = itemCounts.SongCount; dto.ArtistCount = itemCounts.ArtistCount; } return(dto); }); return(new QueryResult <BaseItemDto>( query.StartIndex, result.TotalRecordCount, dtos.ToArray())); }
/// <summary> /// Gets the search hints. /// </summary> /// <param name="query">The query.</param> /// <param name="user">The user.</param> /// <returns>IEnumerable{SearchHintResult}.</returns> /// <exception cref="System.ArgumentNullException">searchTerm</exception> private Task <IEnumerable <SearchHintInfo> > GetSearchHints(SearchQuery query, User user) { var searchTerm = query.SearchTerm; if (searchTerm != null) { searchTerm = searchTerm.Trim().RemoveDiacritics(); } if (string.IsNullOrWhiteSpace(searchTerm)) { throw new ArgumentNullException("searchTerm"); } var terms = GetWords(searchTerm); var excludeItemTypes = query.ExcludeItemTypes.ToList(); var includeItemTypes = (query.IncludeItemTypes ?? new string[] { }).ToList(); excludeItemTypes.Add(typeof(Year).Name); excludeItemTypes.Add(typeof(Folder).Name); if (query.IncludeGenres && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Genre", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { AddIfMissing(includeItemTypes, typeof(Genre).Name); AddIfMissing(includeItemTypes, typeof(GameGenre).Name); AddIfMissing(includeItemTypes, typeof(MusicGenre).Name); } } else { AddIfMissing(excludeItemTypes, typeof(Genre).Name); AddIfMissing(excludeItemTypes, typeof(GameGenre).Name); AddIfMissing(excludeItemTypes, typeof(MusicGenre).Name); } if (query.IncludePeople && (includeItemTypes.Count == 0 || includeItemTypes.Contains("People", StringComparer.OrdinalIgnoreCase) || includeItemTypes.Contains("Person", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { AddIfMissing(includeItemTypes, typeof(Person).Name); } } else { AddIfMissing(excludeItemTypes, typeof(Person).Name); } if (query.IncludeStudios && (includeItemTypes.Count == 0 || includeItemTypes.Contains("Studio", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { AddIfMissing(includeItemTypes, typeof(Studio).Name); } } else { AddIfMissing(excludeItemTypes, typeof(Studio).Name); } if (query.IncludeArtists && (includeItemTypes.Count == 0 || includeItemTypes.Contains("MusicArtist", StringComparer.OrdinalIgnoreCase))) { if (!query.IncludeMedia) { AddIfMissing(includeItemTypes, typeof(MusicArtist).Name); } } else { AddIfMissing(excludeItemTypes, typeof(MusicArtist).Name); } AddIfMissing(excludeItemTypes, typeof(CollectionFolder).Name); AddIfMissing(excludeItemTypes, typeof(Folder).Name); var mediaTypes = query.MediaTypes.ToList(); if (includeItemTypes.Count > 0) { excludeItemTypes.Clear(); mediaTypes.Clear(); } var searchQuery = new InternalItemsQuery(user) { NameContains = searchTerm, ExcludeItemTypes = excludeItemTypes.ToArray(excludeItemTypes.Count), IncludeItemTypes = includeItemTypes.ToArray(includeItemTypes.Count), Limit = query.Limit, IncludeItemsByName = string.IsNullOrWhiteSpace(query.ParentId), ParentId = string.IsNullOrWhiteSpace(query.ParentId) ? (Guid?)null : new Guid(query.ParentId), OrderBy = new[] { new Tuple <string, SortOrder>(ItemSortBy.SortName, SortOrder.Ascending) }, Recursive = true, IsKids = query.IsKids, IsMovie = query.IsMovie, IsNews = query.IsNews, IsSeries = query.IsSeries, IsSports = query.IsSports, MediaTypes = mediaTypes.ToArray(), DtoOptions = new DtoOptions { Fields = new ItemFields[] { ItemFields.AirTime, ItemFields.DateCreated, ItemFields.ChannelInfo } } }; List <BaseItem> mediaItems; if (searchQuery.IncludeItemTypes.Length == 1 && string.Equals(searchQuery.IncludeItemTypes[0], "MusicArtist", StringComparison.OrdinalIgnoreCase)) { if (searchQuery.ParentId.HasValue) { searchQuery.AncestorIds = new string[] { searchQuery.ParentId.Value.ToString("N") }; } searchQuery.ParentId = null; searchQuery.IncludeItemsByName = true; searchQuery.IncludeItemTypes = new string[] { }; mediaItems = _libraryManager.GetArtists(searchQuery).Items.Select(i => i.Item1).ToList(); } else { mediaItems = _libraryManager.GetItemList(searchQuery); } var returnValue = mediaItems.Select(item => { var index = GetIndex(item.Name, searchTerm, terms); return(new Tuple <BaseItem, string, int>(item, index.Item1, index.Item2)); }).OrderBy(i => i.Item3).ThenBy(i => i.Item1.SortName).Select(i => new SearchHintInfo { Item = i.Item1, MatchedTerm = i.Item2 }); return(Task.FromResult(returnValue)); }
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); }
private async Task SyncDataforUserByArtistBulk(User user, IProgress <double> progress, CancellationToken cancellationToken, double maxProgress, double progressOffset) { var artists = _libraryManager.GetArtists(new InternalItemsQuery(user)) .Items .Select(i => i.Item1) .Cast <MusicArtist>() .ToList(); var lastFmUser = UserHelpers.GetUser(user); var totalSongs = 0; var matchedSongs = 0; //Get loved tracks var lovedTracksReponse = await _apiClient.GetLovedTracks(lastFmUser).ConfigureAwait(false); var hasLovedTracks = lovedTracksReponse.HasLovedTracks(); var trackCount = 0; //Loop through each artist foreach (var artist in artists) { cancellationToken.ThrowIfCancellationRequested(); //Get all the tracks by the current artist var artistMBid = Helpers.GetMusicBrainzArtistId(artist); if (artistMBid == null) { continue; } var allArtistTracks = await GetArtistTracks(lastFmUser, artist, progress, cancellationToken, maxProgress, progressOffset).ConfigureAwait(false); //Get the tracks from lastfm for the current artist var artistTracks = allArtistTracks.Where(t => t.Artist.MusicBrainzId.Equals(artistMBid)); trackCount += artistTracks.Count(); if (artistTracks == null || !artistTracks.Any()) { Plugin.Logger.Info("{0} has no tracks in last.fm library for {1}", user.Name, artist.Name); continue; } var artistTracksList = artistTracks.ToList(); Plugin.Logger.Info("Found {0} tracks in last.fm library for {1}", artistTracksList.Count, artist.Name); //Loop through each song foreach (var song in artist.GetTaggedMediaItems(new InternalItemsQuery { IncludeItemTypes = new[] { "Audio" } }).OfType <Audio>().ToList()) { totalSongs++; var matchedSong = Helpers.FindMatchedLastfmSong(artistTracksList, song); if (matchedSong == null) { continue; } //We have found a match matchedSongs++; Plugin.Logger.Debug("Found match for {0} = {1}", song.Name, matchedSong.Name); var userData = _userDataManager.GetUserData(user, song); //Check if its a favourite track if (hasLovedTracks && lastFmUser.Options.SyncFavourites) { //Use MBID if set otherwise match on song name var favourited = lovedTracksReponse.LovedTracks.Tracks.Any( t => String.IsNullOrWhiteSpace(t.MusicBrainzId) ? StringHelper.IsLike(t.Name, matchedSong.Name) : t.MusicBrainzId.Equals(matchedSong.MusicBrainzId) ); userData.IsFavorite = favourited; Plugin.Logger.Debug("{0} Favourite: {1}", song.Name, favourited); } //Update the play count /*if (matchedSong.PlayCount > 0) * { * userData.Played = true; * userData.PlayCount = Math.Max(userData.PlayCount, matchedSong.PlayCount); * } * else * { * userData.Played = false; * userData.PlayCount = 0; * userData.LastPlayedDate = null; * }*/ _userDataManager.SaveUserData(user.InternalId, song, userData, UserDataSaveReason.UpdateUserRating, cancellationToken); } } //The percentage might not actually be correct but I'm pretty tired and don't want to think about it Plugin.Logger.Info("Finished import Last.fm library for {0}. Local Songs: {1} | Last.fm Songs: {2} | Matched Songs: {3} | {4}% match rate", user.Name, totalSongs, trackCount, matchedSongs, Math.Round(((double)matchedSongs / Math.Min(trackCount, totalSongs)) * 100)); }