Ejemplo n.º 1
0
 public static void Log(string message, DebugStack ds)
 {
     if (ds != null)
     {
         ds.Log(message);
     }
     else
     {
         Log(message);
     }
 }
Ejemplo n.º 2
0
        // --- Main Process Method ---
        private static TagWriterReturnCode WriteTagsForRow(Entry entry, int processed, DebugStack ds)
        {
            TagLib.File file;
            ds.Log("#" + processed + " - " + entry.fileName);

            // Check if the entry is mapped to a file
            if (entry.isMapped == false)
            {
                string message = "Entry is not matched to file";
                ds.LogWarning(" -> " + message);
                entryErrors.TryAdd(entry, message);
                return(TagWriterReturnCode.Unmapped);
            }

            bool isRetry = false;

Retry:

            // Create TagLib file representation, catch to see if the file is valid
            try
            {
                file = TagLib.File.Create(entry.mappedFilePath, isRetry ? ReadStyle.Average : ReadStyle.PictureLazy);
            }
            catch (Exception exception)
            {
                var    type         = exception.GetType();
                string errorMessage = "";
                TagWriterReturnCode returnCode;

                if (type == typeof(UnsupportedFormatException))
                {
                    errorMessage = "File format with extension \"" + Path.GetExtension(entry.mappedFilePath) + "\" is unsupported (" + exception.Message + ")";
                    returnCode   = TagWriterReturnCode.UnsupportedFormat;
                }
                else if (type == typeof(CorruptFileException))
                {
                    errorMessage = "File appears corrupt! " + exception.Message;
                    returnCode   = TagWriterReturnCode.CorruptFile;
                }
                else if (type == typeof(IOException))
                {
                    errorMessage = "An IO exception occured while loading the file! " + exception.Message;

                    // Get the locking processes (if any)
                    var lockingProcesses = FileLockUtility.GetProcessesLockingFile(entry.mappedFilePath);

                    // Log locking processes
                    if (lockingProcesses != null && lockingProcesses.Count > 0)
                    {
                        Debug.LogError("\tThe file appears to be locked by the process(es): " +
                                       string.Join(", ", lockingProcesses.Select(p => p.ProcessName).ToArray()));
                    }

                    returnCode = TagWriterReturnCode.IOEError;
                }
                else
                {
                    errorMessage = "An error occured while loading the file! " + exception.Message;
                    returnCode   = TagWriterReturnCode.OtherError;
                }

                ds.LogError(" -> " + errorMessage);
                entryErrors.TryAdd(entry, errorMessage);
                return(returnCode);
            }

            // Before doing anything, remove any tags that aren't on the disk.
            TagTypes tagLibCreatedTags = file.TagTypes ^ file.TagTypesOnDisk;

            file.RemoveTags(tagLibCreatedTags);

            // Then create a new tag type if needed
            TagLibUtility.CreateTagIfRequired(file, out TagTypes usedTagTypes);

            // Remove the ID3v1 tag if set in the settings at this point
            if (Settings.Current.removeID3v1 && file.TagTypes.HasFlag(TagTypes.Id3v1))
            {
                file.RemoveTags(TagTypes.Id3v1);
            }

            // --- RESUME COPYING OVER FROM HERE ---

            // If we're in remove move
            if (args.removeTags)
            {
                if (!args.skipDateAdded)
                {
                    TagLibUtility.RemoveCustomTag(file, Consts.TAG_DATE_ADDED, ds);
                }
                if (!args.skipLastPlayed)
                {
                    TagLibUtility.RemoveCustomTag(file, Consts.TAG_LAST_PLAYED, ds);
                }
                if (!args.skipPlayCount)
                {
                    TagLibUtility.RemoveCustomTag(file, Consts.TAG_PLAY_COUNT, ds);
                }
                if (!args.skipRating)
                {
                    TagLibUtility.RemoveRating(file, ds);
                }

                entry.wroteTags = false;
            }

            // If we're in writing mode
            else
            {
                // Date Added
                if (!args.skipDateAdded && entry.dateAdded != DateTime.MinValue)
                {
                    // Create LDAP/Windows File Time long
                    long dateAddedWinTime = entry.dateAdded.ToFileTime();

                    if (Settings.Current.fullLogging)
                    {
                        ds.Log(string.Format("\tWriting {0}: {1}\n\t-> Converted to {3} (or {2})", Consts.PLIST_KEY_DATE_ADDED, entry.dateAdded.ToString("o", System.Globalization.CultureInfo.InvariantCulture), entry.dateAdded.ToString(), dateAddedWinTime));
                    }

                    // Write the tag
                    TagLibUtility.WriteCustomTag(file, Consts.TAG_DATE_ADDED, dateAddedWinTime.ToString(), ds);
                }

                // Last Played
                if (!args.skipLastPlayed && entry.lastPlayed != DateTime.MinValue)
                {
                    // Create LDAP/Windows File Time long
                    long lastPlayedWinTime = entry.lastPlayed.ToFileTime();

                    if (Settings.Current.fullLogging)
                    {
                        ds.Log(string.Format("\tWriting {0}: {1}\n\t-> Converted to {3} (or {2})", Consts.PLIST_KEY_LAST_PLAYED, entry.lastPlayed.ToString("o", System.Globalization.CultureInfo.InvariantCulture), entry.lastPlayed.ToString(), lastPlayedWinTime));
                    }

                    // Write the tag
                    TagLibUtility.WriteCustomTag(file, Consts.TAG_LAST_PLAYED, lastPlayedWinTime.ToString(), ds);
                }

                // Play Count
                if (!args.skipPlayCount && entry.playCount > 0)
                {
                    if (Settings.Current.fullLogging)
                    {
                        ds.Log(string.Format("\tWriting {0}: {1}", Consts.PLIST_KEY_PLAY_COUNT, entry.playCount));
                    }

                    // Write the tag
                    TagLibUtility.WriteCustomTag(file, Consts.TAG_PLAY_COUNT, entry.playCount.ToString(), ds);
                }

                // Rating
                if (!args.skipRating && entry.rating != Rating.Unrated)
                {
                    int ratingInStars = (int)entry.rating;

                    if (Settings.Current.fullLogging)
                    {
                        ds.Log(string.Format("\tWriting {0}: {1} ({2} stars)", Consts.PLIST_KEY_RATING, ratingInStars * 20, ratingInStars));
                    }

                    // Write the tag
                    TagLibUtility.WriteRating(file, ratingInStars, ds);
                }

                // Process WAV files (after writing stats, since an ID3v2 tag should exist then)
                if (Settings.Current.writeInfoToWavFiles && file.MimeType == "taglib/wav")
                {
                    // This will compare the file with the entry, and will write any missing info that is present in the entry - but not present in the file. Limited to the following tags: Name, Artist, Album Artist, Album, Genre, Comments, Year, Disc Number, Disc Count, Track Number, Track Count

                    ds.Log("\tWriting WAV info:");

                    // Create an Id3v2 tag if it doesn't already exist.
                    var id3v2tag = (TagLib.Id3v2.Tag)file.GetTag(TagTypes.Id3v2, true);

                    // Create a RIFF INFO tag if it doesn't already exist
                    // foobar2000 seems to require a RIFF INFO chunk with at least one tag to detect the ID3v2 tags
                    var riffInfo = (TagLib.Riff.InfoTag)file.GetTag(TagTypes.RiffInfo, true);

                    // Write track title
                    if (string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.ID3v2_FRAME_TITLE)) &&
                        string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.RIFF_ID_TITLE)) && !string.IsNullOrEmpty(entry.trackTitle))
                    {
                        TagLibUtility.WriteTextTag(id3v2tag, Consts.ID3v2_FRAME_TITLE, entry.trackTitle, ds);
                        //TagLibUtility.WriteTextTag(riffInfo, Consts.RIFF_ID_TITLE, entry.trackTitle, ds);
                    }

                    // Write artist
                    if (string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.ID3v2_FRAME_ARTIST)) &&
                        string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.RIFF_ID_ARTIST)) && !string.IsNullOrEmpty(entry.artist))
                    {
                        TagLibUtility.WriteTextTag(id3v2tag, Consts.ID3v2_FRAME_ARTIST, entry.artist, ds);
                        //TagLibUtility.WriteTextTag(riffInfo, Consts.RIFF_ID_ARTIST, entry.artist, ds);
                    }

                    // Write album artist (ID3v2 only)
                    if (string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.ID3v2_FRAME_ALBUM_ARTIST)) &&
                        string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.RIFF_ID_ALBUM)) && !string.IsNullOrEmpty(entry.albumArtist))
                    {
                        TagLibUtility.WriteTextTag(id3v2tag, Consts.ID3v2_FRAME_ALBUM_ARTIST, entry.albumArtist, ds);
                    }

                    // Write album
                    if (string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.ID3v2_FRAME_ALBUM)) &&
                        string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.RIFF_ID_ALBUM)) && !string.IsNullOrEmpty(entry.album))
                    {
                        TagLibUtility.WriteTextTag(id3v2tag, Consts.ID3v2_FRAME_ALBUM, entry.album);
                        //TagLibUtility.WriteTextTag(riffInfo, Consts.RIFF_ID_ALBUM, entry.album);
                    }

                    // Write genre
                    if (string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.ID3v2_FRAME_GENRE)) &&
                        string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.RIFF_ID_GENRE)) && !string.IsNullOrEmpty(entry.genre))
                    {
                        TagLibUtility.WriteTextTag(id3v2tag, Consts.ID3v2_FRAME_GENRE, entry.genre, ds);
                        //TagLibUtility.WriteTextTag(riffInfo, Consts.RIFF_ID_GENRE, entry.genre, ds);
                    }

                    // Write year
                    if (string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.ID3v2_FRAME_DATE)) &&
                        string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.RIFF_ID_YEAR)) && !string.IsNullOrEmpty(entry.year))
                    {
                        TagLibUtility.WriteTextTag(id3v2tag, Consts.ID3v2_FRAME_DATE, entry.year, ds);
                        //TagLibUtility.WriteTextTag(riffInfo, Consts.RIFF_ID_YEAR, entry.year, ds);
                    }

                    // Write track number
                    if (string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.ID3v2_FRAME_TRACK_NUMBER)) &&
                        string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.RIFF_ID_TRACK_NUMBER)) && entry.trackNumber != null)
                    {
                        TagLibUtility.WriteTextTag(id3v2tag, Consts.ID3v2_FRAME_TRACK_NUMBER, entry.trackNumberDisplay, ds);
                        //TagLibUtility.WriteTextTag(riffInfo, Consts.RIFF_ID_TRACK_NUMBER, entry.trackNumberDisplay, ds);
                    }

                    // Write disc number (ID3v2 only)
                    if (string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.ID3v2_FRAME_DISC_NUMBER)) && entry.discNumber != null)
                    {
                        TagLibUtility.WriteTextTag(id3v2tag, Consts.ID3v2_FRAME_DISC_NUMBER, entry.discNumberDisplay, ds);
                    }

                    // Write comments
                    if (string.IsNullOrEmpty(TagLibUtility.GetCommentsTag(file)) &&
                        string.IsNullOrEmpty(TagLibUtility.GetTextTag(file, Consts.RIFF_ID_COMMENTS)) && !string.IsNullOrEmpty(entry.comments))
                    {
                        TagLibUtility.WriteCommentsTag(file, entry.comments, ds);
                        //TagLibUtility.WriteTextTag(riffInfo, Consts.RIFF_ID_COMMENTS, entry.comments, ds);
                    }
                }

                entry.wroteTags = true;
            }

            // Write the modified tags to the file
            try
            {
                if (Settings.Current.fullLogging)
                {
                    TagTypes newTags = file.TagTypesOnDisk ^ file.TagTypes;

                    ds.Log("\tTags for writing:\t" + file.TagTypes.ToString());
                    ds.Log("\t    New tags:\t\t" + newTags.ToString());
                    ds.Log("\t    Existing tags:\t" + file.TagTypesOnDisk.ToString());
                }

                if (!Settings.Current.dryRun)
                {
                    file.Save();
                }

                // If we're here, it means the TagLib.File was saved correctly

                if (isRetry)
                {
                    ds.LogSuccess("\tReattempt succeeded");
                }
            }
            catch (IOException ioex)
            {
                // If this was a retry...
                if (isRetry)
                {
                    string message = "Could not save file after retry. An exception occurred: " + ioex.Message;
                    ds.LogError("\t" + message);

                    entryErrors.TryAdd(entry, message);
                    return(TagWriterReturnCode.IOEError);
                }
                else
                {
                    ds.LogError("\t-> An IO exception occured while saving tags to the file \"" + entry.fileName + "\"");

                    // Get the locking processes (if any)
                    var lockingProcesses = FileLockUtility.GetProcessesLockingFile(entry.mappedFilePath);

                    // Print the process(es) that are locking the file
                    if (lockingProcesses != null && lockingProcesses.Count > 0)
                    {
                        string message = "The file appears to be locked by the process: " + string.Join(", ", lockingProcesses.Select(p => p.ProcessName).ToArray());
                        ds.LogError("\t" + message);

                        entryErrors.TryAdd(entry, message);
                        return(TagWriterReturnCode.IOEError);
                    }

                    // Otherwise if there is no locking process, this is a known issue in TagLib while using ReadStyle.PictureLazy.
                    // Reattempt, using the default ReadStyle.Average
                    else
                    {
                        ds.LogError("\t-> Reattempting load with different parameters...");
                        isRetry = true;
                        goto Retry;
                    }
                }
            }
            catch (Exception ex)
            {
                string message = "An error occurred while saving tags to \"" + entry.fileName + "\": (" + ex.Message + ")";
                ds.LogError("\t" + message);
                entryErrors.TryAdd(entry, message);
                return(TagWriterReturnCode.OtherError);
            }

            file.Dispose();
            return(TagWriterReturnCode.Success);
        }