TagLib-Sharp - Retagging files - c#

im about to create a small tool, which recreates all tags on my mp3 files.
Because they are in a mess, i want to remove all tags and recreate them with the correct values.
Doing so ive encountered the problem that im not able to set the tag values.
But the problem is, that im not able to set the tags. I have the following code:
File tagLibFile = File.Create(filePath);
tagLibFile.RemoveTags(TagLib.TagTypes.AllTags);
tagLibFile.Tag.Album = album;
tagLibFile.Tag.AlbumArtists = artists.ToArray();
tagLibFile.Tag.Track = track;
tagLibFile.Tag.Title = title;
tagLibFile.Tag.TitleSort = titleSort;
...
tagLibFile.Save();
The file is read out correctly. Then the tags are removed.
But after that setting the Tag does not work. The strings inside the tag are still null.
I havent seen a method like "tagLibFile.SetTag(Tag t)". The Tag is only available as a getter, but not a setter.
After that ive added some Frames, but that doesent have the effect of setting the tags. Maybe im using it the wrong way?
Hope you can help me out of this!
Kind regards,
SyLuS

I'm guessing that after removing tags, TagLib# (or TagLib, for that matter) does not create a new tag to hold information. However, when opening a file, it possibly does some checking and if the file doesn't have one, it creates a new tag.
Hence, as a workaround, you could save the file once after removing the tags, and then proceed to add new tag information.
File tagLibFile = File.Create(filePath);
tagLibFile.RemoveTags(TagLib.TagTypes.AllTags);
// Save the file once, so that Taglib Sharp takes care of creating any necessary tags when opening the file next time and dispose the file reference:
tagLibFile.Save();
tagLibFile.Dispose();
You can then proceed to editing the tags as you're already doing after opening the file again:
tagLibFile = File.Create(filePath);
tagLibFile.Tag.Album = album;
tagLibFile.Tag.AlbumArtists = artists.ToArray();
tagLibFile.Tag.Track = track;
tagLibFile.Tag.Title = title;
tagLibFile.Tag.TitleSort = titleSort;
// ...
Remember to save the file again, after you're done editing tags:
tagLibFile.Save();
I hope this helps. If you have any further questions, or the above code doesn't work still, feel free to comment. :)

Related

Change default application for .txt

