//Ensures that all placeholders in the pattern refer to existing tag frame properties. //Then it attempts to mapping dictionary between the frame name and the corresponding frame //property, so that multiple renames can be done fast. private static Dictionary <string, PropertyInfo> ValidatePatternAndBuildMapping(string pattern) { //Find all placeholders within the pattern. If there are none, throw an exception. MatchCollection framePlaceholderMatches = FramePlaceholderPattern.Matches(pattern); if (framePlaceholderMatches.Count == 0) { throw new ArgumentException(string.Format(Id3FileMessages.MissingPlaceholdersInPattern, pattern)); } //Get all public properties in the tag that derive from Id3Frame. PropertyInfo[] frameProperties = typeof(Id3Tag).GetProperties().Where(prop => prop.PropertyType.IsSubclassOf(typeof(Id3Frame))).ToArray(); //Iterate through each placeholder and find the corresponding frame property. If such a //property does not exist, throw an exception; otherwise add a mapping from the frame name //to the property. var mapping = new Dictionary <string, PropertyInfo>(framePlaceholderMatches.Count); foreach (Match match in framePlaceholderMatches) { string matchedFrameName = match.Groups[1].Value.ToLowerInvariant(); PropertyInfo matchingFrameProperty = frameProperties.FirstOrDefault(frame => frame.Name.Equals(matchedFrameName, StringComparison.InvariantCultureIgnoreCase)); if (matchingFrameProperty == null) { throw new ArgumentException(string.Format(Id3FileMessages.MissingTagProperty, matchedFrameName)); } if (!mapping.ContainsKey(matchedFrameName)) { mapping.Add(matchedFrameName, matchingFrameProperty); } } return(mapping); }
/// <summary> /// Ensures that all placeholders in the pattern refer to existing tag frame properties. Then it attempts to mapping /// dictionary between the frame name and the corresponding frame property, so that multiple renames can be done fast. /// </summary> /// <param name="patterns">The pattern to validate</param> /// <returns>A mapping of placeholder name to property info of the correspoding frame in <see cref="Id3Tag" /></returns> /// <exception cref="ArgumentException">Thrown if any pattern contains invalid placeholders.</exception> private static void ValidatePatterns(IEnumerable <string> patterns) { // Get all distinct placeholder names in all the patterns and check whether any of them // do not appear as a key in the _mappings dictionary. If so, throw an exception. string[] invalidPlaceholders = patterns .SelectMany(pattern => { MatchCollection matches = FramePlaceholderPattern.Matches(pattern); if (matches.Count == 0) { throw new ArgumentException(string.Format(FileNamerMessages.MissingPlaceholdersInPattern, pattern)); } return(matches.Cast <Match>().Select(m => m.Groups[1].Value)); }) .Distinct(StringComparer.OrdinalIgnoreCase) .Where(ph => !_mapping.ContainsKey(ph)) .ToArray(); if (invalidPlaceholders.Length <= 0) { return; } //Build detailed exception and throw it. string invalidPlaceholderNames = string.Join(", ", invalidPlaceholders); string allowedPlaceholderNames = string.Join(", ", _allowedFrames); string exceptionMessage = "The following placeholders are not allowed in the file naming patterns:" + Environment.NewLine + Environment.NewLine + invalidPlaceholderNames + Environment.NewLine + Environment.NewLine + "Only these placeholders are allowed:" + Environment.NewLine + Environment.NewLine + allowedPlaceholderNames; throw new ArgumentException(exceptionMessage, nameof(patterns)); }
private string GetNewName(Id3Tag tag, string originalName, out string missingFrameName) { missingFrameName = null; string missingFrame = null; //Make two passes of the patterns. //In the first pass, we try to find the perfect match without resorting to the //ResolveMissingData event. //If we still don't have a match, in the second pass, we use the ResolveMissingData event. for (var i = 0; i < 2; i++) { foreach (string pattern in _patterns) { var hasMissingFrames = false; int iteration = i; string newName = FramePlaceholderPattern.Replace(pattern, match => { //If this pattern already has missing frames, don't proces anything if (hasMissingFrames) { return(string.Empty); } string frameName = match.Groups[1].Value; PropertyInfo frameProperty = _mapping[frameName]; //Because all frame properties in Id3Tag are lazily-loaded, this will never be null var frame = (Id3Frame)frameProperty.GetValue(tag, null); if (frame.IsAssigned) { return(frame.ToString()); } if (iteration == 1) { string frameValue = FireResolveMissingDataEvent(tag, frame, originalName); if (!string.IsNullOrWhiteSpace(frameValue)) { return(frameValue); } } hasMissingFrames = true; missingFrame = frameName; return(string.Empty); }); if (!hasMissingFrames) { return(newName); } } } missingFrameName = missingFrame; return(null); }
private IEnumerable <T> RenameOrSuggest <T>(IEnumerable <string> filePaths) where T : RenameAction, new() { foreach (string filePath in filePaths) { if (string.IsNullOrWhiteSpace(filePath)) { yield return(new T { Directory = filePath, OriginalName = filePath, Status = RenameStatus.Error, ErrorMessage = Id3FileMessages.InvalidFilePath }); continue; } if (!File.Exists(filePath)) { yield return(new T { Directory = filePath, OriginalName = filePath, Status = RenameStatus.Error, ErrorMessage = Id3FileMessages.MissingFile }); continue; } var result = new T { Directory = Path.GetDirectoryName(filePath), OriginalName = Path.GetFileName(filePath) }; using (var mp3 = new Mp3File(filePath)) { Id3Tag tag = mp3.GetTag(2, 3); if (tag == null) { result.Status = RenameStatus.Error; result.ErrorMessage = Id3FileMessages.MissingId3v23TagInFile; yield return(result); continue; } string missingFrameName = null; string newName = FramePlaceholderPattern.Replace(_pattern, match => { string frameName = match.Groups[1].Value; string frameNameKey = frameName.ToLowerInvariant(); PropertyInfo frameProperty = _mapping[frameNameKey]; var frame = (Id3Frame)frameProperty.GetValue(tag, null); string frameValue = frame.IsAssigned ? frame.ToString() : FireResolveMissingDataEvent(tag, frame, result.OriginalName); if (string.IsNullOrEmpty(frameValue)) { missingFrameName = frameName; } return(frameValue); }); if (missingFrameName != null) { result.Status = RenameStatus.Error; result.ErrorMessage = string.Format(Id3FileMessages.MissingDataForFrame, missingFrameName); yield return(result); continue; } result.NewName = newName + ".mp3"; RenamingEventArgs renamingEventResult = FireRenamingEvent(tag, result.OriginalName, result.NewName); if (renamingEventResult.Cancel) { result.Status = RenameStatus.Cancelled; } else { result.NewName = renamingEventResult.NewName; } if (result.OriginalName.Equals(result.NewName, StringComparison.Ordinal)) { result.Status = RenameStatus.CorrectlyNamed; } yield return(result); } } }