Skip to content

Commit

Permalink
Non downloaded library items (#2101)
Browse files Browse the repository at this point in the history
* Make Nexus Library Items inherit from LibraryItem

* Fix bugs in the initial implementation

* Bit 'o cleanup

* Fix compile error

* Rename NexusModsLibraryFile to NexusMOdsLibraryItem
  • Loading branch information
halgari authored Oct 1, 2024
1 parent 7100bc4 commit 5d4479f
Show file tree
Hide file tree
Showing 8 changed files with 45 additions and 41 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@ public partial class NexusModsFileMetadata : IModelDefinition
/// The version of the file.
/// </summary>
public static readonly StringAttribute Version = new(Namespace, nameof(Version));

/// <summary>
/// The size in bytes of the file.
/// The size of the file in bytes, this is optional in the NexusMods API for whatever reason.
/// </summary>
public static readonly SizeAttribute Size = new(Namespace, nameof(Size)) { IsOptional = true };

Expand All @@ -42,5 +42,5 @@ public partial class NexusModsFileMetadata : IModelDefinition
/// <summary>
/// Library Files that link to this file.
/// </summary>
public static readonly BackReferenceAttribute<NexusModsLibraryFile> LibraryFiles = new(NexusModsLibraryFile.FileMetadata);
public static readonly BackReferenceAttribute<NexusModsLibraryItem> LibraryFiles = new(NexusModsLibraryItem.FileMetadata);
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
namespace NexusMods.Abstractions.NexusModsLibrary;

/// <summary>
/// Represented a <see cref="DownloadedFile"/> originating from Nexus Mods.
/// Represented a <see cref="LibraryItem"/> originating from Nexus Mods.
/// </summary>
[PublicAPI]
[Include<DownloadedFile>]
public partial class NexusModsLibraryFile : IModelDefinition
[Include<LibraryItem>]
public partial class NexusModsLibraryItem : IModelDefinition
{
private const string Namespace = "NexusMods.Library.NexusModsLibraryFile";
private const string Namespace = "NexusMods.Library.NexusModsLibraryItem";

/// <summary>
/// Remote metadata of the file on Nexus Mods.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ public static IServiceCollection AddNexusModsLibraryModels(this IServiceCollecti
return serviceCollection
.AddNexusModsFileMetadataModel()
.AddNexusModsModPageMetadataModel()
.AddNexusModsLibraryFileModel()
.AddNexusModsLibraryItemModel()
.AddCollectionMetadataModel()
.AddCollectionRevisionMetadataModel()
.AddCollectionRevisionModFileModel()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using NexusMods.Abstractions.Library.Models;
using NexusMods.Abstractions.NexusModsLibrary;
using NexusMods.MnemonicDB.Abstractions;
using NexusMods.MnemonicDB.Abstractions.TxFunctions;
using NexusMods.Networking.HttpDownloader;
using NexusMods.Paths;

Expand Down Expand Up @@ -34,19 +35,18 @@ public async ValueTask<AbsolutePath> StartAsync(IJobContext<NexusModsDownloadJob
}

/// <inheritdoc/>
public ValueTask AddMetadata(ITransaction transaction, LibraryFile.New libraryFile)
public ValueTask AddMetadata(ITransaction tx, LibraryFile.New libraryFile)
{
libraryFile.GetLibraryItem(transaction).Name = FileMetadata.Name;
libraryFile.GetLibraryItem(tx).Name = FileMetadata.Name;

_ = new NexusModsLibraryFile.New(transaction, libraryFile.Id)
// Not using .New here because we can't use the LibraryItem Id and don't have the LibraryItem in this method
tx.Add(libraryFile.Id, NexusModsLibraryItem.FileMetadataId, FileMetadata.Id);
tx.Add(libraryFile.Id, NexusModsLibraryItem.ModPageMetadataId, FileMetadata.ModPage.Id);

_ = new DownloadedFile.New(tx, libraryFile.Id)
{
FileMetadataId = FileMetadata,
ModPageMetadataId = FileMetadata.ModPage,
DownloadedFile = new DownloadedFile.New(transaction, libraryFile.Id)
{
DownloadPageUri = HttpDownloadJob.Job.DownloadPageUri,
LibraryFile = libraryFile,
},
DownloadPageUri = HttpDownloadJob.Job.DownloadPageUri,
LibraryFile = libraryFile,
};

return ValueTask.CompletedTask;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,18 @@ private async Task<byte[]> DownloadImage(string? uri, CancellationToken token)

if (!files.TryGetFirst(x => x.FileId == fileId, out var fileInfo))
throw new NotImplementedException();


var size = Optional<Size>.None;
if (fileInfo.SizeInBytes.HasValue)
size = Size.FromLong((long)fileInfo.SizeInBytes!);

var newFile = new NexusModsFileMetadata.New(tx)
{
Name = fileInfo.Name,
Version = fileInfo.Version,
FileId = fileId,
ModPageId = modPage,
Size = size.HasValue ? size.Value : null,
};

if (fileInfo.SizeInBytes.HasValue)
Expand Down
19 changes: 8 additions & 11 deletions src/NexusMods.App.UI/Pages/Library/LibraryItemRemovalInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,19 +20,16 @@ public static LibraryItemRemovalInfo Determine(LibraryItem.ReadOnly toRemove, Lo
var info = new LibraryItemRemovalInfo();

// Check if it's a file which was downloaded.
var isDownloadedFile = toRemove.TryGetAsDownloadedFile(out var downloadedFile);;
switch (isDownloadedFile)
if (toRemove.TryGetAsNexusModsLibraryItem(out _))
{
case true:
info.IsNexus = downloadedFile.IsNexusModsLibraryFile();
info.IsNonPermanent = !info.IsNexus;
break;
// Check if it's a LocalFile (manually added)
case false when toRemove.TryGetAsLocalFile(out _):
info.IsManuallyAdded = true;
break;
info.IsNexus = true;
info.IsNonPermanent = !info.IsNexus;
}

else if (toRemove.TryGetAsLocalFile(out _))
{
info.IsManuallyAdded = true;
}

// Check if it's added to any loadout
info.Loadouts = loadouts.Where(loadout => loadout.GetLoadoutItemsByLibraryItem(toRemove).Any()).ToArray();
return info;
Expand Down
19 changes: 9 additions & 10 deletions src/NexusMods.App.UI/Pages/NexusModsDataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ public NexusModsDataProvider(IServiceProvider serviceProvider)
public IObservable<IChangeSet<LibraryItemModel, EntityId>> ObserveFlatLibraryItems(LibraryFilter libraryFilter)
{
// NOTE(erri120): For the flat library view, we display each NexusModsLibraryFile
return NexusModsLibraryFile
return NexusModsLibraryItem
.ObserveAll(_connection)
// only show library files for the currently selected game
.FilterOnObservable((file, _) => libraryFilter.GameObservable.Select(game => file.ModPageMetadata.GameDomain.Equals(game.Domain)))
Expand All @@ -47,13 +47,13 @@ public IObservable<IChangeSet<LibraryItemModel, EntityId>> ObserveNestedLibraryI
.FilterOnObservable((modPage, _) => libraryFilter.GameObservable.Select(game => modPage.GameDomain.Equals(game.Domain)))
// only show mod pages that have library files
.FilterOnObservable((_, e) => _connection
.ObserveDatoms(NexusModsLibraryFile.ModPageMetadataId, e)
.ObserveDatoms(NexusModsLibraryItem.ModPageMetadataId, e)
.IsNotEmpty()
)
.Transform((modPage, _) => ToLibraryItemModel(modPage, libraryFilter));
}

private LibraryItemModel ToLibraryItemModel(NexusModsLibraryFile.ReadOnly nexusModsLibraryFile, LibraryFilter libraryFilter)
private LibraryItemModel ToLibraryItemModel(NexusModsLibraryItem.ReadOnly nexusModsLibraryFile, LibraryFilter libraryFilter)
{
var linkedLoadoutItemsObservable = QueryHelper.GetLinkedLoadoutItems(_connection, nexusModsLibraryFile.Id, libraryFilter);

Expand All @@ -64,9 +64,8 @@ private LibraryItemModel ToLibraryItemModel(NexusModsLibraryFile.ReadOnly nexusM
};

model.CreatedAtDate.Value = nexusModsLibraryFile.GetCreatedAt();
model.ItemSize.Value = nexusModsLibraryFile.AsDownloadedFile().AsLibraryFile().Size.ToString();
model.Version.Value = nexusModsLibraryFile.FileMetadata.Version;

model.ItemSize.Value = nexusModsLibraryFile.FileMetadata.Size.ToString();
return model;
}

Expand All @@ -75,15 +74,15 @@ private LibraryItemModel ToLibraryItemModel(NexusModsModPageMetadata.ReadOnly mo
// TODO: dispose
var cache = new SourceCache<Datom, EntityId>(static datom => datom.E);
var disposable = _connection
.ObserveDatoms(NexusModsLibraryFile.ModPageMetadataId, modPageMetadata.Id)
.ObserveDatoms(NexusModsLibraryItem.ModPageMetadataId, modPageMetadata.Id)
.AsEntityIds()
.Adapt(new SourceCacheAdapter<Datom, EntityId>(cache))
.SubscribeWithErrorLogging();

var hasChildrenObservable = cache.Connect().IsNotEmpty();
var childrenObservable = cache.Connect().Transform((_, e) =>
{
var libraryFile = NexusModsLibraryFile.Load(_connection.Db, e);
var libraryFile = NexusModsLibraryItem.Load(_connection.Db, e);
return ToLibraryItemModel(libraryFile, libraryFilter);
});

Expand All @@ -94,7 +93,7 @@ private LibraryItemModel ToLibraryItemModel(NexusModsModPageMetadata.ReadOnly mo
.Transform((_, e) => LibraryLinkedLoadoutItem.Load(_connection.Db, e));

var libraryFilesObservable = cache.Connect()
.Transform((_, e) => NexusModsLibraryFile.Load(_connection.Db, e).AsDownloadedFile().AsLibraryFile().AsLibraryItem());
.Transform((_, e) => NexusModsLibraryItem.Load(_connection.Db, e).AsLibraryItem());

var numInstalledObservable = cache.Connect().TransformOnObservable((_, e) => _connection
.ObserveDatoms(LibraryLinkedLoadoutItem.LibraryItemId, e)
Expand Down Expand Up @@ -122,7 +121,7 @@ public IObservable<IChangeSet<LoadoutItemModel, EntityId>> ObserveNestedLoadoutI
return NexusModsModPageMetadata
.ObserveAll(_connection)
.FilterOnObservable((_, modPageEntityId) => _connection
.ObserveDatoms(NexusModsLibraryFile.ModPageMetadataId, modPageEntityId)
.ObserveDatoms(NexusModsLibraryItem.ModPageMetadataId, modPageEntityId)
.FilterOnObservable((d, _) => _connection
.ObserveDatoms(LibraryLinkedLoadoutItem.LibraryItemId, d.E)
.AsEntityIds()
Expand All @@ -135,7 +134,7 @@ public IObservable<IChangeSet<LoadoutItemModel, EntityId>> ObserveNestedLoadoutI
// TODO: dispose
var cache = new SourceCache<Datom, EntityId>(static datom => datom.E);
var disposable = _connection
.ObserveDatoms(NexusModsLibraryFile.ModPageMetadataId, modPage.Id).AsEntityIds()
.ObserveDatoms(NexusModsLibraryItem.ModPageMetadataId, modPage.Id).AsEntityIds()
.FilterOnObservable((_, e) => _connection.ObserveDatoms(LibraryLinkedLoadoutItem.LibraryItemId, e).IsNotEmpty())
// NOTE(erri120): DynamicData 9.0.4 is broken for value types because it uses ReferenceEquals. Temporary workaround is a custom equality comparer.
.MergeManyChangeSets((_, e) => _connection.ObserveDatoms(LibraryLinkedLoadoutItem.LibraryItemId, e).AsEntityIds(), equalityComparer: DatomEntityIdEqualityComparer.Instance)
Expand Down
5 changes: 4 additions & 1 deletion src/NexusMods.Collections/InstallCollectionJob.cs
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,10 @@ private async Task<ModInstructions> EnsureNexusModDownloaded(Mod mod)
.FirstOrOptional(f => f.LibraryFiles.Any());

if (file.HasValue)
return (mod, file.Value.LibraryFiles.First().AsDownloadedFile().AsLibraryFile());
{
if (!file.Value.LibraryFiles.First().AsLibraryItem().TryGetAsLibraryFile(out var firstLibraryFile))
return (mod, firstLibraryFile);
}

await using var tempPath = TemporaryFileManager.CreateFile();

Expand Down

0 comments on commit 5d4479f

Please sign in to comment.