After a lot of searching on the internet without any success, I'm looking here for some help.
The problem seems to be quiet simple, but unfortunately I'm not able to solve it.
I want to change the default-application to open .txt-files. For example instead of using notepad I want to use Wordpad which is located at C:\Program Files\Windows NT\Accessories\wordpad.exe
So I've tried to change the registry at: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.txt\OpenWithProgids with no success.
I've also found a solution which tries to change the group policy. This code looks like:
string tempFile = Path.GetTempFileName();
string xmlFile = tempFile.Replace(".tmp", ".xml");
File.Move(tempFile, xmlFile);
XDocument document = new XDocument(new XElement("DefaultAssociations",
new XElement("Association",
new XAttribute("Identifier", ".txt"),
new XAttribute("ProgId", "txtFile"),
new XAttribute("ApplicationName", "Editor"))));
document.Save(xmlFile);
ComputerGroupPolicyObject.SetPolicySetting(#"HKLM\Software\Policies\Microsoft\Windows\System!DefaultAssociationsConfiguration",
xmlFile, RegistryValueKind.String);
But this also doesn't work.
I also tried to use the command-line with ftype but that also didn't work.
Can anybody tell me how to change the assoziated application for a given filetype?
I guess you want to this because you have some kind of Set as default option in your program, by the way I have spent the last hour trying to figure out why it doesn't work and here it is what I've found so far.
The step you need to take are the following:
Creates a registry key in ClassesRoot for the .custom extension.
(Period is important)
Code:
Registry.ClassesRoot.CreateSubKey(".custom").SetValue("", "customfile", Microsoft.Win32.RegistryValueKind.String);`
Creating the "Customfile" sub-key and the "customfile\open\command"
subkey that is needed to store the path to the application that will
open this file type.
Code:
Registry.ClassesRoot.CreateSubKey("Customfile\shell\open\command").SetValue("", PATH_TO_YOUR_EXE, Microsoft.Win32.RegistryValueKind.String);
And now the association has been made, your app will be registered as one of those which can open that extention.
The case of .txt (or other already associated extentions)
After messing a little bit around i found out that in order to do changes to an already associated extention you also need to edit the registry
Example (with .txt ext.)
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\FileExts\.txt\UserChoice
This key has an ProgId value which actually contains the default application set by the user, the value is a string. So you will also have do edit/delete this Registry as well.
I hope it helps :)!

Listing extended tags in files with Tagliib

I am working with .flac audio files that use extended tags for a bit of magic. There is a tag called ReleaseGuid. I want to be able to list the contents or create the tag if it doesn't exist. I have done the prerequisite beating of my head against the wall for three days now. I have found a way to add a usertextinformation frame...although I don't see the value just the Owner. Please help me figure this out.
The following are lines of code that at least compile and seem to do something.
I need to get this to the point where I can add the needed tag.
File objFile = TagLib.File.Create(path);
TagLib.Id3v2.Tag id3v2tag = (TagLib.Id3v2.Tag)objFile.GetTag TagLib.TagTypes.Id3v2, true);
if (id3v2tag != null)
{
// Get the private frame, create if necessary.
PrivateFrame frame = PrivateFrame.Get(id3v2tag, "Mytag", true);
frame.PrivateData = System.Text.Encoding.Unicode.GetBytes "MyInfo");
id3v2tag.AddFrame(frame);
}
I have used mp3tag to see the tags I am needing by clicking on "extended tags".
Which type of tags would these be if I can add them using mp3tag? How do I read/write them using taglib?
To search for the tag type, you can open the (.flac) audio file in a texteditor like Notepad++ and search for your 'ReleaseGuid'. In front of this ID you will see the type like TXXX or PRIV or COMM.
Or you can have a look into the documentation (source code?) of the program who writes this 'ReleaseGuid' in your audio files.

Set BaseUrl of an existing Pdf Document

We're having trouble setting a BaseUrl using iTextSharp. We have used Adobes Implementation for this in the past, but we got some severe performance issues. So we switched to iTextSharp, which is aprox 10 times faster.
Adobe enabled us to set a base url for each document. We really need this in order to deploy our documents on different servers. But we cant seem to find the right code to do this.
This code is what we used with Adobe:
public bool SetBaseUrl(object jso, string baseUrl)
{
try
{
object result = jso.GetType().InvokeMember("baseURL", BindingFlags.SetProperty, null, jso, new Object[] {baseUrl });
return result != null;
}
catch
{
return false;
}
}
A lot of solutions describe how you can insert links in new or empty documents. But our documents already exist and do contain more than just text. We want to overlay specific words with a link that leads to one or more other documents. Therefore, its really important to us that we can insert a link without accessing the text itself. Maybe lay a box ontop of these words and set its position (since we know where the words are located in the document)
We have tried different implementations, using the setAction method, but it doesnt seem to work properly. The result was in most cases, that we saw out box, but there was no link inside or associated with it. (the cursor didn't change and nothing happend, when i clicked inside the box)
Any help is appreciated.
I've made you a couple of examples.
First, let's take a look at BaseURL1. In your comment, you referred to JavaScript, so I created a document to which I added a snippet of document-level JavaScript:
writer.addJavaScript("this.baseURL = \"http://itextpdf.com/\";");
This works perfectly in Adobe Acrobat, but when you try this in Adobe Reader, you get the following error:
NotAllowedError: Security settings prevent access to this property or
method. Doc.baseURL:1:Document-Level:0000000000000000
This is consistent with the JavaScript reference for Acrobat where it is clearly indicated that special permissions are needed to change the base URL.
So instead of following your suggested path, I consulted ISO-32000-1 (which was what I asked you to do, but... I've beaten you in speed).
I discovered that you can add a URI dictionary to the catalog with a Base entry. So I wrote a second example, BaseURL2, where I add this dictionary to the root dictionary of the PDF:
PdfDictionary uri = new PdfDictionary(PdfName.URI);
uri.put(new PdfName("Base"), new PdfString("http://itextpdf.com/"));
writer.getExtraCatalog().put(PdfName.URI, uri);
Now the BaseURL works in both Acrobat and Reader.
Assuming that you want to add a BaseURL to existing documents, I wrote BaseURL3. In this example, we add the same dictionary to the root dictionary of an existing PDF:
PdfReader reader = new PdfReader(src);
PdfDictionary uri = new PdfDictionary(PdfName.URI);
uri.put(new PdfName("Base"), new PdfString("http://itextpdf.com/"));
reader.getCatalog().put(PdfName.URI, uri);
PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(dest));
stamper.close();
Using this code, you can change a link that points to "index.php" (base_url.pdf) into a link that points to "http://itextpdf.com/index.php" (base_url_3.pdf).
Now you can replace your Adobe license with a less expensive iTextSharp license ;-)

Inserting word content into a VSTO document level customization

I have a VSTO document level customization that performs specific functionality when opened from within our application. Basically, we open normal documents from inside of our application and I copy the content from the normal docx file into the VSTO document file which is stored inside of our database.
var app = new Microsoft.Office.Interop.Word.Application();
var docs = app.Documents;
var vstoDoc = docs.Open(vstoDocPath);
var doc = docs.Open(currentDocPath);
doc.Range().Copy();
vstoDoc.Range().PasteAndFormat(WdRecoveryType.wdFormatOriginalFormatting);
Everything works great, however using the above code leaves out certain formatting related to the document. The code below fixes these issues, but there will most likely be more issues that I come across, as I come across them I could address them one by one ...
for (int i = 0; i < doc.Sections.Count; i++)
{
var footerFont = doc.Sections[i + 1].Footers.GetEnumerator();
var headerFont = doc.Sections[i + 1].Headers.GetEnumerator();
var footNoteFont = doc.Footnotes.GetEnumerator();
foreach (HeaderFooter foot in vstoDoc.Sections[i + 1].Footers)
{
footerFont.MoveNext();
foot.Range.Font.Name = ((HeaderFooter)footerFont.Current).Range.Font.Name;
}
foreach (HeaderFooter head in vstoDoc.Sections[i + 1].Headers)
{
headerFont.MoveNext();
head.Range.Font.Name = ((HeaderFooter)headerFont.Current).Range.Font.Name;
}
foreach (Footnote footNote in vstoDoc.Footnotes)
{
footNoteFont.MoveNext();
footNote.Range.Font.Name = ((Footnote)footNoteFont.Current).Range.Font.Name;
}
}
I need a fool proof safe way of copying the content of one docx file to another docx file while preserving formatting and eliminating the risk of corrupting the document. I've tried to use reflection to set the properties of the two documents to one another, the code does start to look a bit ugly and I always worry that certain properties that I'm setting may have undesirable side effects. I've also tried zipping and unzipping the docx files, editing the xml manually and then rezipping afterwards, this hasn't worked too well, I've ended up corrupting a few of the documents during this process.
If anyone has dealt with a similar issue in the past, please could you point me in the right direction.
Thank you for your time
This code copies and keeps source formatting.
bookmark.Range.Copy();
Document newDocument = WordInstance.Documents.Add();
newDocument.Activate();
newDocument.Application.CommandBars.ExecuteMso("PasteSourceFormatting");
There is one more elegant way to manage it based upon
Globals.ThisAddIn.Application.ActiveDocument.Range().ImportFragment(filePath);
or you can do the following
Globals.ThisAddIn.Application.Selection.Range.ImportFragment(filePath);
in order to obtain current range where filePath is a path to the document you are copping from.

How to read file in C# from POST data from web

Basically, I'm building a website that allows user to upload file.
From the front end (JavaScript), the user will browse a file, I can get the site to send POST data (the parameter "UploadInput" and it's value, which the value is the file)
In the backend (C#), I want to make a copy of the file and save it in a specific path.
Below is the way I did it.
var files = Request.Files;
file[0].SaveAs("\temp\\" + file[0].FileName);
The problem I ran into is that I got the error message saying index out of range. I tried Response.Write(files.Count) and it gives me 0 instead of 1.
I'm wondering where I did wrong and how to fix it, or if there's a better way of doing it.
Thanks!
Edit:
I am using HttpFox to debug. From HttpFox, I can see that under POST data, parameter is "UploadInput" and the value is "test.txt"
Edit 2:
So I tried the way Marc provides, and I have a different problem.
I am able to create a new file, however, the content is not copied over. I tried opening the new created file in notepad and all it says is "UploadInput = test.txt"
If they simply posted the file as the body content, then there will be zero "files" involved here, so file[0] will fail. Instead, you need to look at the input-stream, and simply read from that stream. For example:
using(var file = File.Create(somePath)) {
Request.InputStream.CopyTo(file);
}

Categories