public void GetContentMetadata(Book.Part part, EFlags flags = default) { var filename = part.AaxFileItem.FileName; Log(3, this, () => $"\"{filename.SubstitUser ()}\", flags={flags}"); try { var contentMetadataFile = findContentMetadataFile(filename); if (contentMetadataFile is null || contentMetadataFile.Filename is null) { part.AaxFileItem.ContentMetadataFile = new AsinJsonFile(null, null); return; } part.AaxFileItem.ContentMetadataFile = contentMetadataFile; string metafile = contentMetadataFile.Filename; Log(3, this, () => $"\"{metafile.SubstitUser ()}\""); if (flags.HasFlag(EFlags.fileOnly)) { return; } getContentMetaChapters(part, metafile, flags.HasFlag(EFlags.skuOnly)); } catch (Exception exc) { Log(1, this, () => exc.ToShortString()); } }
private void setContext(Book.Part part = null) { if (part is null && Book.PartsType != Book.EParts.some) { part = Book?.Parts?.FirstOrDefault(); } if (part is null || !part.AaxFileItem.Converted) { return; } AaxFileItem = part.AaxFileItem; double duration = 0; if (Book.PartsType != Book.EParts.some) { duration = Book.Parts.SelectMany(p => p.Tracks).Select(t => t.Time.Duration.TotalSeconds).Sum(); } else { duration = part.Tracks.Select(t => t.Time.Duration.TotalSeconds).Sum(); } Duration = TimeSpan.FromSeconds(duration); }
public void GetContentMetadata(Book.Part part, bool fileOnly = false) { var filename = part.AaxFileItem.FileName; Log(3, this, () => $"\"{filename.SubstitUser ()}\", file only={fileOnly}"); var contentMetadataFile = findContentMetadataFile(filename); if (contentMetadataFile is null || contentMetadataFile.Filename is null) { part.AaxFileItem.ContentMetadataFile = new ContentMetadataFile(null, null); return; } part.AaxFileItem.ContentMetadataFile = contentMetadataFile; string metafile = contentMetadataFile.Filename; Log(3, this, () => $"\"{metafile.SubstitUser ()}\""); if (fileOnly) { return; } getContentMetaChapters(part, metafile); }
private string chapterList(Book.Part part) { var sb = new StringBuilder($"content meta chapters:"); sb.AppendLine(); if (!(part.Chapters2 is null)) { foreach (var ch in part.Chapters2) { sb.AppendLine($" {ch}"); } } sb.Append($" intro={part.BrandIntro.ToStringHMSm ()}, outro={part.BrandOutro.ToStringHMSm ()}, duration={part.Duration.ToStringHMSm ()}"); return(sb.ToString()); }
private AA.AsinJsonFile findSeriesFileDirectOrSku(Book.Part part, bool fileOnly, string filePrefix, GetProductsDelegate getProducts) { // try to find sims by series file, either locally, relative or absolute // precondition content meta file is available // either by ASIN (single-part book) or by SKU (multipart book) // get asin var afi = part.AaxFileItem; string asin = afi.ContentMetadataFile?.ASIN; if (asin is null) { Log(3, this, () => $"ASIN not found."); return(null); } Log(3, this, () => $"ASIN={asin}{(filePrefix.IsNullOrWhiteSpace() ? string.Empty : $", prefix={filePrefix}")}");
private bool findSeriesFile(Book.Part part, bool fileOnly, string filePrefix, GetProductsDelegate getProducts) { try { var simsBySeriesFile = findSeriesFileDirectOrSku(part, fileOnly, filePrefix, getProducts); if (simsBySeriesFile is null || simsBySeriesFile.Filename is null) { part.AaxFileItem.SimsBySeriesFile = new AA.AsinJsonFile(null, null); return(false); } part.AaxFileItem.SimsBySeriesFile = simsBySeriesFile; string metafile = simsBySeriesFile.Filename; Log(3, this, () => $"\"{metafile.SubstitUser ()}\""); return(true); } catch (Exception exc) { Log(1, this, () => exc.ToShortString()); return(false); } }
public void GetSimsBySeries(Book.Part part, bool fileOnly = false) { if (part.Book.ExternalMeta != null) { return; } var filename = part.AaxFileItem.FileName; Log(3, this, () => $"\"{filename.SubstitUser ()}\", file only={fileOnly}"); // either ASIN.json or series_titles_ASIN.json bool succ = findSeriesFile(part, fileOnly, string.Empty, getProductsSingle); if (!succ) { findSeriesFile(part, fileOnly, SERIES_TITLES, getProductsMulti); } }
public readonly int nnPrt = -1; // part digits public Numbers(Track track, Book.Part part) { Book book = part.Book; this.nPrt = part.PartNumber; this.nnPrt = book.Parts.Select(p => p.PartNumber).Max().Digits(); if (!(track is null)) { var chapterTracks = part.Tracks?.Where(t => !(track.Chapter is null) && object.ReferenceEquals(t.Chapter, track.Chapter)).ToList(); this.nChTrk = (chapterTracks?.IndexOf(track) ?? -1) + 1; this.nChTrks = chapterTracks?.Count ?? 0; this.nnChTrk = this.nChTrks.Digits(); } if (book.PartsType == Book.EParts.some) { this.nTrk = (part.Tracks?.IndexOf(track) ?? -1) + 1; this.nTrks = part.Tracks?.Count ?? 0; this.nDsk = part.PartNumber; this.nDsks = 0; this.nChp = (part.Chapters?.IndexOf(track?.Chapter) ?? -1) + 1; this.nnChp = part.Chapters?.Count.Digits() ?? 0; } else { this.nTrk = book.Parts.Select(pt => { if (pt != part) { if (pt.PartNumber < part.PartNumber) { return(pt.Tracks?.Count ?? 0); } else { return(0); } } else { return((part.Tracks?.IndexOf(track) ?? -1) + 1); } }).Sum(); this.nTrks = book.Parts.Select(p => p.Tracks?.Count() ?? 0).Sum(); this.nDsks = book.Parts.Count; this.nChp = book.Parts.Select(pt => { if (pt != part) { if (pt.PartNumber < part.PartNumber) { return(pt.Chapters?.Count ?? 0); } else { return(0); } } else { if (track?.Chapter is null) { return(0); } else { return((pt.Chapters?.IndexOf(track?.Chapter) ?? -1) + 1); } } }).Sum(); this.nnChp = book.Parts.Select(p => p.Chapters?.Count ?? 0).Sum().Digits(); this.nDsk = book.PartsType == Book.EParts.none ? 1 : part.PartNumber; } this.nnTrk = this.nTrks.Digits(); }
public void CreateCueSheet(Book.Part part, int trackDurMins, bool splitTimeMode) { Log(3, this, () => this.ToString()); // chapter duration in sec double chLenSec = this.Time.Duration.TotalSeconds; // rounded number of tracks in chapter, observing desired track duration int numTracks = Math.Max((int)(chLenSec / (trackDurMins * 60) + 0.5), 1); // average track length in sec double aveTrackLen = chLenSec / numTracks; // average track length as TimeSpan var tsAveTrackLen = TimeSpan.FromSeconds(aveTrackLen); // search range for silence at desired end of track is +/- 1/3 ave track length var tsSearchRange = TimeSpan.FromSeconds(aveTrackLen / 3); // start 1st track at zero // unless in time split mode where we start at the actual beginning of the chapter var tsStart = TimeSpan.Zero; if (splitTimeMode) { tsStart = this.Time.Begin; } // desired end of 1st track var tsEnd = tsStart + tsAveTrackLen; // max end is chapter duration unless in time split mode var tsChEnd = this.Time.Duration - TS_EPS_SILENCE; if (splitTimeMode) { tsChEnd = this.Time.End; } // filter silences var silences = this.Silences.Where(s => s.Duration >= TS_SHORT_SILENCE).ToList(); // while chapter length has not been reached, will be checked in loop while (true) { if (tsEnd < tsChEnd) { // upper search limit for silence var tsUpper = tsEnd + tsSearchRange; // lower search limit for silence var tsLower = tsEnd - tsSearchRange; // take the easy road using LINQ, find nearest silence or none, above and below var silUp = silences.Where(t => t.Begin >= tsEnd && t.Begin < tsUpper).FirstOrDefault(); var silDn = silences.Where(t => t.End > tsLower && t.End <= tsEnd).LastOrDefault(); // which silence shall it be TimeInterval sil = null; if (!(silUp is null || silDn is null)) { // up and down found, use nearest var deltaUp = silUp.Begin - tsEnd; var deltaDn = tsEnd - silDn.End; if (deltaUp < deltaDn) { sil = silUp; } else { sil = silDn; } } else { // not both found, use any present if (!(silUp is null)) { sil = silUp; }
public PartChapters(Book.Part part) { Part = part; }
private void getContentMetaChapters(Book.Part part, string metafile, bool skuOnly) { string json = File.ReadAllText(metafile); var metadata = JsonConvert.DeserializeObject <json.AppContentMetadata> (json); // get the SKU part.SKU = metadata.content_metadata.content_reference.sku; Log(3, this, () => $"SKU={part.SKU}"); if (skuOnly) { return; } // set the chapters var chapters = new List <Chapter> (); var metaChapters = metadata.content_metadata.chapter_info.chapters; if (metaChapters.Count == 0) { return; } // handle chapters with no name. Set '.' as a placeholder var whites = metaChapters.Where(c => string.IsNullOrWhiteSpace(c.title)).ToList(); whites.ForEach(c => c.title = "."); // handle chapters of zero length. Min length must be 1 ms. var zeros = metaChapters.Where(c => c.length_ms == 0).ToList(); Log(3, this, () => $"chapters: #zero={zeros.Count}, #white={whites.Count}"); if (zeros.Count > 0) { zeros.ForEach(c => c.length_ms = Chapter.MS_MIN_CHAPTER_LENGTH); for (int i = 1; i < metaChapters.Count; i++) { var ch0 = metaChapters[i - 1]; var ch = metaChapters[i]; int chOffsNew = ch0.start_offset_ms + ch0.length_ms; if (ch.start_offset_ms >= chOffsNew) { continue; } Log(3, this, () => $"duration fix for: {ch}"); int chLenNew = ch.length_ms + ch.start_offset_ms - chOffsNew; if (chLenNew <= 0) { chLenNew = Chapter.MS_MIN_CHAPTER_LENGTH; } ch.start_offset_ms = chOffsNew; ch.length_ms = chLenNew; } } foreach (var ch in metaChapters) { var chapter = new Chapter(); chapter.Name = ch.title.Trim(); chapter.Time.Begin = TimeSpan.FromMilliseconds(ch.start_offset_ms); chapter.Time.End = TimeSpan.FromMilliseconds(ch.start_offset_ms + ch.length_ms); chapters.Add(chapter); } part.Chapters2 = chapters; // set brandintro and brandoutro times part.BrandIntro = TimeSpan.FromMilliseconds(metadata.content_metadata.chapter_info.brandIntroDurationMs); part.BrandOutro = TimeSpan.FromMilliseconds(metadata.content_metadata.chapter_info.brandOutroDurationMs); part.Duration = TimeSpan.FromMilliseconds(metadata.content_metadata.chapter_info.runtime_length_ms); Log(3, this, () => chapterList(part)); }
public void GetContentMetadata(Book.Part part, bool fileOnly) => GetContentMetadata(part, fileOnly ? EFlags.fileOnly : default);