/// <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> /// 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(string filepath) { //Check that the file exists, just in case if (!File.Exists(filepath)) { Logger.LogError("Warning! Psarc file {0} does not exist!", filepath); return(null); } var sw = new Stopwatch(); sw.Start(); //If its big, print a warning var fileinfo = new FileInfo(filepath); long size = fileinfo.Length; var detailsDict = new Dictionary <string, SongDetails>(); using (LazyPsarcLoader loader = new LazyPsarcLoader(filepath)) { //Extract toolkit info var tkInfo = loader.ExtractToolkitInfo(); List <Manifest2014 <Attributes2014> > manifests = null; try { manifests = loader.ExtractJsonManifests(); } catch (Exception e) { Logger.LogError("Warning! Could not parse psarc file {0}: {1}", Path.GetFileName(filepath), e.Message); return(null); } //Extract all arrangements foreach (var v in manifests) { if (v == null) { Logger.LogError("Unable to process JSON manifest for {0}", Path.GetFileName(filepath)); continue; } var arrangement = v.Entries.First(); var arrangement_id = arrangement.Key; var attr = arrangement.Value.First().Value; if (attr.Phrases != null) { if (!detailsDict.ContainsKey(attr.SongKey)) { detailsDict[attr.SongKey] = new SongDetails(); } SongDetails details = detailsDict[attr.SongKey]; if (details.albumArt == null) { try { details.albumArt = ExtractAlbumArt(loader, attr.AlbumArt); } catch (Exception) { Logger.LogError("Warning: couldn't extract album art for {0}", attr.SongName); 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 attr.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]++; } //Build arrangement details var arrangementDetails = new ArrangementDetails { name = attr.ArrangementName, arrangementID = arrangement_id, sections = sections, isBonusArrangement = (attr.ArrangementProperties.BonusArr == 1), isAlternateArrangement = (attr.ArrangementProperties.Represent == 0) }; //Determine path type if (attr.ArrangementProperties.PathLead == 1) { arrangementDetails.type = "Lead"; } else if (attr.ArrangementProperties.PathRhythm == 1) { arrangementDetails.type = "Rhythm"; } else if (attr.ArrangementProperties.PathBass == 1) { arrangementDetails.type = "Bass"; } //Get general song information details.songID = attr.SongKey; details.songLength = (float)(attr.SongLength ?? 0); details.songName = attr.SongName; details.artistName = attr.ArtistName; details.albumName = attr.AlbumName; details.albumYear = attr.SongYear ?? 0; 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); } }