Files
ZuneShell.dll/ZuneImpl/Library/StrixLibraryDataProviderQuery.cs
T
2023-10-09 00:57:37 -05:00

747 lines
32 KiB
C#

using Microsoft.Iris;
using Microsoft.Iris.Drawing;
using Microsoft.Iris.Markup;
using Microsoft.Iris.OS;
using Microsoft.Iris.Render;
using Microsoft.Zune.Playlist;
using OwlCore.Extensions;
using StrixMusic.Sdk.AppModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Microsoft.Zune.Library
{
public class StrixLibraryDataProviderQuery : DataProviderQuery
{
private LibraryVirtualList m_virtualListResultSet;
private bool m_disposed = false;
private int m_requestGeneration;
private string m_thumbnailFallbackImageUrl;
private readonly MarkupTypeSchema m_dataType;
private readonly IStrixDataRoot m_dataRoot;
private readonly Dictionary<int, string> m_albumIdMap = new();
private readonly Dictionary<int, string> m_artistIdMap = new();
private readonly Dictionary<int, string> m_trackIdMap = new();
public StrixLibraryDataProviderQuery(object typeCookie, IStrixDataRoot dataRoot) : base(typeCookie)
{
m_dataRoot = dataRoot;
m_dataType = (MarkupTypeSchema)((MarkupTypeSchema)ResultTypeCookie).Properties[0].AlternateType;
if (Application.DebugSettings.GenerateDataMappingModels)
TypeSchema.GenerateModelCode(m_dataType);
}
public bool GetSortAttributes(out string[] sorts, out bool[] ascendings)
{
if (!TryGetProperty("Sort", out string sortStr) || sortStr == null)
{
sorts = null;
ascendings = null;
return false;
}
var options = sortStr.Split(',');
sorts = new string[options.Length];
ascendings = new bool[options.Length];
for (int i = 0; i < options.Length; i++)
{
sorts[i] = options[i].Substring(1);
ascendings[i] = options[i][0] != '-';
}
return true;
}
protected override void BeginExecute()
{
if (m_virtualListResultSet is IDisposable disposableResultSet)
disposableResultSet.Dispose();
m_virtualListResultSet = null;
m_thumbnailFallbackImageUrl = null;
m_requestGeneration++;
Status = DataProviderQueryStatus.RequestingData;
ExecuteWorker(m_requestGeneration).ConfigureAwait(true);
}
private async Task ExecuteWorker(object state)
{
bool[] sortAscendings = null;
string[] sortStrings = null;
int num = (int)state;
if (num == m_requestGeneration)
{
ZuneQueryList queryList = new();
//QueryPropertyBag queryPropertyBag = new QueryPropertyBag();
//IQueryPropertyBag* iqueryPropertyBag = queryPropertyBag.GetIQueryPropertyBag();
bool retainedList = false;
if (GetSortAttributes(out sortStrings, out sortAscendings))
{
}
if (TryGetProperty<object>("ArtistIds", out var artistIds))
{
}
if (TryGetProperty<object>("GenreIds", out var genreIds))
{
}
if (TryGetProperty<object>("AlbumIds", out var albumIds))
{
}
if (TryGetProperty<object>("UserCardIds", out var userCardIds))
{
}
if (TryGetProperty<object>("DeviceId", out var deviceId))
{
}
else
{
}
if (TryGetProperty<object>("SyncMappedError", out var syncMappedError))
{
}
if (TryGetProperty<object>("UserId", out var userId))
{
}
else
{
}
if (TryGetProperty<bool>("InLibrary", out var inLibrary))
{
}
//object obj13 = calli(System.Int32 modopt(System.Runtime.CompilerServices.IsLong) modopt(System.Runtime.CompilerServices.CallConvCdecl)(System.IntPtr, EQueryPropertyBagProp, System.Int32), iqueryPropertyBag, 2, 0, *(*(long*)iqueryPropertyBag + 56L));
EQueryTypeView equeryTypeView = EQueryTypeView.eQueryTypeLibraryView;
if (TryGetProperty("ShowDeviceContents", out bool showDeviceContents))
equeryTypeView = showDeviceContents ? EQueryTypeView.eQueryTypeDeviceView : equeryTypeView;
if (TryGetProperty("DiscMediaView", out bool discMediaView))
equeryTypeView = discMediaView ? EQueryTypeView.eQueryTypeDiscMediaView : equeryTypeView;
if (TryGetProperty("Remaining", out bool remaining))
equeryTypeView = remaining ? EQueryTypeView.eQueryTypeSyncRemaining : equeryTypeView;
if (TryGetProperty("Complete", out bool complete))
equeryTypeView = complete ? EQueryTypeView.eQueryTypeSyncSucceeded : equeryTypeView;
if (TryGetProperty("Failed", out bool failed))
equeryTypeView = failed ? EQueryTypeView.eQueryTypeSyncFailed : equeryTypeView;
if (TryGetProperty("MultiSelect", out bool multiSelect))
{
equeryTypeView = (EQueryTypeView.eQueryTypeDeviceView == equeryTypeView)
? EQueryTypeView.eQueryTypeDeviceMultiSelectView
: EQueryTypeView.eQueryTypeLibraryMultiSelectView;
}
if (TryGetProperty("RulesOnly", out bool rulesOnly))
equeryTypeView = rulesOnly ? EQueryTypeView.eQueryTypeDeviceSyncRuleView : equeryTypeView;
#region Unhandled properties
//object obj14 = calli(System.Int32 modopt(System.Runtime.CompilerServices.IsLong) modopt(System.Runtime.CompilerServices.CallConvCdecl)(System.IntPtr, EQueryPropertyBagProp, System.Int32), iqueryPropertyBag, 15, equeryTypeView, *(*(long*)iqueryPropertyBag + 56L));
if (TryGetProperty("Keywords", out string keywords))
{
}
if (TryGetProperty("ContributingArtistId", out int contributingArtistId))
{
}
if (TryGetProperty("ArtistId", out int artistId))
{
}
if (TryGetProperty("GenreId", out int genreId))
{
}
if (TryGetProperty("AlbumId", out int albumId))
{
}
if (TryGetProperty("FolderId", out int folderId))
{
}
if (TryGetProperty("RecurseIntoFolder", out int recurseIntoFolders) && recurseIntoFolders != 0)
{
}
if (TryGetProperty("FolderMediaType", out string folderMediaType))
{
//EMediaTypes emediaTypes = LibraryDataProvider.NameToMediaType(folderMediaType);
}
if (TryGetProperty("MediaType", out string mediaType))
{
}
if (TryGetProperty("TOC", out string toc))
{
}
if (TryGetProperty("SeriesId", out int seriesId))
{
}
if (TryGetProperty("WatchType", out string watchType))
{
}
if (TryGetProperty("ExpiresOnly", out object expiresOnly) && expiresOnly != null)
{
}
if (TryGetProperty("Operation", out object operation))
{
}
if (TryGetProperty("InitTime", out object initTime))
{
}
if (TryGetProperty("PlaylistId", out int playlistId))
{
}
if (TryGetProperty("CategoryId", out int categoryId))
{
}
if (TryGetProperty("PlaylistType", out string playlistTypeStr) && !string.IsNullOrEmpty(playlistTypeStr))
{
PlaylistType playlistType = (PlaylistType)Enum.Parse(typeof(PlaylistType), playlistTypeStr);
//object obj32 = calli(System.Int32 modopt(System.Runtime.CompilerServices.IsLong) modopt(System.Runtime.CompilerServices.CallConvCdecl)(System.IntPtr, EQueryPropertyBagProp, System.Int32), iqueryPropertyBag, 24, playlistType, *(*(long*)iqueryPropertyBag + 56L));
}
if (TryGetProperty("PlaylistTypeMask", out int playlistTypeMask))
{
if (playlistTypeMask != 0)
{
}
}
if (!TryGetProperty("MaxResultCount", out int maxResultCount))
{
maxResultCount = int.MaxValue;
}
var property19 = GetProperty("DrmStateMask");
if (TryGetProperty("DrmStateMask", out ulong drmStateMask))
{
if (drmStateMask != 0UL)
{
}
}
#endregion
var filterIds = (albumId, artistId, genreId);
string text = (string)GetProperty("QueryType");
EQueryType queryType = EQueryType.eQueryTypeInvalid;
if (keywords != null)//queryPropertyBag.IsSet("Keywords"))
{
if (text == "Artist")
{
queryType = EQueryType.eQueryTypeArtistsWithKeyword;
}
else if (text == "Album")
{
queryType = EQueryType.eQueryTypeAlbumsWithKeyword;
}
else if (text == "Track")
{
queryType = EQueryType.eQueryTypeTracksWithKeyword;
}
else if (text == "Playlist")
{
queryType = EQueryType.eQueryTypePlaylistsWithKeyword;
}
else if (text == "Photo")
{
queryType = EQueryType.eQueryTypePhotosWithKeyword;
}
else if (text == "PodcastSeries")
{
queryType = EQueryType.eQueryTypeSubscriptionsSeriesWithKeyword;
}
else if (text == "PodcastEpisode")
{
queryType = EQueryType.eQueryTypeSubscriptionsEpisodesWithKeyword;
}
else if (text == "Video")
{
queryType = EQueryType.eQueryTypeVideoWithKeyword;
}
}
else if (text == "Artist")
{
queryType = EQueryType.eQueryTypeAllAlbumArtists;
var stArtists = m_dataRoot.Library.GetArtistItemsAsync(int.MaxValue, 0);
await foreach (var stPlayableArtist in stArtists)
{
var stArtist = stPlayableArtist as IArtist;
UriImage image = null;
if (stArtist != null)
{
var stImage = await stArtist.GetImagesAsync(1, 0).FirstOrDefaultAsync();
if (stImage != null && stImage.Sources.Count > 0)
{
var imageSource = stImage.Sources[0];
using var imageStream = await imageSource.OpenStreamAsync();
var imageBytes = await imageStream.ToBytesAsync();
BytesResource imageResource = new(stArtist.Id, imageBytes, stArtist.Id, false);
image = new(imageResource, stArtist.Id + "_img", Inset.Zero, new Size(int.MaxValue, int.MaxValue), true);
}
}
Schemas.Artist artist = new(m_dataType)
{
Copyright = "©",
DateLastPlayed = stPlayableArtist.LastPlayed ?? DateTime.Now,
DeviceFileSize = 0L,
DrmStateMask = 0,
Image = image,
LibraryId = stPlayableArtist.Id.HashToInt32(),
NumberOfAlbums = stArtist?.TotalAlbumItemsCount ?? 0,
QuickMixState = 0,
SyncState = 0,
Title = stPlayableArtist.Name,
Type = "artist",
UserRating = 0,
ZuneMediaId = stPlayableArtist.Id.HashToGuid()
};
queryList.Add(artist.Item);
}
}
else if (text == "Genres")
{
if (GetProperty("MediaType") is not int genreMediaType)
genreMediaType = 3;
queryType = EQueryType.eQueryTypeAllGenres;
// Strix doesn't support getting a list of genres, so we'll
// instead get a list of all children and create a set of
// genres from that.
var stChildren = m_dataRoot.Library.GetTracksAsync(int.MaxValue, 0);
HashSet<string> knownGenres = new();
await foreach (var stChild in stChildren)
{
if (stChild is not IGenreCollection stGenreCollection)
continue;
var genreNames = stGenreCollection.GetGenresAsync(int.MaxValue, 0)
.Select(g => g.Name);
await foreach (var genreName in genreNames)
{
if (knownGenres.Contains(genreName))
continue;
knownGenres.Add(genreName);
Schemas.Genre genre = new(m_dataType)
{
LibraryId = genreName.HashToInt32(),
Title = genreName,
SyncState = 0,
Type = "genre",
DeviceFileSize = 0L,
Copyright = "©",
DateLastPlayed = DateTime.Now
};
queryList.Add(genre.Item);
}
}
}
else if (text == "Album")
{
if (TryGetProperty("ArtistId", out artistId) && artistId != -1)
queryType = EQueryType.eQueryTypeAlbumsForAlbumArtistId;
else if (TryGetProperty("GenreId", out genreId) && genreId != -1)
queryType = EQueryType.eQueryTypeAlbumsByGenreId;
else
queryType = EQueryType.eQueryTypeAllAlbums;
retainedList = true;
var stAlbums = m_dataRoot.Library.GetAlbumItemsAsync(int.MaxValue, 0);
await foreach (var stAlbumItem in stAlbums)
{
var stAlbum = stAlbumItem as IAlbum;
var stAlbumArtist = stAlbum != null
? await stAlbum.GetArtistItemsAsync(int.MaxValue, 0).FirstOrDefaultAsync()
: null;
// Handle filters
var currentArtistId = stAlbumArtist?.Id.HashToInt32() ?? -1;
if (queryType == EQueryType.eQueryTypeAlbumsForAlbumArtistId && currentArtistId != artistId)
{
// Ignore all other artists
continue;
}
else if (queryType == EQueryType.eQueryTypeAlbumsByGenreId)
{
var containsCurrentGenre = await stAlbum.GetGenresAsync(int.MaxValue, 0)
.Select(g => g.Name.HashToInt32())
.AnyAsync(g => g == genreId);
if (!containsCurrentGenre)
{
// If the album doesn't have the genre, the tracks might.
containsCurrentGenre = await stAlbum.GetTracksAsync(int.MaxValue, 0)
.SelectMany(t => t.GetGenresAsync(int.MaxValue, 0))
.Select(g => g.Name.HashToInt32())
.AnyAsync(g => g == genreId);
if (!containsCurrentGenre) continue;
}
}
Schemas.Album album = new(m_dataType)
{
ArtistLibraryId = currentArtistId,
ArtistName = stAlbumArtist?.Name,
DateAdded = DateTime.Now,
ContributingArtistCount = 0,
Copyright = "",
DateLastPlayed = stAlbumArtist.LastPlayed ?? DateTime.Now,
DeviceFileSize = 0L,
DisplayArtistCount = 0,
DrmStateMask = 0,
ReleaseDate = stAlbum.DatePublished ?? DateTime.Now,
HasAlbumArt = true,
LibraryId = stAlbumItem.Id.HashToInt32(),
QuickMixState = 0,
SyncState = 0,
ThumbnailPath = null,
Title = stAlbumItem.Name,
Type = "album",
ZuneMediaId = stAlbumItem.Id.HashToGuid(),
};
UriImage image = null;
if (stAlbum != null)
{
var stImage = await stAlbum.GetImagesAsync(1, 0).FirstOrDefaultAsync();
if (stImage != null && stImage.Sources.Count > 0)
{
var imageSource = stImage.Sources[0];
using var imageStream = await imageSource.OpenStreamAsync();
var imageBytes = await imageStream.ToBytesAsync();
BytesResource imageResource = new(stAlbum.Id, imageBytes, stAlbum.Id, false);
image = new(imageResource, stAlbum.Id + "_img", Inset.Zero, new Size(int.MaxValue, int.MaxValue), true);
}
}
album.AlbumArtSmall = album.AlbumArtLarge = album.AlbumArtSuperLarge = image;
queryList.Add(album.Item);
}
}
else if (text == "Track")
{
if (GetProperty("RulesOnly") is bool queryAllTracks)
queryType = EQueryType.eQueryTypeAllTracks;
int albumArtistId = -1;
bool detailed = false;
if (TryGetProperty("AlbumId", out albumId) && albumId != -1)
{
if (TryGetProperty("ArtistId", out albumArtistId) && albumArtistId != -1)
queryType = EQueryType.eQueryTypeTracksForAlbumArtistId;
else
queryType = EQueryType.eQueryTypeTracksForAlbumId;
}
else
{
if (TryGetProperty("ArtistId", out artistId) && artistId != -1)
{
queryType = EQueryType.eQueryTypeTracksForAlbumArtistId;
}
else
{
if (TryGetProperty("GenreId", out genreId) && genreId != -1)
{
queryType = EQueryType.eQueryTypeTracksByGenreId;
}
else
{
if (TryGetProperty("Detailed", out detailed) && detailed)
{
queryType = EQueryType.eQueryTypeAllTracksDetailed;
}
else
{
if (TryGetProperty("TOC", out toc) && !string.IsNullOrEmpty(toc))
queryType = EQueryType.eQueryTypeTracksForTOC;
else
queryType = EQueryType.eQueryTypeAllTracks;
}
}
}
}
var stTracks = m_dataRoot.Library.GetTracksAsync(int.MaxValue, 0);
await foreach (var stTrack in stTracks)
{
var track = await CreateTrack(stTrack, queryType, filterIds);
queryList.Add(track.Item);
}
}
else if (text == "AlbumByTOC")
{
queryType = EQueryType.eQueryTypeAlbumsByTOC;
//if (!queryPropertyBag.IsSet("TOC"))
//{
// equeryType = EQueryType.eQueryTypeInvalid;
//}
}
else if (text == "Photo")
{
queryType = (equeryTypeView == EQueryTypeView.eQueryTypeDeviceSyncRuleView)
? EQueryType.eQueryTypeAllPhotos
: EQueryType.eQueryTypePhotosByFolderId;
}
else if (text == "MediaFolder")
{
queryType = EQueryType.eQueryTypeMediaFolders;
}
else if (text == "Video")
{
if (TryGetProperty("CategoryId", out categoryId) && categoryId != -1)
queryType = EQueryType.eQueryTypeVideosByCategoryId;
else
queryType = EQueryType.eQueryTypeAllVideos;
}
else if (text == "PodcastSeries")
{
queryType = EQueryType.eQueryTypeAllPodcastSeries;
}
else if (text == "PodcastEpisode")
{
if (TryGetProperty("SeriesId", out seriesId) && seriesId != -1)
queryType = EQueryType.eQueryTypeEpisodesForSeriesId;
else
queryType = EQueryType.eQueryTypeAllPodcastEpisodes;
}
else if (text == "SyncItem")
{
queryType = EQueryType.eQueryTypeSyncProgress;
}
else if (text == "Playlist")
{
queryType = EQueryType.eQueryTypeAllPlaylists;
}
else if (text == "PlaylistContent")
{
queryType = EQueryType.eQueryTypePlaylistContentByPlaylistId;
}
else if (text == "UserCard")
{
queryType = EQueryType.eQueryTypeUserCards;
}
else if (text == "Person")
{
queryType = EQueryType.eQueryTypePersonsByTypeId;
EMediaTypes personType = EMediaTypes.eMediaTypePersonArtist;
personType = ((string)GetProperty("PersonType") == "Composer")
? EMediaTypes.eMediaTypePersonComposer
: personType;
}
else if (text == "ArtistsRanking")
{
queryType = EQueryType.eQueryTypeArtistsRanking;
}
else if (text == "TVSeries")
{
queryType = EQueryType.eQueryTypeVideoSeriesTitles;
}
else if (text == "Pin")
{
queryType = EQueryType.eQueryTypePinsByPinType;
if (!TryGetProperty("PinType", out EPinType pinType))
pinType = EPinType.ePinTypeGeneric;
var pinnedTracks = m_dataRoot.Library.GetTracksAsync(3, 0);
Schemas.Pin pin = new(m_dataType)
{
PinId = 42,
PinType = 1,
Ordinal = 1,
Description = "An OpenZune pin",
MediaId = 1,
MediaType = 1,
ZuneMediaRef = "ZuneSomethingHehe",
UserId = 0,
DateModified = DateTime.Now,
ZuneMediaType = 0,
};
//queryList.Add(pin.Item);
}
else if (text == "App")
{
queryType = EQueryType.eQueryTypeAllApps;
}
queryList.QueryType = queryType;
DeferredSetResult(new DeferredSetResultArgs(num, queryList, false));// retainedList));
}
}
private void DeferredSetResult(object state)
{
DeferredSetResultArgs deferredSetResultArgs = (DeferredSetResultArgs)state;
bool isEmpty = true;
if (deferredSetResultArgs.QueryList != null)
{
if (!TryGetProperty("AutoRefresh", out bool autoRefresh))
autoRefresh = true;
if (!TryGetProperty("AntialiasImageEdges", out bool antialiasEdges))
antialiasEdges = false;
m_thumbnailFallbackImageUrl = (string)GetProperty("ThumbnailFallbackImageUrl");
(m_virtualListResultSet as IDisposable)?.Dispose();
m_virtualListResultSet = new(this, deferredSetResultArgs.QueryList, autoRefresh, antialiasEdges)
{
VisualReleaseBehavior = deferredSetResultArgs.RetainedList
? ReleaseBehavior.KeepReference
: ReleaseBehavior.ReleaseReference
};
isEmpty = deferredSetResultArgs.QueryList.IsEmpty;
}
StrixLibraryDataProviderQueryResult libraryDataProviderQueryResult = new(this, m_virtualListResultSet, ResultTypeCookie);
libraryDataProviderQueryResult.SetIsEmpty(isEmpty);
Result = libraryDataProviderQueryResult;
Status = DataProviderQueryStatus.Complete;
}
private async Task<Schemas.Track> CreateTrack(ITrack stTrack, EQueryType queryType, (int? album, int? albumArtist, int? genre) filterIds)
{
var stAlbum = stTrack.Album;
var stAlbumArtist = stAlbum != null
? await stAlbum.GetArtistItemsAsync(1, 0).FirstOrDefaultAsync()
: null;
// Handle filters
if (queryType == EQueryType.eQueryTypeTracksForAlbumId)
{
var currentAlbumId = stAlbum?.Id.HashToInt32();
if (currentAlbumId != filterIds.album) return null;
}
else if (queryType == EQueryType.eQueryTypeTracksForAlbumArtistId)
{
var currentAlbumArtistId = stAlbumArtist?.Id.HashToInt32();
if (currentAlbumArtistId != filterIds.albumArtist) return null;
}
else if (queryType == EQueryType.eQueryTypeTracksByGenreId)
{
var containsCurrentGenre = await stTrack.GetGenresAsync(int.MaxValue, 0)
.Select(g => g.Name.HashToInt32())
.AnyAsync(g => g == filterIds.genre);
if (!containsCurrentGenre && stAlbum != null)
{
// If the track doesn't have the genre, the album might.
containsCurrentGenre = await stAlbum.GetGenresAsync(int.MaxValue, 0)
.Select(g => g.Name.HashToInt32())
.AnyAsync(g => g == filterIds.genre);
}
if (!containsCurrentGenre) return null;
}
Schemas.Track track = new(m_dataType)
{
AlbumName = stTrack.Album?.Name,
AlbumLibraryId = stTrack.Album?.Id.HashToInt32() ?? 0,
TitleYomi = stTrack.Name,
ReleaseDate = DateTime.Now,
ZuneMediaId = stTrack.Id.HashToGuid(),
TrackNumber = stTrack.TrackNumber ?? 0,
Duration = stTrack.Duration,
ComponentId = "strix",
FileName = System.IO.Path.GetFileName(stTrack.Id),
FolderName = System.IO.Path.GetDirectoryName(stTrack.Id),
FilePath = stTrack.Id,
NowPlaying = false,
InLibrary = true,
DateLastPlayed = stTrack.LastPlayed ?? DateTime.MinValue,
PlayCount = 0,
FileSize = 0,
ComposerName = null,
ConductorName = null,
IsProtected = 0,
DateAdded = stTrack.AddedAt ?? DateTime.Now,
Bitrate = 0,
MediaType = "track",
DiscNumber = stTrack.DiscNumber ?? 0,
DateAlbumAdded = DateTime.Now,
FileCount = 1L,
DrmState = 0,
DrmStateMask = 0L,
QuickMixState = 0,
LibraryId = stTrack.Id.HashToInt32(),
Title = stTrack.Name,
SyncState = 0,
Type = "track",
DeviceFileSize = 0L,
UserRating = 0,
AlbumArtistName = stAlbumArtist?.Name,
AlbumArtistLibraryId = stAlbumArtist?.Id.HashToInt32() ?? 0
};
var stArtists = stTrack.GetArtistItemsAsync(int.MaxValue, 0);
bool setPrimaryArtist = false;
List<string> contributingArtists = new();
await foreach (var stArtist in stArtists)
{
if (!setPrimaryArtist)
{
track.ArtistLibraryId = stArtist.Id.HashToInt32();
track.ArtistName = stArtist.Name;
track.ArtistNameYomi = stArtist.Name;
setPrimaryArtist = true;
}
else if (!string.IsNullOrEmpty(stArtist.Name))
{
contributingArtists.Add(stArtist.Name);
}
}
track.ContributingArtistCount = contributingArtists.Count;
track.ContributingArtistNames = contributingArtists;
// No artists
if (!setPrimaryArtist)
{
track.ArtistLibraryId = 0;
track.ArtistName = null;
track.ArtistNameYomi = null;
}
var stGenre = await stTrack.GetGenresAsync(1, 0).FirstOrDefaultAsync();
track.Genre = stGenre?.Name;
track.Item.Storage["StrixItem"] = stTrack;
return track;
}
}
internal class DeferredSetResultArgs
{
public DeferredSetResultArgs(int requestGeneration, ZuneQueryList queryList, bool retainedList)
{
RequestGeneration = requestGeneration;
QueryList = queryList;
RetainedList = retainedList;
}
public int RequestGeneration { get; }
public ZuneQueryList QueryList { get; }
public bool RetainedList { get; }
}
}