public async Task SetMetaData(string fileName, IEnumerable <MetaDataItem> metaData, Func <MetaDataItem, bool> predicate) { if (MetaDataBehaviourConfiguration.GetWriteBehaviour(this.Write.Value) == WriteBehaviour.None) { Logger.Write(this, LogLevel.Warn, "Writing is disabled: {0}", fileName); return; } if (!this.IsSupported(fileName)) { Logger.Write(this, LogLevel.Warn, "Unsupported file format: {0}", fileName); return; } var metaDataItems = default(IEnumerable <MetaDataItem>); lock (metaData) { if (predicate != null) { metaDataItems = metaData.Where(predicate).ToArray(); } else { metaDataItems = metaData.ToArray(); } if (!metaDataItems.Any()) { //Nothing to update. return; } } var collect = default(bool); using (var file = this.FileFactory.Create(fileName)) { if (file.PossiblyCorrupt) { this.AddWarnings(fileName, file.CorruptionReasons); } foreach (var metaDataItem in metaDataItems) { switch (metaDataItem.Type) { case MetaDataItemType.Tag: this.SetTag(metaDataItem, file); break; case MetaDataItemType.Image: if (file.InvariantStartPosition > MAX_TAG_SIZE) { collect = true; } await ImageManager.Write(this, metaDataItem, file).ConfigureAwait(false); break; case MetaDataItemType.Document: if (this.Documents.Value) { DocumentManager.Write(this, metaDataItem, file); } break; } } if (file is IMetaDataSource metaDataSource) { await this.SetAdditional(metaData, file, metaDataSource).ConfigureAwait(false); } file.Save(); } if (collect) { //If we encountered a large meta data section (>10MB) then we need to try to reclaim the memory. GC.Collect(); } }
public async Task <IEnumerable <MetaDataItem> > GetMetaData(string fileName, Func <File> factory) { if (!this.IsSupported(fileName)) { Logger.Write(this, LogLevel.Warn, "Unsupported file format: {0}", fileName); this.AddWarning(fileName, "Unsupported file format."); return(Enumerable.Empty <MetaDataItem>()); } var collect = default(bool); var metaData = new List <MetaDataItem>(); Logger.Write(this, LogLevel.Trace, "Reading meta data for file: {0}", fileName); try { using (var file = factory()) { if (file.PossiblyCorrupt) { this.AddWarnings(fileName, file.CorruptionReasons); } if (file.InvariantStartPosition > MAX_TAG_SIZE) { collect = true; } if (file.Tag != null) { this.AddTags(metaData, file.Tag); } if (file.Properties != null) { this.AddProperties(metaData, file.Properties); } if (this.Popularimeter.Value) { this.Try(() => PopularimeterManager.Read(this, metaData, file), this.ErrorHandler); } if (this.ReplayGain.Value) { this.Try(() => ReplayGainManager.Read(this, metaData, file), this.ErrorHandler); } if (this.Documents.Value) { this.Try(() => DocumentManager.Read(this, metaData, file), this.ErrorHandler); } this.Try(() => CompilationManager.Read(this, metaData, file), this.ErrorHandler); if (file is IMetaDataSource metaDataSource) { await this.AddAdditional(metaData, file, metaDataSource).ConfigureAwait(false); } await ImageManager.Read(this, metaData, file).ConfigureAwait(false); } } catch (UnsupportedFormatException) { Logger.Write(this, LogLevel.Warn, "Unsupported file format: {0}", fileName); this.AddWarning(fileName, "Unsupported file format."); } catch (OutOfMemoryException) { //This can happen with really big embedded images. //It's tricky to avoid because we can't check InvariantStartPosition without parsing. Logger.Write(this, LogLevel.Warn, "Out of memory: {0}", fileName); this.AddWarning(fileName, "Out of memory."); collect = true; } catch (Exception e) { Logger.Write(this, LogLevel.Warn, "Failed to read meta data: {0} => {1}", fileName, e.Message); this.AddWarning(fileName, string.Format("Failed to read meta data: {0}", e.Message)); } finally { if (collect) { //If we encountered a large meta data section (>10MB) then we need to try to reclaim the memory. GC.Collect(); } } return(metaData); }