// Scans the file for ogg rating/playcount tags as defined by the Quod Libet standard // All applicable tags are overwritten with the new values, regardless of tag author public static void StoreRatingAndPlayCount(int rating, int playcount, TagLib.File to_file) { TagLib.Ogg.XiphComment xiphtag = GetTag(to_file); if (xiphtag == null) { return; } ArrayList rating_fieldnames = new ArrayList(); ArrayList playcount_fieldnames = new ArrayList(); // Collect list of rating and playcount tags to be updated: foreach (string fieldname in xiphtag) { if (fieldname.ToUpper().StartsWith(rating_prefix)) { rating_fieldnames.Add(fieldname); } else if (fieldname.ToUpper().StartsWith(playcount_prefix)) { playcount_fieldnames.Add(fieldname); } } // Add "BANSHEE" tags if no rating/playcount tags were found: if (rating_fieldnames.Count == 0) { rating_fieldnames.Add(rating_prefix + ogg_our_creator_name); } if (playcount_fieldnames.Count == 0) { playcount_fieldnames.Add(playcount_prefix + ogg_our_creator_name); } string ogg_rating = BansheeToOgg(rating); foreach (string ratingname in rating_fieldnames) { xiphtag.SetField(ratingname, ogg_rating); Hyena.Log.DebugFormat("Exporting Ogg Rating={0}({1}) to File \"{2}\" as Creator \"{3}\"", rating, ogg_rating, to_file.Name, ratingname.Substring(rating_prefix.Length)); } string ogg_playcount = playcount.ToString(); foreach (string playcountname in playcount_fieldnames) { xiphtag.SetField(playcountname, ogg_playcount); Hyena.Log.DebugFormat("Exporting Ogg Playcount={0}({1}) to File \"{2}\" as Creator \"{3}\"", playcount, ogg_playcount, to_file.Name, playcountname.Substring(playcount_prefix.Length)); } }
public static bool UpdateTags(TagLib.File fileInfo, NameValueCollection tags, CUEToolsCodecsConfig config, bool useId3v24) { if (fileInfo is TagLib.Riff.File) { return(false); } TagLib.Ogg.XiphComment xiph = (TagLib.Ogg.XiphComment)fileInfo.GetTag(TagLib.TagTypes.Xiph); if (xiph != null) { foreach (string tag in tags.AllKeys) { xiph.SetField(tag, tags.GetValues(tag)); } return(true); } if (fileInfo is TagLib.Mpeg4.File) { var mpeg4 = (TagLib.Mpeg4.AppleTag)fileInfo.GetTag(TagLib.TagTypes.Apple, true); foreach (string tag in tags.AllKeys) { mpeg4.SetDashBox("com.apple.iTunes", tag, string.Join(";", tags.GetValues(tag))); } return(true); } if (fileInfo is TagLib.Mpeg.AudioFile || (fileInfo is TagLib.UserDefined.File && (fileInfo as TagLib.UserDefined.File).Tagger == CUEToolsTagger.ID3v2)) { var id3v2 = (TagLib.Id3v2.Tag)fileInfo.GetTag(TagLib.TagTypes.Id3v2, true); id3v2.Version = (byte)(useId3v24 ? 4 : 3); foreach (string tag in tags.AllKeys) { var frame = TagLib.Id3v2.UserTextInformationFrame.Get(id3v2, tag, true); frame.Text = tags.GetValues(tag); } return(true); } if (fileInfo is TagLib.Asf.File) { var asf = (TagLib.Asf.Tag)fileInfo.GetTag(TagLib.TagTypes.Asf, true); foreach (string tag in tags.AllKeys) { asf.SetDescriptorStrings(tags.GetValues(tag), "foobar2000/" + tag); } return(true); } TagLib.Ape.Tag ape = (TagLib.Ape.Tag)fileInfo.GetTag(TagLib.TagTypes.Ape, true); if (ape != null) { foreach (string tag in tags.AllKeys) { ape.SetValue(tag, tags.GetValues(tag)); } } return(true); }
/// <summary> /// Write a single Xiph tag to the file /// This will overwrite the tag if it already exists, or create it if it doesn't /// It will also create the Xiph tag block within the file if it doesn't already have one /// This function writes to disk. If setting multiple tags consider using SetTags(OggTag[] Tags) to reduce the number of write operations /// If setting an array, Tag.Values must contain at least one item. Tag.Value is ignored in this case /// If setting a single value, Tag.Value must contain at least one character. Tag.Values is ignored in this case /// </summary> /// <param name="Tag"> /// The <see cref="OggTag"/> to write /// </param> /// <returns> /// An <see cref="OggTagWriteCommandReturn"/> indicating the result of the operation /// </returns> public OggTagWriteCommandReturn SetTag(OggTag Tag) { // Validate Tag if (Tag.IsEmpty) { return(OggTagWriteCommandReturn.InvalidValue); } if (Tag.Name.Length <= 0) { return(OggTagWriteCommandReturn.UnknownTag); } if (Tag.IsArray) { if (Tag.Values.Length <= 0) { return(OggTagWriteCommandReturn.InvalidValue); } } else { if (Tag.Value.Length <= 0) { return(OggTagWriteCommandReturn.InvalidValue); } } // Tag valid, try and write it TagLib.Ogg.XiphComment XC = (TagLib.Ogg.XiphComment)m_TagLibFile.GetTag(TagTypes.Xiph, true); if (XC != null) { string[] tmpStrArray; if (Tag.IsArray) { tmpStrArray = Tag.Values; } else { tmpStrArray = new string[1]; tmpStrArray[0] = Tag.Value; } // Set field XC.SetField(Tag.Name, tmpStrArray); // Copy the XC instance into our file (not sure if this is needed) XC.CopyTo(m_TagLibFile.Tag, true); // Commit m_TagLibFile.Save(); return(OggTagWriteCommandReturn.Success); } else { // If we're null something went wrong (we tried to create the XiphComment block and it failed probably) return(OggTagWriteCommandReturn.Error); } }
/// <summary> /// Write multiple Xiph tags to the file /// This will overwrite any existing tags, and create them if they don't exist /// It will also create the Xiph tag block within the file if it doesn't already have one /// This function writes to disk. If setting only a single tag, consider using SetTag(OggTag Tag) to reduce the array handling overheads /// If setting an array value Tags[i].Values must contain at least one item. Tags[i].Value is ignored in this case /// If setting a single value, Tags[i].Value must contain at least one character. Tags[i].Values is ignored in this case /// If AbortOnError is true, this function will abort (and not write) if any item in the Tags array is invalid. /// If AbortOnError is false, this function will continue (and write) if items in the Tags array are invalid. It will still abort (and not write) if there are other errors. /// </summary> /// <param name="Tags"> /// An <see cref="OggTag[]"/> containing the tags to be written /// </param> /// <param name="AbortOnError"> /// A <see cref="System.bool"/> indicating whether to invalid items in the Tags array. /// <returns> /// An <see cref="OggTagWriteCommandReturn"/> indicating the result of the operation /// </returns> public OggTagWriteCommandReturn SetTags(OggTag[] Tags, bool AbortOnError) { // Check that the Tags array has at least one item in it if (Tags.Length < 1) { return(OggTagWriteCommandReturn.UnknownTag); } TagLib.Ogg.XiphComment XC = (TagLib.Ogg.XiphComment)m_TagLibFile.GetTag(TagTypes.Xiph, true); if (XC != null) { // Write the tags to the 'virtual' file foreach (OggTag Tag in Tags) { // Validate tag if (Tag.IsEmpty) { if (AbortOnError) { return(OggTagWriteCommandReturn.InvalidValue); } else { continue; } } if (Tag.Name.Length <= 0) { if (AbortOnError) { return(OggTagWriteCommandReturn.UnknownTag); } else { continue; } } if (Tag.IsArray) { if (Tag.Values.Length <= 0) { if (AbortOnError) { return(OggTagWriteCommandReturn.InvalidValue); } else { continue; } } } else { if (Tag.Value.Length <= 0) { if (AbortOnError) { return(OggTagWriteCommandReturn.InvalidValue); } else { continue; } } } string[] tmpStrArray; if (Tag.IsArray) { tmpStrArray = Tag.Values; } else { tmpStrArray = new string[1]; tmpStrArray[0] = Tag.Value; } // Write tag XC.SetField(Tag.Name, tmpStrArray); } // Copy the XC instance into our file (not sure if this is needed) XC.CopyTo(m_TagLibFile.Tag, true); // Save to disk m_TagLibFile.Save(); return(OggTagWriteCommandReturn.Success); } else { // If we're null something went wrong (we tried to create the XiphComment block and it failed probably) return(OggTagWriteCommandReturn.Error); } }
public void TestPictures() { var tag = new XiphComment(); Picture[] pictures = { new Picture(TestPath.Covers + "sample_a.png"), new Picture(TestPath.Covers + "sample_a.jpg"), new Picture(TestPath.Covers + "sample_b.png"), new Picture(TestPath.Covers + "sample_b.jpg"), new Picture(TestPath.Covers + "sample_c.png"), new Picture(TestPath.Covers + "sample_c.jpg") }; for (int i = 0; i < 6; i++) { pictures[i].Type = (PictureType)(i * 2); } pictures[3].Description = val_sing; TagTestWithSave(ref tag, delegate(XiphComment t, string m) { Assert.IsTrue(t.IsEmpty, "Initial (IsEmpty): " + m); Assert.AreEqual(0, t.Pictures.Length, "Initial (Zero): " + m); }); tag.Pictures = pictures; TagTestWithSave(ref tag, delegate(XiphComment t, string m) { Assert.IsTrue(!t.IsEmpty, "Value Set (IsEmpty): " + m); }); tag.Pictures = new Picture[0]; TagTestWithSave(ref tag, delegate(XiphComment t, string m) { Assert.IsTrue(t.IsEmpty, "Value Cleared (IsEmpty): " + m); Assert.AreEqual(0, t.Pictures.Length, "Value Cleared (Zero): " + m); }); // Test that COVERART fields are parsed in Pictures property string[] pictureStrings = new string[pictures.Length]; for (int i = 0; i < 6; ++i) { pictureStrings[i] = Convert.ToBase64String(pictures[i].Data.Data); } tag.SetField("COVERART", pictureStrings); var parsedPictures = tag.Pictures; Assert.IsTrue(!tag.IsEmpty, "Legacy Value Set (IsEmpty)"); Assert.AreEqual(6, parsedPictures.Length, "Legacy Value Set (Length)"); TagTestWithSave(ref tag, delegate(XiphComment t, string m) { // COVERART should be preserved Assert.AreEqual(6, t.GetField("COVERART").Length, "Legacy Field Set (Length): " + m); }); // Setting the pictures array should replace COVERART with METADATA_BLOCK_PICTURE tag.Pictures = pictures; TagTestWithSave(ref tag, delegate(XiphComment t, string m) { Assert.AreEqual(0, t.GetField("COVERART").Length, "Legacy Field Set (Length): " + m); Assert.AreEqual(6, t.GetField("METADATA_BLOCK_PICTURE").Length, "Current Field Set (Length): " + m); }); // The user should be able to clear the pictures array tag.Pictures = null; TagTestWithSave(ref tag, delegate(XiphComment t, string m) { Assert.AreEqual(0, t.Pictures.Length, "Pictures Length (null): " + m); }); }