public Tasker.Conclusion DecompressGames(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.DecompressingGames); tasker.SetStatusImage(Resources.sign_cogs); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.DecompressingGames); int i = 0; foreach (NesApplication game in Games) { if (!game.IsOriginalGame) { tasker.SetStatus(string.Format(Resources.Decompressing, game.Name)); game.Decompress(); tasker.SetProgress(++i, Games.Count); } else { tasker.SetStatus(string.Format(Resources.Skipping, game.Name)); Thread.Sleep(1); } } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion ResetROMHeaders(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.ResettingHeaders); tasker.SetStatusImage(Resources.sign_database); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.ResettingHeaders); int i = 0; foreach (NesApplication game in Games) { if (game is SnesGame && !(game as SnesGame).IsOriginalGame) { tasker.SetStatus(string.Format(Resources.ResettingHeader, game.Name)); bool wasCompressed = game.DecompressPossible().Length > 0; if (wasCompressed) { game.Decompress(); } SfromToolWrapper.ResetSFROM(game.GameFilePath); if (wasCompressed) { game.Compress(); } } else { tasker.SetStatus(string.Format(Resources.Skipping, game.Name)); Thread.Sleep(1); } tasker.SetProgress(++i, Games.Count); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion DeleteGames(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.RemovingGames); tasker.SetStatusImage(Resources.sign_trashcan); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.RemovingGames); int i = 0; foreach (NesApplication game in Games) { if (!game.IsOriginalGame) { tasker.SetStatus(string.Format(Resources.Removing, game.Name)); game.IsDeleting = true; Directory.Delete(game.BasePath, true); tasker.SetProgress(++i, Games.Count); } else { tasker.SetStatus(string.Format(Resources.Skipping, game.Name)); Thread.Sleep(1); } } return(Tasker.Conclusion.Success); }
public static Conclusion GetHmods(Tasker tasker, Object modObject) { if (!(modObject is ModObject)) { return(Conclusion.Error); } ModObject unboxedObject = (ModObject)modObject; unboxedObject.LoadedHmods = new List <Hmod>(); if (unboxedObject.HmodsToLoad == null) { return(Conclusion.Error); } tasker.SetStatus(Properties.Resources.LoadingHmods); int progress = 0; foreach (string mod in unboxedObject.HmodsToLoad) { unboxedObject.LoadedHmods.Add(new Hmod(mod, unboxedObject.InstalledHmods)); progress++; tasker.SetProgress(progress, unboxedObject.HmodsToLoad.Count); } tasker.SetProgress(1, 1); return(Conclusion.Success); }
public Tasker.Conclusion ScanCovers(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.ScanningCovers); tasker.SetStatusImage(Resources.sign_file_picture); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.ScanningCovers); var unknownApps = new List <NesApplication>(); int i = 0; foreach (NesApplication game in Games) { tasker.SetStatus(string.Format(Resources.ScanningCover, game.Name)); try { uint crc32 = game.Metadata.OriginalCrc32; string gameFile = game.GameFilePath; if (crc32 == 0 && !game.IsOriginalGame && gameFile != null && File.Exists(gameFile)) { using (var stream = game.GameFileStream) { if (stream != null) { stream.Position = 0; crc32 = Shared.CRC32(stream); game.Metadata.OriginalCrc32 = crc32; game.SaveMetadata(); } } } else { gameFile = game.BasePath; } game.FindCover(game.Metadata.OriginalFilename ?? Path.GetFileName(gameFile), crc32, game.Name); if (!game.CoverArtMatchSuccess && game.CoverArtMatches.Any()) { unknownApps.Add(game); } } catch (Exception ex) { Debug.WriteLine("Error trying to finding cover art for game " + game.Name); Debug.WriteLine(ex.Message + ex.StackTrace); } tasker.SetProgress(++i, Games.Count); } if (unknownApps.Count > 0) { tasker.HostForm.Invoke(new Action(() => { using (SelectCoverDialog selectCoverDialog = new SelectCoverDialog()) { selectCoverDialog.Games.AddRange(unknownApps); selectCoverDialog.ShowDialog(tasker.HostForm); } })); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion DownloadCovers(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.DownloadAllCoversTitle); tasker.SetStatusImage(Resources.sign_globe); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.DownloadAllCoversTitle); int i = 0; foreach (NesApplication game in Games) { tasker.SetStatus(Resources.GooglingFor.Trim() + " " + game.Name + "..."); string[] urls = null; for (int tries = 0; tries < 5; tries++) { if (urls == null) { try { urls = ImageGooglerForm.GetImageUrls(game); break; } catch (Exception ex) { tasker.SetStatus(Resources.Error + ": " + ex.Message); Thread.Sleep(1500); continue; } } } if (urls != null && urls.Length == 0) { tasker.SetStatus(Resources.NotFound + " " + game.Name); } for (int tries = 0; urls != null && tries < 5 && tries < urls.Length; tries++) { try { var cover = ImageGooglerForm.DownloadImage(urls[tries]); game.Image = cover; break; } catch (Exception ex) { tasker.SetStatus(Resources.Error + ": " + ex.Message); Thread.Sleep(1500); continue; } } tasker.SetProgress(++i, Games.Count); Thread.Sleep(500); // not so fast, Google don't like it } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion DeleteCovers(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.RemovingCovers); tasker.SetStatusImage(Resources.sign_trashcan); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.RemovingCovers); int i = 0; foreach (NesApplication game in Games) { game.Image = null; tasker.SetProgress(++i, Games.Count); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion SyncOriginalGames(Tasker tasker, Object syncObject = null) { if (originalGames.Any()) { using (MemoryStream commandBuilder = new MemoryStream()) { tasker.SetStatus(Resources.UploadingOriginalGames); string data = $"#!/bin/sh\ncd \"/tmp\"\n"; commandBuilder.Write(Encoding.UTF8.GetBytes(data), 0, data.Length); foreach (var originalCode in originalGames.Keys) { string originalSyncCode = ""; switch (ConfigIni.Instance.ConsoleType) { case hakchi.ConsoleType.NES: case hakchi.ConsoleType.Famicom: originalSyncCode = $"src=\"{hakchi.SquashFsPath}{hakchi.GamesSquashFsPath}/{originalCode}\" && " + $"dst=\"{uploadPath}/{originalGames[originalCode]}/{originalCode}\" && " + $"mkdir -p \"$dst\" && " + $"([ -L \"$dst/autoplay\" ] || ln -s \"$src/autoplay\" \"$dst/\") && " + $"([ -L \"$dst/pixelart\" ] || ln -s \"$src/pixelart\" \"$dst/\")" + "\n"; break; case hakchi.ConsoleType.SNES_EUR: case hakchi.ConsoleType.SNES_USA: case hakchi.ConsoleType.SuperFamicom: originalSyncCode = $"src=\"{hakchi.SquashFsPath}{hakchi.GamesSquashFsPath}/{originalCode}\" && " + $"dst=\"{uploadPath}/{originalGames[originalCode]}/{originalCode}\" && " + $"mkdir -p \"$dst\" && " + $"([ -L \"$dst/autoplay\" ] || ln -s \"$src/autoplay\" \"$dst/\")" + "\n"; break; } commandBuilder.Write(Encoding.UTF8.GetBytes(originalSyncCode), 0, originalSyncCode.Length); } tasker.SetProgress(1, 2); hakchi.RunTemporaryScript(commandBuilder, "originalgamessync.sh"); } tasker.SetProgress(2, 2); } return(Tasker.Conclusion.Success); }
public static Tasker SetProgress(this Tasker tasker, long value, long maximum, Tasker.State state, string status) { tasker.SetProgress(value, maximum); tasker.SetState(state); tasker.SetStatus(status); return(tasker); }
public Tasker.Conclusion SyncLocalGames(Tasker tasker, Object syncObject = null) { // now transfer whatever games are remaining Debug.WriteLine("Exporting games: " + Shared.SizeSuffix(stats.TotalSize)); long max = transferGameSet.Sum(afi => afi.FileSize); long value = 0; DateTime startTime = DateTime.Now, lastTime = DateTime.Now; tasker.SetProgress(0, max, Tasker.State.Running, Resources.CopyingGames); foreach (var afi in transferGameSet) { string path = new Uri(exportDirectory + "/" + afi.FilePath).LocalPath; string dir = Path.GetDirectoryName(path); if (!Directory.Exists(dir)) { Directory.CreateDirectory(dir); } if (!string.IsNullOrEmpty(afi.LocalFilePath)) { File.Copy(afi.LocalFilePath, path, true); } else { if (afi.FileStream == null || !afi.FileStream.CanRead) { Debug.WriteLine($"\"{afi.FilePath}\": no source data or stream or unreadable"); } else { afi.FileStream.Position = 0; using (var f = File.Open(path, FileMode.Create)) afi.FileStream.CopyTo(f); File.SetLastWriteTimeUtc(path, afi.ModifiedTime); } } value += afi.FileSize; if (DateTime.Now.Subtract(lastTime).TotalMilliseconds > UpdateFreq) { transferForm.SetProgress(value, max, afi.FilePath); lastTime = DateTime.Now; } } Debug.WriteLine("Uploaded " + (int)(max / 1024) + "kb in " + DateTime.Now.Subtract(startTime).TotalSeconds + " seconds"); // show resulting games directory tasker.SetStatus(Resources.PleaseWait); var process = new Process() { StartInfo = new ProcessStartInfo() { FileName = exportDirectory } }; process.Start(); return(Tasker.Conclusion.Success); }
internal Tasker.Conclusion ArchiveGames(Tasker tasker, object syncObject) { long counter = 0; long gameCount = Games.Count; tasker.SetTitle(gameCount > 1 ? Resources.ArchivingGames : Resources.ArchivingGame); string directory = null; if (gameCount > 1) { using (var fbd = new FolderBrowserDialog() { SelectedPath = Program.BaseDirectoryExternal }) { if (fbd.ShowDialog() == DialogResult.OK) { directory = fbd.SelectedPath; } else { return(Tasker.Conclusion.Abort); } } } foreach (var game in Games) { tasker.SetStatus(String.Format(Resources.Archiving, game.Name)); var fileName = Shared.ReplaceInvalidFilenameCharacters($"{game.Code} - {game.Name}.clvg"); if (directory == null) { using (var sfd = new SaveFileDialog() { Filter = Resources.GameArchive + "(*.clvg)|*.clvg", FileName = fileName }) { if (sfd.ShowDialog() == DialogResult.OK) { game.Archive(sfd.FileName); } } } else { var archivePath = Path.Combine(directory, fileName); if (File.Exists(archivePath) && tasker.ShowMessage(Resources.ReplaceFileQ, String.Format(Resources.ReplaceFollowingFileQ, archivePath), Resources.sign_question, new MessageForm.Button[] { MessageForm.Button.Yes, MessageForm.Button.No }) == MessageForm.Button.No) { continue; } game.Archive(archivePath); } counter++; tasker.SetProgress(counter, gameCount); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion SetCoverArtForMultipleGames(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.ApplyChanges); tasker.SetStatusImage(Resources.sign_file_picture); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.ApplyChanges); NesApplication.CachedCoverFiles = null; int i = 0, max = GamesChanged.Count; foreach (var pair in GamesChanged) { pair.Key.SetImageFile(pair.Value, ConfigIni.Instance.CompressCover); tasker.SetProgress(++i, max); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion SyncRemoteGamesShell(Tasker tasker, Object syncObject = null) { // transfer games tasker.SetProgress(0, 100, Tasker.State.Running, Resources.UploadingGames); bool uploadSuccessful = false; if (!transferGameSet.Any()) { Trace.WriteLine("No file to upload"); uploadSuccessful = true; } else { Trace.WriteLine("Uploading through tar file"); using (var gamesTar = new TarStream(transferGameSet, ".")) { Trace.WriteLine($"Upload size: " + Shared.SizeSuffix(gamesTar.Length)); if (gamesTar.Length > 0) { DateTime startTime = DateTime.Now, lastTime = DateTime.Now; bool done = false; gamesTar.OnAdvancedReadProgress += delegate(long pos, long len, string filename) { if (done) { return; } if (DateTime.Now.Subtract(lastTime).TotalMilliseconds >= UpdateFreq) { transferForm.SetAdvancedProgress(pos, len, filename); lastTime = DateTime.Now; } }; hakchi.Shell.Execute($"tar -xvC \"{uploadPath}\"", gamesTar, null, null, 0, true); Trace.WriteLine("Uploaded " + (int)(gamesTar.Length / 1024) + "kb in " + DateTime.Now.Subtract(startTime).TotalSeconds + " seconds"); uploadSuccessful = true; done = true; #if VERY_DEBUG File.Delete(Program.BaseDirectoryExternal + "\\DebugSyncOutput.tar"); gamesTar.Position = 0; gamesTar.CopyTo(File.OpenWrite(Program.BaseDirectoryExternal + "\\DebugSyncOutput.tar")); #endif } transferForm.SetAdvancedProgress(gamesTar.Length, gamesTar.Length, ""); } } // don't continue if upload wasn't successful if (!uploadSuccessful) { Trace.WriteLine("Something happened during transfer, cancelling"); return(Tasker.Conclusion.Error); } return(Tasker.Conclusion.Success); }
public Conclusion MembootFel(Tasker tasker, Object syncObject = null) { tasker.SetStatus(Resources.Membooting); if (hakchi.Shell.IsOnline) return Conclusion.Abort; // check and adjust kernel size byte[] kernel = hakchi.GetMembootImage().ToArray(); var size = Shared.CalcKernelSize(kernel); if (size > kernel.Length || size > Fel.transfer_max_size) throw new Exception(Resources.InvalidKernelSize + " " + size); size = (size + Fel.sector_size - 1) / Fel.sector_size; size = size * Fel.sector_size; if (kernel.Length != size) { var newK = new byte[size]; Array.Copy(kernel, newK, kernel.Length); kernel = newK; } // clovershell override "hex-edit" boot.img if (ConfigIni.Instance.ForceClovershell || ConfigIni.Instance.ForceNetwork) { kernel.InPlaceStringEdit(64, 512, 0, (string str) => { str.Replace("hakchi-shell", "").Replace("hakchi-clovershell", ""); if (ConfigIni.Instance.ForceClovershell) str += " hakchi-clovershell"; else if (ConfigIni.Instance.ForceNetwork) str += " hakchi-shell"; return str; }); } // upload kernel through fel int progress = 0; int maxProgress = (int)((double)kernel.Length / (double)67000 + 50); fel.WriteMemory(Fel.transfer_base_m, kernel, delegate (Fel.CurrentAction action, string command) { switch (action) { case Fel.CurrentAction.WritingMemory: tasker.SetStatus(Resources.UploadingKernel); break; } progress++; tasker.SetProgress(progress, maxProgress); } ); var bootCommand = string.Format("boota {0:x}", Fel.transfer_base_m); tasker.SetStatus(Resources.ExecutingCommand + " " + bootCommand); fel.RunUbootCmd(bootCommand, true); return Conclusion.Success; }
public Tasker.Conclusion RepairGames(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.RepairGames); tasker.SetStatusImage(Resources.sign_cogs); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.RepairGames); NesApplication.ParentForm = tasker.HostForm; int i = 0, max = Games.Count; foreach (var game in Games) { tasker.SetStatus(string.Format(Resources.RepairingGame, game.Name)); bool success = game.Repair(); Debug.WriteLine($"Repairing game \"{game.Name}\" was " + (success ? "successful" : "not successful")); tasker.SetProgress(++i, max); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion LinkGames(Tasker tasker, Object syncObject = null) { using (MemoryStream commandBuilder = new MemoryStream()) { tasker.SetStatus(Resources.LinkingGames); string data = $"#!/bin/sh\ncd \"/tmp\"\n"; commandBuilder.Write(Encoding.UTF8.GetBytes(data), 0, data.Length); foreach (var menuCollection in stats.allMenus) { AddSymLinks(menuCollection, commandBuilder); } tasker.SetProgress(1, 2); hakchi.RunTemporaryScript(commandBuilder, "linkgamessync.sh"); } tasker.SetProgress(2, 2); return(Tasker.Conclusion.Success); }
public Tasker.Conclusion SyncRemoteGamesFTP(Tasker tasker, Object syncObject = null) { // transfer games tasker.SetProgress(0, 100, Tasker.State.Running, Resources.UploadingGames); bool uploadSuccessful = false; if (!transferGameSet.Any()) { Trace.WriteLine("No file to upload"); uploadSuccessful = true; } else { Trace.WriteLine("Uploading through FTP"); using (var ftp = new FtpWrapper(transferGameSet)) { Trace.WriteLine($"Upload size: " + Shared.SizeSuffix(ftp.Length)); if (ftp.Length > 0) { DateTime startTime = DateTime.Now, lastTime = DateTime.Now; ftp.OnReadProgress += delegate(long pos, long len, string filename) { if (DateTime.Now.Subtract(lastTime).TotalMilliseconds >= UpdateFreq) { transferForm.SetAdvancedProgress(pos, len, filename); lastTime = DateTime.Now; } }; if (ftp.Connect((hakchi.Shell as INetworkShell).IPAddress, 21, hakchi.USERNAME, hakchi.PASSWORD)) { ftp.Upload(uploadPath); uploadSuccessful = true; Trace.WriteLine("Uploaded " + (int)(ftp.Length / 1024) + "kb in " + DateTime.Now.Subtract(startTime).TotalSeconds + " seconds"); } } transferForm.SetAdvancedProgress(ftp.Length, ftp.Length, ""); } } // don't continue if upload wasn't successful if (!uploadSuccessful) { Trace.WriteLine("Something happened during transfer, cancelling"); return(Tasker.Conclusion.Error); } return(Tasker.Conclusion.Success); }
// --- scan files and create internal list public Tasker.Conclusion LoadGamesFromFiles(Tasker tasker, Object syncObject = null) { var sync = (LoadGamesSyncObject)syncObject; // list original game directories var originalGameDirs = new List <string>(); foreach (var defaultGame in NesApplication.CurrentDefaultGames) { string gameDir = Path.Combine(NesApplication.OriginalGamesDirectory, defaultGame); string cachedDir = Path.Combine(NesApplication.OriginalGamesCacheDirectory, defaultGame); if (Directory.Exists(gameDir) && (!ConfigIni.Instance.AlwaysCopyOriginalGames || Directory.Exists(cachedDir))) { originalGameDirs.Add(gameDir); } } // add custom games Directory.CreateDirectory(NesApplication.GamesDirectory); var gameDirs = Shared.ConcatArrays(Directory.GetDirectories(NesApplication.GamesDirectory), originalGameDirs.ToArray()); var items = new List <ListViewItem>(); int i = 0; foreach (var gameDir in gameDirs) { try { var game = NesApplication.FromDirectory(gameDir); items.Add(new ListViewItem(game.Name) { Tag = game }); } catch // remove bad directories if any, no throw { Trace.WriteLine($"Game directory \"{gameDir}\" is invalid, deleting"); Directory.Delete(gameDir, true); } tasker.SetProgress(++i, gameDirs.Length); } sync.items = ConfigIni.Instance.OriginalGamesPosition == MainForm.OriginalGamesPosition.Hidden ? items.Where(item => !(item.Tag as NesApplication).IsOriginalGame).ToArray() : items.ToArray(); return(Tasker.Conclusion.Success); }
public Tasker.Conclusion LoadGames(Tasker tasker, Object syncObject = null) { tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.LoadingGames); tasker.SetStatusImage(Resources.sign_down); tasker.SetTitle(Resources.LoadingGames); tasker.SyncObject = new LoadGamesSyncObject(); tasker.AddTasks( CreateListViewGroups, this.reloadFromFiles ? (Tasker.TaskFunc)LoadGamesFromFiles : (Tasker.TaskFunc)LoadGamesFromList, AssignGroupsToGames, AssignListViewGroups, UpdateListView); return(Tasker.Conclusion.Success); }
public Tasker.Conclusion UpdateLocal(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.UpdatingLocalCache); tasker.SetStatusImage(Resources.sign_sync); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.UpdatingLocalCache); var shell = hakchi.Shell; if (!shell.IsOnline) { return(Tasker.Conclusion.Abort); } string gamesCloverPath = shell.ExecuteSimple("hakchi eval 'echo \"$squashfs$gamepath\"'", 2000, true); string cachePath = Path.Combine(Program.BaseDirectoryExternal, "games_cache"); try { var reply = shell.ExecuteSimple($"[ -d {gamesCloverPath} ] && echo YES || echo NO"); if (reply == "NO") { gamesCloverPath = hakchi.GamesPath; reply = shell.ExecuteSimple($"[ -d {gamesCloverPath} ] && echo YES || echo NO"); if (reply == "NO") { throw new Exception("Unable to update local cache. games directory not accessible"); } } int i = 0; foreach (NesDefaultGame game in Games) { string gamePath = Path.Combine(cachePath, game.Code); if (!Directory.Exists(gamePath)) { try { Directory.CreateDirectory(gamePath); using (var tar = new MemoryStream()) { string cmd = $"cd {gamesCloverPath}/{game.Code} && tar -c *"; shell.Execute(cmd, null, tar, null, 10000, true); tar.Seek(0, SeekOrigin.Begin); using (var szExtractorTar = new SevenZipExtractor(tar)) szExtractorTar.ExtractArchive(gamePath); } } catch (Exception ex) { Debug.WriteLine(ex.Message + ex.StackTrace); if (Directory.Exists(gamePath)) { Debug.WriteLine($"Exception, erasing \"{gamePath}\"."); Directory.Delete(gamePath, true); } } } tasker.SetProgress(++i, Games.Count); } } catch (Exception ex) { Debug.WriteLine(ex.Message + ex.StackTrace); return(Tasker.Conclusion.Error); } return(Tasker.Conclusion.Success); }
public ITaskerView SetProgress(long value, long maximum, string fileName) { // call parent tasker SetProgress to update other views (and this one's progress bar) Tasker.SetProgress(value, maximum); if (Disposing || value < 0 || maximum < 0) { return(this); } try { if (InvokeRequired) { return((ITaskerView)Invoke(new Func <long, long, string, ITaskerView>(SetProgress), new object[] { value, maximum, fileName })); } // update other elements if (value >= maximum) { this.labelFileName.Text = ""; this.labelTimeLeft.Text = Resources.Done; this.labelTransferRate.Text = ""; return(this); } this.labelFileName.Text = System.IO.Path.GetFileName(fileName); DateTime now = DateTime.Now; if (lastTime == default(DateTime)) { startTime = lastTime = now; speedSamples = new Queue <double>(); return(this); } else { TimeSpan elapsed = now.Subtract(lastTime); if (elapsed.TotalMilliseconds >= SpeedSampleFreq) { speedSamples.Enqueue(((value - lastData) / elapsed.TotalSeconds)); if (speedSamples.Count > SpeedSampleNum) { speedSamples.Dequeue(); } lastTime = now; lastData = value; } } if (speedSamples.Any()) { double sampledSpeed = speedSamples.Average(); double timeLeft = (maximum - value) / (value / now.Subtract(startTime).TotalSeconds); this.labelTimeLeft.Text = new TimeSpan(0, 0, (int)timeLeft).ToReadableString() + " (" + Shared.SizeSuffix(value) + " of " + Shared.SizeSuffix(maximum) + " copied)"; this.labelTransferRate.Text = Shared.SizeSuffix((long)sampledSpeed) + "/Sec"; } else { this.labelTimeLeft.Text = "(" + Shared.SizeSuffix(value) + " of " + Shared.SizeSuffix(maximum) + " copied)"; this.labelTransferRate.Text = "Calculating..."; } } catch (InvalidOperationException) { } return(this); }
public Conclusion Memboot(Tasker tasker, Object syncObject = null) { // load appropriate kernel byte[] kernel; if (stockKernel != null && stockKernel.Length > 0) { kernel = stockKernel.ToArray(); } else { stockKernel = null; // double-safety kernel = hakchi.GetMembootImage().ToArray(); } tasker.SetStatus(Resources.Membooting); if (hakchi.Shell.IsOnline) { // override arguments string addedArgs = ConfigIni.Instance.ForceClovershell ? " hakchi-clovershell" : ""; // skip to built-in recovery if running latest version if (stockKernel == null && hakchi.CanInteract && !hakchi.SystemEligibleForRootfsUpdate()) { if (hakchi.Shell.Execute("[ -e /bin/detached ]") == 0) // detached recovery function? { try { hakchi.Shell.ExecuteSimple("/bin/detached recovery" + addedArgs, 100); } catch { } // no-op return(Conclusion.Success); } } try { hakchi.Shell.ExecuteSimple("uistop"); hakchi.Shell.ExecuteSimple("mkdir -p /tmp/kexec/", throwOnNonZero: true); hakchi.UploadFile( Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "kexec.static"), "/tmp/kexec/kexec"); TrackableStream kernelStream = new TrackableStream(kernel); kernelStream.OnProgress += tasker.OnProgress; if (stockKernel == null) { hakchi.UploadFile( Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "detached-fallback"), "/tmp/kexec/detached-fallback"); hakchi.UploadFile(kernelStream, "/tmp/kexec/boot.img", false); try { hakchi.Shell.ExecuteSimple("cd /tmp/kexec/; /bin/sh /tmp/kexec/detached-fallback recovery /tmp/kexec/boot.img" + addedArgs, 100); } catch { } // no-op } else { hakchi.UploadFile( Path.Combine(Program.BaseDirectoryInternal, "tools", "arm", "unpackbootimg.static"), "/tmp/kexec/unpackbootimg"); hakchi.Shell.Execute( command: "cat > /tmp/kexec/boot.img; cd /tmp/kexec/; ./unpackbootimg -i boot.img", stdin: kernelStream, throwOnNonZero: true ); hakchi.Shell.ExecuteSimple("cd /tmp/kexec/ && ./kexec -l -t zImage boot.img-zImage \"--command-line=$(cat boot.img-cmdline)\" --ramdisk=boot.img-ramdisk.gz --atags", 0, true); hakchi.Shell.ExecuteSimple("cd /tmp/; umount -ar", 0); try { hakchi.Shell.ExecuteSimple("/tmp/kexec/kexec -e", 100); } catch { } // no-op } } catch { try { hakchi.Shell.ExecuteSimple("uistart"); } catch { } // no-op throw; } } else { // check and adjust kernel size var size = Shared.CalcKernelSize(kernel); if (size > kernel.Length || size > Fel.transfer_max_size) { throw new Exception(Resources.InvalidKernelSize + " " + size); } size = (size + Fel.sector_size - 1) / Fel.sector_size; size = size * Fel.sector_size; if (kernel.Length != size) { var newK = new byte[size]; Array.Copy(kernel, newK, kernel.Length); kernel = newK; } // clovershell override "hex-edit" boot.img if (stockKernel == null && ConfigIni.Instance.ForceClovershell) { kernel.InPlaceStringEdit(64, 512, 0, (string str) => { if (str.IndexOf("hakchi-shell") != -1) { return(str.Replace("hakchi-shell", "hakchi-clovershell")); } else { return(str + " hakchi-clovershell"); } }); } // upload kernel through fel int progress = 0; int maxProgress = (int)((double)kernel.Length / (double)67000 + 50); fel.WriteMemory(Fel.transfer_base_m, kernel, delegate(Fel.CurrentAction action, string command) { switch (action) { case Fel.CurrentAction.WritingMemory: tasker.SetStatus(Resources.UploadingKernel); break; } progress++; tasker.SetProgress(progress, maxProgress); } ); var bootCommand = string.Format("boota {0:x}", Fel.transfer_base_m); tasker.SetStatus(Resources.ExecutingCommand + " " + bootCommand); fel.RunUbootCmd(bootCommand, true); } return(Conclusion.Success); }
public Tasker.Conclusion ScrapeGames(Tasker tasker, Object syncObject = null) { if (Program.TheGamesDBAPI == null) { return(Tasker.Conclusion.Success); } try { var idList = new Dictionary <UInt32, int>(); foreach (var app in NewGames) { if (app.Metadata.OriginalCrc32 != 0 && data.GamesDB.HashLookup.ContainsKey(app.Metadata.OriginalCrc32) && data.GamesDB.HashLookup[app.Metadata.OriginalCrc32].TgdbId.Count > 0) { if (!idList.ContainsKey(app.Metadata.OriginalCrc32)) { idList.Add(app.Metadata.OriginalCrc32, data.GamesDB.HashLookup[app.Metadata.OriginalCrc32].TgdbId.First()); } } } var api = Program.TheGamesDBAPI; var infoList = new Dictionary <int, IScraperData>(); foreach (var chunk in idList.Values.Distinct().ToList().ChunkBy(20)) { var apiResponse = api.GetInfoByID(chunk.ToArray()); while (true) { apiResponse.Wait(); foreach (var result in apiResponse.Result.Items) { infoList.Add(int.Parse(result.ID), result); } if (apiResponse.Result.HasNextPage) { apiResponse = apiResponse.Result.GetNextPage(); } else { break; } } } var counter = 0; foreach (var app in NewGames) { tasker.SetProgress(++counter, NewGames.Count); tasker.SetStatus(string.Format(Resources.Scraping0, app.Name)); int tgdbId; if (app.Metadata.OriginalCrc32 != 0 && data.GamesDB.HashLookup.ContainsKey(app.Metadata.OriginalCrc32) && data.GamesDB.HashLookup[app.Metadata.OriginalCrc32].TgdbId.Count > 0 && infoList.ContainsKey(tgdbId = data.GamesDB.HashLookup[app.Metadata.OriginalCrc32].TgdbId.First())) { try { var apiResult = infoList[tgdbId]; if (apiResult.Name != null) { var name = GamesDB.HashLookup[app.Metadata.OriginalCrc32].Name; if (name != null) { name = Shared.CleanName(name, true); } app.Desktop.Name = name ?? apiResult.Name; app.Desktop.SortName = Shared.GetSortName(app.Desktop.Name); } if (apiResult.Publishers != null && apiResult.Publishers.Length > 0) { app.Desktop.Publisher = String.Join(", ", apiResult.Publishers).ToUpper(); } else if (apiResult.Developers != null && apiResult.Developers.Length > 0) { if (apiResult.ReleaseDate != null) { app.Desktop.Copyright = $"© {apiResult.ReleaseDate.Year} {String.Join(", ", apiResult.Developers)}"; } else { app.Desktop.Copyright = $"© {String.Join(", ", apiResult.Developers)}"; } } if (apiResult.Description != null) { app.Desktop.Description = apiResult.Description; } if (apiResult.ReleaseDate != null) { app.Desktop.ReleaseDate = apiResult.ReleaseDate.ToString("yyyy-MM-dd"); } if (apiResult.PlayerCount > 0) { app.Desktop.Players = Convert.ToByte(apiResult.PlayerCount); app.Desktop.Simultaneous = apiResult.PlayerCount == 2; } if (apiResult.Genres != null && apiResult.Genres.Length > 0) { foreach (var genre in apiResult.Genres) { var match = Genre.GenreList.Where(g => g.GamesDbId.Contains(genre.ID)).Select(g => g); if (match.Count() > 0) { var firstGenre = match.First(); app.Desktop.Genre = firstGenre.DesktopName; break; } } } using (var wc = new HakchiWebClient()) { try { var front = apiResult.Images.Where(i => i.Type == TeamShinkansen.Scrapers.Enums.ArtType.Front).ToArray(); if (front.Length > 0 && !app.CoverArtMatchSuccess) { tasker.SetStatus(string.Format(Resources.DownloadingFrontArtFor0, apiResult.Name)); var data = wc.DownloadData(front[0].Url); using (var ms = new MemoryStream(data)) using (var bm = new Bitmap(ms)) { app.SetImage(bm); } } } catch (WebException ex) { } try { tasker.SetStatus(string.Format(Resources.DownloadingClearLogoFor0, apiResult.Name)); var imageData = wc.DownloadData($"https://cdn.thegamesdb.net/images/original/clearlogo/{apiResult.ID}.png"); using (var ms = new MemoryStream(imageData)) using (var clearLogo = File.OpenWrite(Path.Combine(app.BasePath, $"{app.Code}_logo.png"))) { ms.Seek(0, SeekOrigin.Begin); ms.CopyTo(clearLogo); ms.Seek(0, SeekOrigin.Begin); tasker.SetStatus(string.Format(Resources.GeneratingSpineFor0, apiResult.Name)); using (var bm = new Bitmap(ms)) using (var cl = new SystemDrawingBitmap(bm)) using (var spineImage = (Program.SpineTemplates.Where(e => e.Value.Name == "Custom (Black Grid)").First().Value as SpineTemplate <Bitmap>).Process(cl).Bitmap) { app.SetMdMini(spineImage, NesMenuElementBase.GameImageType.MdSpine); } } } catch (WebException ex) { } } } catch (Exception innerEx) { } } } } catch (Exception ex) { } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion SyncOriginalGames(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.ResettingOriginalGames); tasker.SetStatusImage(Resources.sign_sync); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.ResettingOriginalGames); string desktopEntriesArchiveFile = Path.Combine(Path.Combine(Program.BaseDirectoryInternal, "data"), "desktop_entries.tar"); string originalGamesPath = Path.Combine(Program.BaseDirectoryExternal, "games_originals"); if (!Directory.Exists(originalGamesPath)) { Directory.CreateDirectory(originalGamesPath); } if (!File.Exists(desktopEntriesArchiveFile)) { throw new FileLoadException("desktop_entries.tar data file was deleted, cannot sync original games."); } try { var defaultGames = ResetAllOriginalGames ? NesApplication.AllDefaultGames.Select(g => g.Key) : NesApplication.CurrentDefaultGames; using (var extractor = ArchiveFactory.Open(desktopEntriesArchiveFile)) using (var reader = extractor.ExtractAllEntries()) { int i = 0; while (reader.MoveToNextEntry()) { if (reader.Entry.IsDirectory) { continue; } var code = Path.GetFileNameWithoutExtension(reader.Entry.Key); if (!defaultGames.Contains(code)) { continue; } var ext = Path.GetExtension(reader.Entry.Key).ToLower(); if (ext != ".desktop") // sanity check { throw new FileLoadException($"invalid file \"{reader.Entry.Key}\" found in desktop_entries.tar data file."); } string path = Path.Combine(originalGamesPath, code); string outputFile = Path.Combine(path, code + ".desktop"); bool exists = File.Exists(outputFile); if (exists && !NonDestructiveSync) { Shared.EnsureEmptyDirectory(path); Thread.Sleep(0); } if (!exists || !NonDestructiveSync) { Directory.CreateDirectory(path); // extract .desktop file from archive using (var o = new FileStream(outputFile, FileMode.Create, FileAccess.Write)) { reader.WriteEntryTo(o); o.Flush(); if (!this.ResetAllOriginalGames && !ConfigIni.Instance.OriginalGames.Contains(code)) { ConfigIni.Instance.OriginalGames.Add(code); } } // create game temporarily to perform cover search Trace.WriteLine(string.Format($"Resetting game \"{NesApplication.AllDefaultGames[code].Name}\".")); var game = NesApplication.FromDirectory(path); game.FindCover(code + ".desktop"); game.Save(); } tasker.SetProgress(++i, defaultGames.Count()); } } } catch (Exception ex) { Trace.WriteLine("Error synchronizing original games " + ex.Message + ex.StackTrace); tasker.ShowError(ex, Resources.ErrorRestoringAllOriginalGames); return(Tasker.Conclusion.Error); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion AddGames(Tasker tasker, Object syncObject = null) { tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.AddingGames); tasker.SetTitle(Resources.AddingGames); tasker.SetStatusImage(Resources.sign_cogs); // static presets NesApplication.ParentForm = tasker.HostForm; NesApplication.NeedPatch = null; NesApplication.Need3rdPartyEmulator = null; NesApplication.CachedCoverFiles = null; NesGame.IgnoreMapper = null; SnesGame.NeedAutoDownloadCover = null; int total = files.Count(); int count = 0; foreach (var sourceFileName in files) { NesApplication app = null; try { tasker.SetStatus(string.Format(Resources.AddingGame, Path.GetFileName(sourceFileName))); var fileName = sourceFileName; var ext = Path.GetExtension(sourceFileName).ToLower(); byte[] rawData = null; string tmp = null; if (ext == ".7z" || ext == ".zip" || ext == ".rar") { using (var szExtractor = new SevenZipExtractor(sourceFileName)) { var filesInArchive = szExtractor.ArchiveFileNames; var gameFilesInArchive = new List <string>(); foreach (var f in szExtractor.ArchiveFileNames) { var e = Path.GetExtension(f).ToLower(); if (e == ".desktop") { gameFilesInArchive.Clear(); gameFilesInArchive.Add(f); break; } else if (CoreCollection.Extensions.Contains(e)) { gameFilesInArchive.Add(f); } } if (gameFilesInArchive.Count == 1) // Only one known file (or app) { fileName = gameFilesInArchive[0]; } else if (gameFilesInArchive.Count > 1) // Many known files, need to select { var r = SelectFile(tasker, gameFilesInArchive.ToArray()); if (r == DialogResult.OK) { fileName = selectedFile; } else if (r == DialogResult.Ignore) { fileName = sourceFileName; } else { continue; } } else if (filesInArchive.Count == 1) // No known files but only one another file { fileName = filesInArchive[0]; } else // Need to select { var r = SelectFile(tasker, filesInArchive.ToArray()); if (r == DialogResult.OK) { fileName = selectedFile; } else if (r == DialogResult.Ignore) { fileName = sourceFileName; } else { continue; } } if (fileName != sourceFileName) { var o = new MemoryStream(); if (Path.GetExtension(fileName).ToLower() == ".desktop" || // App in archive, need the whole directory szExtractor.ArchiveFileNames.Contains(Path.GetFileNameWithoutExtension(fileName) + ".jpg") || // Or it has cover in archive szExtractor.ArchiveFileNames.Contains(Path.GetFileNameWithoutExtension(fileName) + ".png") || szExtractor.ArchiveFileNames.Contains(Path.GetFileNameWithoutExtension(fileName) + ".ips") // Or IPS file ) { tmp = Path.Combine(tempDirectory, fileName); Directory.CreateDirectory(tmp); szExtractor.ExtractArchive(tmp); fileName = Path.Combine(tmp, fileName); } else { szExtractor.ExtractFile(fileName, o); rawData = new byte[o.Length]; o.Seek(0, SeekOrigin.Begin); o.Read(rawData, 0, (int)o.Length); } } } } app = NesApplication.Import(fileName, sourceFileName, rawData); if (app is ISupportsGameGenie && Path.GetExtension(fileName).ToLower() == ".nes") { var lGameGeniePath = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".xml"); if (File.Exists(lGameGeniePath)) { GameGenieDataBase lGameGenieDataBase = new GameGenieDataBase(app); lGameGenieDataBase.ImportCodes(lGameGeniePath, true); lGameGenieDataBase.Save(); } } if (!string.IsNullOrEmpty(tmp) && Directory.Exists(tmp)) { Directory.Delete(tmp, true); } } catch (Exception ex) { if (ex is ThreadAbortException) { return(Tasker.Conclusion.Abort); } if (ex.InnerException != null && !string.IsNullOrEmpty(ex.InnerException.Message)) { Debug.WriteLine(ex.InnerException.Message + ex.InnerException.StackTrace); tasker.ShowError(ex.InnerException, Path.GetFileName(sourceFileName)); } else { Debug.WriteLine(ex.Message + ex.StackTrace, Path.GetFileName(sourceFileName)); tasker.ShowError(ex); } return(Tasker.Conclusion.Error); } if (app != null) { addedApps.Add(app); } tasker.SetProgress(++count, total); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion UpdateListView(Tasker tasker, Object syncObject = null) { if (tasker.HostForm.Disposing) { return(Tasker.Conclusion.Abort); } if (tasker.HostForm.InvokeRequired) { return((Tasker.Conclusion)tasker.HostForm.Invoke(new Func <Tasker, Object, Tasker.Conclusion>(UpdateListView), new object[] { tasker, syncObject })); } if (addedApps != null) { tasker.SetTitle(Resources.UpdatingList); // show select core dialog if applicable var unknownApps = new List <NesApplication>(); foreach (var app in addedApps) { if (app.Metadata.AppInfo.Unknown) { unknownApps.Add(app); } } if (unknownApps.Count > 0) { using (SelectCoreDialog selectCoreDialog = new SelectCoreDialog()) { selectCoreDialog.Games.AddRange(unknownApps); selectCoreDialog.ShowDialog(tasker.HostForm); } } // show select cover dialog if applicable unknownApps.Clear(); foreach (var app in addedApps) { if (!app.CoverArtMatchSuccess && app.CoverArtMatches.Any()) { unknownApps.Add(app); } } if (unknownApps.Count > 0) { using (SelectCoverDialog selectCoverDialog = new SelectCoverDialog()) { selectCoverDialog.Games.AddRange(unknownApps); selectCoverDialog.ShowDialog(tasker.HostForm); } } // update list view try { listViewGames.BeginUpdate(); foreach (ListViewItem item in listViewGames.Items) { item.Selected = false; } // add games, only new ones var newApps = addedApps.Distinct(new NesApplication.NesAppEqualityComparer()); var newCodes = from app in newApps select app.Code; var oldAppsReplaced = from app in listViewGames.Items.Cast <ListViewItem>().ToArray() where (app.Tag is NesApplication) && newCodes.Contains((app.Tag as NesApplication).Code) select app; // find "new apps" group ListViewGroup newGroup = null; if (listViewGames.Groups.Count > 0) { newGroup = listViewGames.Groups.OfType <ListViewGroup>().Where(group => group.Header == Resources.ListCategoryNew).FirstOrDefault(); } int i = 0, max = newApps.Count() + oldAppsReplaced.Count(); foreach (var replaced in oldAppsReplaced) { listViewGames.Items.Remove(replaced); tasker.SetProgress(++i, max); } foreach (var newApp in newApps) { var item = new ListViewItem(newApp.Name); item.Group = newGroup; item.Tag = newApp; item.Selected = true; item.Checked = true; listViewGames.Items.Add(item); tasker.SetProgress(++i, max); } } finally { listViewGames.EndUpdate(); } } return(Tasker.Conclusion.Success); }
private Tasker.Conclusion InstallSDPart1(Tasker tasker, Object sync) { tasker.SetStatus(Resources.InstallingHakchi); if (hakchi.Shell.Execute("[ -b /dev/mmcblk0 ]") != 0) { throw new Exception(Resources.NoSDCard); } var splitStream = new SplitterStream(Program.debugStreams); hakchi.Shell.Execute("mkdir -p /squashtools /tmp", null, null, null, 0, true); hakchi.Shell.Execute("umount /newroot"); hakchi.Shell.Execute("losetup -d /dev/loop2"); hakchi.Shell.Execute("umount /firmware"); hakchi.Shell.Execute("mkdir -p /sd-temp/", null, null, null, 0, true); tasker.SetStatus(Resources.ExtractingHakchiToTemporaryFolder); hakchi.Shell.Execute("tar -xzvf - -C /sd-temp/", hakchi.Hmod.GetHmodStream(), null, null, 0, true); // 16 tasker.SetProgress(16, 161); tasker.SetStatus(Resources.ClearingTheFirst32MBOfSDCard); hakchi.Shell.Execute("dd if=/dev/zero of=/dev/mmcblk0 bs=1M count=32", null, null, null, 0, true); // 32 tasker.SetProgress(48, 161); if (DialogOptions.MakeBootable) { tasker.SetStatus(Resources.AddingHakchiMBR); hakchi.Shell.Execute("printf \"hakchi\\n%s\\n\" \"$(cat \"/sd-temp/var/version\")\" | dd \"of=/dev/mmcblk0\"", null, null, null, 0, true); tasker.SetProgress(49, 161); tasker.SetStatus(Resources.WritingFATFilesystem); hakchi.Shell.Execute("gunzip -c /sd-temp/sd/data.vfat.gz | dd of=/dev/mmcblk0 bs=1M seek=32", null, null, null, 0, true); // 96 tasker.SetProgress(145, 161); tasker.SetStatus(Resources.WritingBoot0); hakchi.Shell.Execute("dd if=/sd-temp/sd/boot0.bin of=/dev/mmcblk0 bs=1K seek=8", null, null, null, 0, true); // 1 tasker.SetProgress(146, 161); tasker.SetStatus(Resources.WritingUboot); hakchi.Shell.Execute("dd if=/sd-temp/sd/uboot.bin of=/dev/mmcblk0 bs=1K seek=19096", null, null, null, 0, true); // 1 tasker.SetProgress(147, 161); tasker.SetStatus(Resources.WritingKernel); hakchi.Shell.Execute("dd if=/sd-temp/sd/kernel.img of=/dev/mmcblk0 bs=1K seek=20480", null, null, null, 0, true); // 4 tasker.SetProgress(151, 161); tasker.SetStatus(Resources.WritingSquashFS); hakchi.Shell.Execute("dd \"if=/sd-temp/sd/squash.hsqs\" of=/dev/mmcblk0 bs=1K seek=40", null, null, null, 0, true); // 10 tasker.SetProgress(161, 161); tasker.SetStatus(Resources.MountingSquashFS); hakchi.Shell.Execute($"losetup -o {1024 * 40} /dev/loop1 /dev/mmcblk0", null, null, null, 0, true); hakchi.Shell.Execute("mount /dev/loop1 /squashtools", null, null, null, 0, true); hakchi.Shell.Execute("cp /squashtools/init /tmp/init", null, null, null, 0, true); hakchi.Shell.Execute("sh /tmp/init partition", null, splitStream, splitStream, 0, true); } else { hakchi.Shell.Execute("echo sdprep | dd \"of=/dev/mmcblk0\"", null, null, null, 0, true); hakchi.Shell.Execute("mount /sd-temp/sd/squash.hsqs /squashtools", null, null, null, 0, true); hakchi.Shell.Execute("/squashtools/sfdisk /dev/mmcblk0", new MemoryStream(Encoding.ASCII.GetBytes("128M,,L\n")), splitStream, splitStream, 0, true); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion SyncOriginalGames(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.ResettingOriginalGames); tasker.SetStatusImage(Resources.sign_sync); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.ResettingOriginalGames); string desktopEntriesArchiveFile = Path.Combine(Path.Combine(Program.BaseDirectoryInternal, "data"), "desktop_entries.7z"); string originalGamesPath = Path.Combine(Program.BaseDirectoryExternal, "games_originals"); var selectedGames = ConfigIni.Instance.SelectedGames; if (!Directory.Exists(originalGamesPath)) { Directory.CreateDirectory(originalGamesPath); } if (!File.Exists(desktopEntriesArchiveFile)) { throw new FileLoadException("desktop_entries.7z data file was deleted, cannot sync original games."); } try { var defaultGames = ResetAllOriginalGames ? NesApplication.AllDefaultGames : NesApplication.DefaultGames; using (var szExtractor = new SevenZipExtractor(desktopEntriesArchiveFile)) { int i = 0; foreach (var f in szExtractor.ArchiveFileNames) { var code = Path.GetFileNameWithoutExtension(f); var query = defaultGames.Where(g => g.Code == code); if (query.Count() != 1) { continue; } var ext = Path.GetExtension(f).ToLower(); if (ext != ".desktop") // sanity check { throw new FileLoadException($"invalid file \"{f}\" found in desktop_entries.7z data file."); } string path = Path.Combine(originalGamesPath, code); string outputFile = Path.Combine(path, code + ".desktop"); bool exists = File.Exists(outputFile); if (exists && !NonDestructiveSync) { Shared.EnsureEmptyDirectory(path); Thread.Sleep(0); } if (!exists || !NonDestructiveSync) { Directory.CreateDirectory(path); // extract .desktop file from archive using (var o = new FileStream(outputFile, FileMode.Create, FileAccess.Write)) { szExtractor.ExtractFile(f, o); o.Flush(); if (!this.ResetAllOriginalGames && !selectedGames.Contains(code)) { selectedGames.Add(code); } } // create game temporarily to perform cover search Debug.WriteLine(string.Format("Resetting game \"{0}\".", query.Single().Name)); var game = NesApplication.FromDirectory(path); game.FindCover(code + ".desktop"); game.Save(); } tasker.SetProgress(++i, defaultGames.Length); } } } catch (Exception ex) { Debug.WriteLine("Error synchronizing original games " + ex.Message + ex.StackTrace); tasker.ShowError(ex, Resources.ErrorRestoringAllOriginalGames); return(Tasker.Conclusion.Error); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion UpdateLocal(Tasker tasker, Object SyncObject = null) { tasker.SetTitle(Resources.UpdatingLocalCache); tasker.SetStatusImage(Resources.sign_sync); tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.UpdatingLocalCache); var shell = hakchi.Shell; if (!shell.IsOnline) { return(Tasker.Conclusion.Abort); } string gamesCloverPath = shell.ExecuteSimple("hakchi eval 'echo \"$squashfs$gamepath\"'", 2000, true); string cachePath = Path.Combine(Program.BaseDirectoryExternal, "games_cache"); try { var reply = shell.ExecuteSimple($"[ -d \"{gamesCloverPath}\" ] && echo YES || echo NO"); if (reply == "NO") { gamesCloverPath = hakchi.GamesSquashFsPath; reply = shell.ExecuteSimple($"[ -d \"{gamesCloverPath}\" ] && echo YES || echo NO"); if (reply == "NO") { throw new Exception("Unable to update local cache. games directory not accessible"); } } var list = shell.ExecuteSimple($"ls \"{gamesCloverPath}\" -p -1 | grep '/'").Split(new[] { "\r\n", "\r", "\n" }, StringSplitOptions.None); int i = 0; foreach (var folder in list) { string gameCode = folder.Substring(0, folder.Length - 1); string gamePath = Path.Combine(cachePath, gameCode); if (!Directory.Exists(gamePath)) { try { Directory.CreateDirectory(gamePath); using (var tar = new MemoryStream()) { string cmd = $"cd {gamesCloverPath}/{gameCode} && tar -c *"; shell.Execute(cmd, null, tar, null, 10000, true); tar.Seek(0, SeekOrigin.Begin); using (var extractorTar = SharpCompress.Archives.Tar.TarArchive.Open(tar)) extractorTar.WriteToDirectory(gamePath, new SharpCompress.Common.ExtractionOptions() { ExtractFullPath = true, Overwrite = true }); } ++LoadedGames; } catch (Exception ex) { Trace.WriteLine(ex.Message + ex.StackTrace); if (Directory.Exists(gamePath)) { Trace.WriteLine($"Exception occured while loading data from NES/SNES mini, deleting \"{gamePath}\"."); Directory.Delete(gamePath, true); } } } tasker.SetProgress(++i, list.Length); } } catch (Exception ex) { Trace.WriteLine(ex.Message + ex.StackTrace); return(Tasker.Conclusion.Error); } return(Tasker.Conclusion.Success); }
public Tasker.Conclusion AddGames(Tasker tasker, Object syncObject = null) { tasker.SetProgress(-1, -1, Tasker.State.Running, Resources.AddingGames); tasker.SetTitle(Resources.AddingGames); tasker.SetStatusImage(Resources.sign_cogs); // static presets NesApplication.ParentForm = tasker.HostForm; NesApplication.NeedPatch = null; NesApplication.Need3rdPartyEmulator = null; NesApplication.CachedCoverFiles = null; NesGame.IgnoreMapper = null; SnesGame.NeedAutoDownloadCover = null; int total = files.Count(); int count = 0; var gamesWithMultipleArt = new List <NesApplication>(); foreach (var sourceFileName in files) { NesApplication app = null; try { tasker.SetStatus(string.Format(Resources.AddingGame, Path.GetFileName(sourceFileName))); var fileName = sourceFileName; var ext = Path.GetExtension(sourceFileName).ToLower(); byte[] rawData = null; string tmp = null; if (!asIs && (ext == ".7z" || ext == ".zip" || ext == ".rar" || ext == ".clvg")) { if (ext == ".clvg") { tmp = TempHelpers.getUniqueTempPath(); Directory.CreateDirectory(tmp); using (var file = File.OpenRead(sourceFileName)) using (var reader = ReaderFactory.Open(file)) { reader.WriteAllToDirectory(tmp, new ExtractionOptions() { ExtractFullPath = true, PreserveFileTime = true }); } var gameFilesInArchive = Directory.GetFiles(tmp, "*.desktop").Select(o => new DirectoryInfo(o)).Cast <DirectoryInfo>().ToArray(); switch (gameFilesInArchive.LongLength) { case 0: // no files found break; case 1: // one file found fileName = gameFilesInArchive[0].FullName; break; default: // multiple files found var r = SelectFile(tasker, gameFilesInArchive.Select(o => o.FullName).ToArray()); if (r == DialogResult.OK) { fileName = selectedFile; } else if (r == DialogResult.Ignore) { fileName = sourceFileName; } else { continue; } break; } } else { using (var extractor = ArchiveFactory.Open(sourceFileName)) { var filesInArchive = extractor.Entries; var gameFilesInArchive = new List <string>(); foreach (var f in extractor.Entries) { if (!f.IsDirectory) { var e = Path.GetExtension(f.Key).ToLower(); if (e == ".desktop") { gameFilesInArchive.Clear(); gameFilesInArchive.Add(f.Key); break; } else if (CoreCollection.Extensions.Contains(e)) { gameFilesInArchive.Add(f.Key); } } } if (gameFilesInArchive.Count == 1) // Only one known file (or app) { fileName = gameFilesInArchive[0]; } else if (gameFilesInArchive.Count > 1) // Many known files, need to select { var r = SelectFile(tasker, gameFilesInArchive.ToArray()); if (r == DialogResult.OK) { fileName = selectedFile; } else if (r == DialogResult.Ignore) { fileName = sourceFileName; } else { continue; } } else if (filesInArchive.Count() == 1) // No known files but only one another file { fileName = filesInArchive.First().Key; } else // Need to select { var r = SelectFile(tasker, filesInArchive.Select(f => f.Key).ToArray()); if (r == DialogResult.OK) { fileName = selectedFile; } else if (r == DialogResult.Ignore) { fileName = sourceFileName; } else { continue; } } if (fileName != sourceFileName) { var o = new MemoryStream(); if (Path.GetExtension(fileName).ToLower() == ".desktop" || // App in archive, need the whole directory filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".jpg") || // Or it has cover in archive filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".png") || filesInArchive.Select(f => f.Key).Contains(Path.GetFileNameWithoutExtension(fileName) + ".ips") // Or IPS file ) { tmp = Path.Combine(tempDirectory, fileName); Directory.CreateDirectory(tmp); extractor.WriteToDirectory(tmp, new ExtractionOptions() { ExtractFullPath = true, Overwrite = true }); fileName = Path.Combine(tmp, fileName); } else { extractor.Entries.Where(f => f.Key == fileName).First().WriteTo(o); rawData = new byte[o.Length]; o.Seek(0, SeekOrigin.Begin); o.Read(rawData, 0, (int)o.Length); } } } } } app = NesApplication.Import(fileName, sourceFileName, rawData, asIs); if (ext == ".clvg") { app.SkipCoreSelect = true; } else { if (app != null && app.CoverArtMatches != null && app.CoverArtMatches.Count() > 1) { gamesWithMultipleArt.Add(app); } NewGames.Add(app); } if (app is ISupportsGameGenie && Path.GetExtension(fileName).ToLower() == ".nes") { var lGameGeniePath = Path.Combine(Path.GetDirectoryName(fileName), Path.GetFileNameWithoutExtension(fileName) + ".xml"); if (File.Exists(lGameGeniePath)) { GameGenieDataBase lGameGenieDataBase = new GameGenieDataBase(app); lGameGenieDataBase.ImportCodes(lGameGeniePath, true); lGameGenieDataBase.Save(); } } if (!string.IsNullOrEmpty(tmp) && Directory.Exists(tmp)) { Directory.Delete(tmp, true); } } catch (Exception ex) { if (ex is ThreadAbortException) { return(Tasker.Conclusion.Abort); } if (ex.InnerException != null && !string.IsNullOrEmpty(ex.InnerException.Message)) { Trace.WriteLine(ex.InnerException.Message + ex.InnerException.StackTrace); tasker.ShowError(ex.InnerException, Path.GetFileName(sourceFileName)); } else { Trace.WriteLine(ex.Message + ex.StackTrace, Path.GetFileName(sourceFileName)); tasker.ShowError(ex); } return(Tasker.Conclusion.Error); } if (app != null) { addedApps.Add(app); } tasker.SetProgress(++count, total); } if (gamesWithMultipleArt.Count > 0) { tasker.HostForm.Invoke(new Action(() => { using (SelectCoverDialog selectCoverDialog = new SelectCoverDialog()) { selectCoverDialog.Games.AddRange(gamesWithMultipleArt); selectCoverDialog.ShowDialog(tasker.HostForm); } })); } return(Tasker.Conclusion.Success); }