2019-10-12 21:37:16 +00:00
using System ;
2019-12-20 20:51:10 +00:00
using System.ComponentModel ;
2019-10-12 21:37:16 +00:00
using System.Linq ;
2019-12-20 20:51:10 +00:00
using System.Reactive.Linq ;
2019-12-14 05:46:20 +00:00
using System.Threading ;
2019-12-06 05:29:17 +00:00
using System.Threading.Tasks ;
2019-12-20 20:51:10 +00:00
using System.Windows.Input ;
using ReactiveUI ;
2019-10-12 21:37:16 +00:00
using Wabbajack.Common ;
2019-12-04 04:12:08 +00:00
using Wabbajack.Common.StatusFeed.Errors ;
2019-10-16 03:10:34 +00:00
using Wabbajack.Lib.NexusApi ;
using Wabbajack.Lib.Validation ;
2019-10-12 21:37:16 +00:00
2019-10-16 03:10:34 +00:00
namespace Wabbajack.Lib.Downloaders
2019-10-12 21:37:16 +00:00
{
2020-01-05 01:01:43 +00:00
public class NexusDownloader : IDownloader , INeedsLogin
2019-10-12 21:37:16 +00:00
{
2019-12-14 05:46:20 +00:00
private bool _prepared ;
private SemaphoreSlim _lock = new SemaphoreSlim ( 1 ) ;
private UserStatus _status ;
private NexusApiClient _client ;
2019-12-20 20:51:10 +00:00
public IObservable < bool > IsLoggedIn = > Utils . HaveEncryptedJsonObservable ( "nexusapikey" ) ;
public string SiteName = > "Nexus Mods" ;
2020-01-05 00:05:31 +00:00
public string MetaInfo = > "" ;
2019-12-20 20:51:10 +00:00
public Uri SiteURL = > new Uri ( "https://www.nexusmods.com" ) ;
public Uri IconUri = > new Uri ( "https://www.nexusmods.com/favicon.ico" ) ;
2020-01-05 00:05:31 +00:00
2019-12-20 20:51:10 +00:00
public ICommand TriggerLogin { get ; }
public ICommand ClearLogin { get ; }
2020-01-05 00:05:31 +00:00
public NexusDownloader ( )
{
2020-01-05 13:14:53 +00:00
if ( CLIArguments . ApiKey ! = null )
{
CLIArguments . ApiKey . ToEcryptedJson ( "nexusapikey" ) ;
}
2020-01-05 00:05:31 +00:00
TriggerLogin = ReactiveCommand . CreateFromTask (
execute : ( ) = > Utils . CatchAndLog ( NexusApiClient . RequestAndCacheAPIKey ) ,
canExecute : IsLoggedIn . Select ( b = > ! b ) . ObserveOn ( RxApp . MainThreadScheduler ) ) ;
ClearLogin = ReactiveCommand . Create (
execute : ( ) = > Utils . CatchAndLog ( ( ) = > Utils . DeleteEncryptedJson ( "nexusapikey" ) ) ,
canExecute : IsLoggedIn . ObserveOn ( RxApp . MainThreadScheduler ) ) ;
}
2019-12-07 03:50:50 +00:00
public async Task < AbstractDownloadState > GetDownloaderState ( dynamic archiveINI )
2019-10-12 21:37:16 +00:00
{
2019-11-21 15:51:57 +00:00
var general = archiveINI ? . General ;
2019-10-12 21:37:16 +00:00
if ( general . modID ! = null & & general . fileID ! = null & & general . gameName ! = null )
{
2019-11-08 01:36:01 +00:00
var name = ( string ) general . gameName ;
2019-11-09 14:57:35 +00:00
var gameMeta = GameRegistry . GetByMO2ArchiveName ( name ) ;
var game = gameMeta ! = null ? GameRegistry . GetByMO2ArchiveName ( name ) . Game : GameRegistry . GetByNexusName ( name ) . Game ;
2019-12-07 03:50:50 +00:00
var client = await NexusApiClient . Get ( ) ;
var info = await client . GetModInfo ( game , general . modID ) ;
2019-10-12 21:37:16 +00:00
return new State
{
GameName = general . gameName ,
FileID = general . fileID ,
ModID = general . modID ,
Version = general . version ? ? "0.0.0.0" ,
Author = info . author ,
UploadedBy = info . uploaded_by ,
UploaderProfile = info . uploaded_users_profile_url ,
ModName = info . name ,
SlideShowPic = info . picture_url ,
2019-11-08 01:36:01 +00:00
NexusURL = NexusApiUtils . GetModURL ( game , info . mod_id ) ,
2019-10-12 21:37:16 +00:00
Summary = info . summary ,
Adult = info . contains_adult_content
} ;
}
return null ;
}
2019-12-07 02:45:13 +00:00
public async Task Prepare ( )
2019-10-12 22:15:20 +00:00
{
2019-12-14 05:46:20 +00:00
if ( ! _prepared )
2019-10-12 22:15:20 +00:00
{
2019-12-14 05:46:20 +00:00
await _lock . WaitAsync ( ) ;
try
{
// Could have become prepared while we waited for the lock
if ( ! _prepared )
{
_client = await NexusApiClient . Get ( ) ;
_status = await _client . GetUserStatus ( ) ;
if ( ! _client . IsAuthenticated )
{
Utils . ErrorThrow ( new UnconvertedError (
$"Authenticating for the Nexus failed. A nexus account is required to automatically download mods." ) ) ;
return ;
}
}
}
finally
{
_lock . Release ( ) ;
}
2019-10-12 22:15:20 +00:00
}
2019-12-14 05:46:20 +00:00
_prepared = true ;
if ( _status . is_premium ) return ;
Utils . ErrorThrow ( new UnconvertedError ( $"Automated installs with Wabbajack requires a premium nexus account. {await _client.Username()} is not a premium account." ) ) ;
2019-10-12 22:15:20 +00:00
}
2019-10-12 21:37:16 +00:00
public class State : AbstractDownloadState
{
2020-01-01 16:19:06 +00:00
public string Author { get ; set ; }
public string FileID { get ; set ; }
public string GameName { get ; set ; }
public string ModID { get ; set ; }
public string UploadedBy { get ; set ; }
public string UploaderProfile { get ; set ; }
public string Version { get ; set ; }
public string SlideShowPic { get ; set ; }
public string ModName { get ; set ; }
public string NexusURL { get ; set ; }
public string Summary { get ; set ; }
public bool Adult { get ; set ; }
public override object [ ] PrimaryKey { get = > new object [ ] { GameName , ModID , FileID } ; }
2019-10-12 21:37:16 +00:00
public override bool IsWhitelisted ( ServerWhitelist whitelist )
{
// Nexus files are always whitelisted
return true ;
}
2019-12-06 05:29:17 +00:00
public override async Task Download ( Archive a , string destination )
2019-10-12 21:37:16 +00:00
{
string url ;
try
{
2019-12-07 03:50:50 +00:00
var client = await NexusApiClient . Get ( ) ;
2020-01-02 00:11:13 +00:00
url = await client . GetNexusDownloadLink ( this ) ;
2019-10-12 21:37:16 +00:00
}
catch ( Exception ex )
{
Utils . Log ( $"{a.Name} - Error Getting Nexus Download URL - {ex.Message}" ) ;
return ;
}
Utils . Log ( $"Downloading Nexus Archive - {a.Name} - {GameName} - {ModID} - {FileID}" ) ;
2019-12-06 05:29:17 +00:00
await new HTTPDownloader . State
2019-10-12 21:37:16 +00:00
{
Url = url
} . Download ( a , destination ) ;
}
2019-12-06 05:29:17 +00:00
public override async Task < bool > Verify ( )
2019-10-12 21:37:16 +00:00
{
try
{
2019-12-01 14:44:01 +00:00
var gameMeta = GameRegistry . GetByMO2ArchiveName ( GameName ) ? ? GameRegistry . GetByNexusName ( GameName ) ;
if ( gameMeta = = null )
return false ;
var game = gameMeta . Game ;
if ( ! int . TryParse ( ModID , out var modID ) )
return false ;
2019-12-07 03:50:50 +00:00
var client = await NexusApiClient . Get ( ) ;
var modFiles = await client . GetModFiles ( game , modID ) ;
2019-12-01 14:44:01 +00:00
if ( ! ulong . TryParse ( FileID , out var fileID ) )
return false ;
var found = modFiles . files
. FirstOrDefault ( file = > file . file_id = = fileID & & file . category_name ! = null ) ;
2019-11-21 05:57:48 +00:00
return found ! = null ;
2019-10-12 21:37:16 +00:00
}
catch ( Exception ex )
{
2019-11-22 05:19:42 +00:00
Utils . Log ( $"{ModName} - {GameName} - {ModID} - {FileID} - Error Getting Nexus Download URL - {ex}" ) ;
2019-10-12 21:37:16 +00:00
return false ;
}
}
2019-10-12 22:15:20 +00:00
public override IDownloader GetDownloader ( )
{
return DownloadDispatcher . GetInstance < NexusDownloader > ( ) ;
}
2019-10-12 22:54:25 +00:00
public override string GetReportEntry ( Archive a )
{
var profile = UploaderProfile . Replace ( "/games/" ,
"/" + NexusApiUtils . ConvertGameName ( GameName ) . ToLower ( ) + "/" ) ;
return string . Join ( "\n" ,
$"* [{a.Name}](http://nexusmods.com/{NexusApiUtils.ConvertGameName(GameName)}/mods/{ModID})" ,
$" * Author : [{UploadedBy}]({profile})" ,
$" * Version : {Version}" ) ;
}
2019-10-12 21:37:16 +00:00
}
}
}