/// <summary> /// Reads psarc file from filepath and populates details with information /// </summary> /// <param name="filepath"></param> /// <param name="details"></param> internal static Dictionary <string, SongDetails> ReadPSARCHeaderData(FileInfo fileInfo) { //Wait for the file to exist WaitForFile(fileInfo); if (!fileInfo.Exists) { Logger.LogError("Warning! Psarc file {0} does not exist!", fileInfo.FullName); return(null); } var sw = new Stopwatch(); sw.Start(); string fileHash = GetFileHash(fileInfo); var detailsDict = new Dictionary <string, SongDetails>(); using (PsarcFile loader = new PsarcFile(fileInfo)) { //Extract toolkit info var tkInfo = loader.ExtractToolkitInfo(); List <SongArrangement> manifests; try { manifests = loader.ExtractArrangementManifests(); } catch (Exception e) { Logger.LogError("Warning! Could not parse psarc file {0}: {1}", fileInfo.Name, e.Message); return(null); } //Extract all arrangements foreach (var v in manifests) { if (v == null) { Logger.LogError("Unable to process JSON manifest for {0}", fileInfo.Name); continue; } var arrangement = v.Attributes; var arrangement_id = arrangement.PersistentID; var arrangementSng = loader.InflateEntry <SngAsset>(a => a.Path.Equals($"songs/bin/generic/{arrangement.SongXml.Substring(20)}.sng")); ArrangementData arrangementData = new ArrangementData(arrangementSng); if (arrangement.Phrases != null) { if (!detailsDict.ContainsKey(arrangement.SongKey)) { detailsDict[arrangement.SongKey] = new SongDetails(); } SongDetails details = detailsDict[arrangement.SongKey]; if (details.albumArt == null) { try { details.albumArt = loader.ExtractAlbumArt(arrangement).Bitmap; } catch (Exception e) { Logger.LogError("Warning: couldn't extract album art for {0}", arrangement.SongName); #if DEBUG Logger.LogException(e); #endif details.albumArt = new Bitmap(1, 1); } } //Get a list of all sections var sections = new List <ArrangementDetails.SectionDetails>(); Dictionary <string, int> sectionCounts = new Dictionary <string, int>(); foreach (var sect in arrangement.Sections) { if (!sectionCounts.ContainsKey(sect.Name)) { sectionCounts[sect.Name] = 1; } var sectionDetails = new ArrangementDetails.SectionDetails { name = $"{sect.Name} {sectionCounts[sect.Name]}", startTime = sect.StartTime, endTime = sect.EndTime }; sections.Add(sectionDetails); sectionCounts[sect.Name]++; } //Get a list of all phraseIterations var phraseIterations = new List <ArrangementDetails.PhraseIterationDetails>(); Dictionary <string, int> phraseIterationCounts = new Dictionary <string, int>(); foreach (var phrI in arrangement.PhraseIterations) { if (!phraseIterationCounts.ContainsKey(phrI.Name)) { phraseIterationCounts[phrI.Name] = 1; } var phraseIterationDetails = new ArrangementDetails.PhraseIterationDetails { name = $"{phrI.Name} {phraseIterationCounts[phrI.Name]}", phraseId = phrI.PhraseIndex, maxDifficulty = phrI.MaxDifficulty, startTime = phrI.StartTime, endTime = phrI.EndTime }; phraseIterations.Add(phraseIterationDetails); phraseIterationCounts[phrI.Name]++; } //Build arrangement details var arrangementDetails = new ArrangementDetails { name = arrangement.ArrangementName, arrangementID = arrangement_id, sections = sections, phraseIterations = phraseIterations, data = arrangementData, isBonusArrangement = (arrangement.ArrangementProperties.BonusArr == 1), isAlternateArrangement = (arrangement.ArrangementProperties.Represent == 0) }; //Determine path type if (arrangement.ArrangementProperties.PathLead == 1) { arrangementDetails.type = "Lead"; } else if (arrangement.ArrangementProperties.PathRhythm == 1) { arrangementDetails.type = "Rhythm"; } else if (arrangement.ArrangementProperties.PathBass == 1) { arrangementDetails.type = "Bass"; } arrangementDetails.tuning = new ArrangementTuning(arrangement.Tuning, (int)arrangement.CentOffset, (int)arrangement.CapoFret); //file hash details.psarcFileHash = fileHash; //Get general song information details.songID = arrangement.SongKey; details.songLength = arrangement.SongLength; details.songName = arrangement.SongName; details.artistName = arrangement.ArtistName; details.albumName = arrangement.AlbumName; details.albumYear = arrangement.SongYear; details.arrangements.Add(arrangementDetails); //Apply toolkit information details.toolkit = new ToolkitDetails { version = tkInfo.PackageVersion, author = tkInfo.PackageAuthor, comment = tkInfo.PackageComment, package_version = tkInfo.PackageVersion }; } } sw.Stop(); Logger.Log("Parsed {0} ({1}mb) in {2}ms and found {3} songs", fileInfo.Name, fileInfo.Length / 1024 / 1024, sw.ElapsedMilliseconds, detailsDict.Count); return(detailsDict); } }
/// <summary> /// Fills Songs with SongData. /// </summary> /// <param name="progressBar"> - Attach a progress bar to the loading process.</param> /// <returns> - Value of Songs</returns> public static Dictionary <string, SongData> ExtractSongData(ProgressBar progressBar = null) { // Init Songs.Clear(); bool progressBarAvailable = progressBar != null; List <string> allFiles = Directory.GetFiles(Path.Combine(Settings.Settings.RocksmithLocation, "dlc"), "*_p.psarc", SearchOption.AllDirectories).ToList(); // Setup Progressbar if passed in as a parameter. if (progressBarAvailable) { progressBar.Visible = true; progressBar.Minimum = 1; progressBar.Maximum = allFiles.Count; progressBar.Value = 1; progressBar.Step = 1; } // Look through every file in allFiles. ParallelLoopResult loopResult = Parallel.ForEach(allFiles, (file) => { try { using (PsarcFile psarc = new PsarcFile(file)) { List <SongArrangement> ExtractedArrangementManifests = psarc.ExtractArrangementManifests(); // List every arrangement in the psarc. This is crucial for looking at song packs! foreach (SongArrangement arrangement in ExtractedArrangementManifests) { SongData song = new SongData() { DLCKey = arrangement.Attributes.SongKey, Artist = arrangement.Attributes.ArtistName, AppID = psarc.ExtractAppID(), Title = arrangement.Attributes.SongName, Shipping = arrangement.Attributes.Shipping, SKU = arrangement.Attributes.SKU, CommonName = $"{arrangement.Attributes.ArtistName} - {arrangement.Attributes.SongName}" }; if (song.DLCKey == null || song.CommonName == string.Empty || song.CommonName == " - " || song.Artist == string.Empty || song.Title == string.Empty || !song.Shipping) // Some songs have a glitched arrangment, so we skip it. { continue; } // Load all RS1 DLC and their ID so we can determine if the user owns it, and if we should display it accordingly. if (psarc.ExtractToolkitInfo().PackageAuthor == "Ubisoft") { song.ODLC = true; if (arrangement.Attributes.SKU == "RS1" && arrangement.Attributes.DLCRS1Key != null) { song.RS1AppID = arrangement.Attributes.DLCRS1Key[0].WIN32; } } // Add Song to Songs if it isn't already in it. if (Songs.ContainsKey(song.DLCKey)) { continue; } else if (song != null) { Songs.Add(song.DLCKey, song); } } } } catch {} // We are reading the files too quick. Let's forget about it for now as we are just trying to get a rough count. }); // Shutdown Progressbar if (progressBarAvailable) { progressBar.Visible = false; progressBar.Value = progressBar.Minimum; } Songs = Songs.Where(song => song.Key != null).Distinct().ToDictionary(song => song.Key, song => song.Value); // Clear out duplicates, and any null values that got accidently set. return(Songs); }