--- /dev/null
+/*
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <iostream>
+#include <iomanip>
+#include <iostream>
+#include <taglib/fileref.h>
+#include <taglib/tag.h>
+#include <taglib/tpropertymap.h>
+#include <taglib/tstringlist.h>
+#include <getopt.h>
+#include <vector>
+
+using namespace std;
+
+enum action {LIST, REPLACE, INSERT, ERASE, AUDIO};
+typedef pair<action,string> actionpair;
+typedef vector<actionpair> actionqueue;
+typedef pair<string,string> tagpair;
+
+TagLib::StringList argToStringList (const string &rawtagarg)
+{
+ TagLib::StringList newlist;
+
+ size_t delpos = 0;
+ while (1) {
+ size_t nextdelpos = rawtagarg.find('=', delpos+1);
+ if (nextdelpos == -1)
+ break;
+ newlist.append(rawtagarg.substr(delpos,nextdelpos-delpos));
+ delpos = nextdelpos+1;
+ }
+ newlist.append(rawtagarg.substr(delpos,string::npos));
+
+ return newlist;
+}
+
+tagpair splitToTagPair (const string &rawarg)
+{
+ const size_t delpos = rawarg.find('=');
+ return make_pair(rawarg.substr(0, delpos), rawarg.substr(delpos+1, string::npos));
+}
+
+void action_eraseTag (const TagLib::FileRef f, const string &key)
+{
+ TagLib::PropertyMap propmap = f.file()->properties();
+ propmap.erase(key);
+ f.file()->setProperties(propmap);
+}
+
+void action_replaceTag (const TagLib::FileRef f, const tagpair &tagPair)
+{
+ TagLib::PropertyMap propmap = f.file()->properties();
+ propmap.replace(tagPair.first, argToStringList(tagPair.second));
+ f.file()->setProperties(propmap);
+}
+
+void action_insertTag (const TagLib::FileRef f, const tagpair &tagPair)
+{
+ TagLib::PropertyMap propmap = f.file()->properties();
+ propmap.insert(tagPair.first, argToStringList(tagPair.second));
+ f.file()->setProperties(propmap);
+}
+
+int action_printTags (const TagLib::FileRef f)
+{
+ if(f.tag()) {
+ TagLib::PropertyMap tags = f.file()->properties();
+ unsigned int longest = 0;
+ for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
+ if (i->first.size() > longest) {
+ longest = i->first.size();
+ }
+ }
+ cout << "-- TAG (properties) --" << endl;
+ for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
+ for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
+ cout << i->first << "=" << *j << endl;
+ }
+ }
+ return 0;
+ }
+ else
+ return 1;
+}
+
+int action_printAudio (const TagLib::FileRef f)
+{
+ if(f.audioProperties()) {
+ TagLib::AudioProperties *properties = f.audioProperties();
+ int seconds = properties->length() % 60;
+ int minutes = (properties->length() - seconds) / 60;
+ cout << "-- AUDIO --" << endl;
+ cout << "BITRATE=" << properties->bitrate() << endl;
+ cout << "SAMPLERATE=" << properties->sampleRate() << endl;
+ cout << "CHANNELS=" << properties->channels() << endl;
+ cout << "LENGTH=" << minutes << ":" << setfill('0') << setw(2) << seconds << endl;
+ return 0;
+ }
+ else
+ return 1;
+}
+
+void printHelp ()
+{
+ cout << "Usage: usetaglib [ACTION]... [FILE]..." << endl;
+ cout << "List and edit tags on mediafiles in formats supported by libtag." << endl;
+ cout << endl;
+ cout << "-h, --help Show this help" << endl;
+ cout << endl;
+ cout << "ACTIONS" << endl;
+ cout << setfill(' ') << setw(45) << left << " -l, --list"
+ << "list all tags (implicit if no action specified)"<< endl;
+ cout << setfill(' ') << setw(45) << left << " -e, --erase=TAGNAME"
+ << "erase tag with name TAGNAME"<< endl;
+ cout << setfill(' ') << setw(45) << left << " -r, --replace=TAGNAME=TAGVAL[=TAGVAL...]"
+ << "replace tag TAGNAME with list of values TAGVAL"<< endl;
+ cout << setfill(' ') << setw(45) << left << " -i, --insert=TAGNAME=TAGVAL[=TAGVAL...]"
+ << "insert list of values TAGVAL for tag TAGNAME"<< endl;
+}
+
+int main(int argc, char *argv[])
+{
+ int c;
+ actionqueue requestedActions;
+
+ while (1)
+ {
+ static struct option long_options[] =
+ {
+ {"help", no_argument, 0, 'h'},
+ {"list", no_argument, 0, 'l'},
+ {"listaudio", no_argument, 0, 'a'},
+ {"insert", required_argument, 0, 'i'},
+ {"erase", required_argument, 0, 'e'},
+ {"replace", required_argument, 0, 'r'},
+ {0, 0, 0, 0}
+ };
+
+ int option_index = 0;
+ c = getopt_long (argc, argv, "hlai:e:r:",
+ long_options, &option_index);
+
+ if (c == -1)
+ break;
+
+ switch (c)
+ {
+ case 0:
+ if (long_options[option_index].flag != 0)
+ break;
+
+ case 'h':
+ printHelp();
+ return 0;
+ break;
+
+ case 'l':
+ requestedActions.push_back( make_pair(LIST, "") );
+ break;
+
+ case 'a':
+ requestedActions.push_back( make_pair(AUDIO, "") );
+ break;
+
+ case 'i':
+ requestedActions.push_back( make_pair(INSERT, optarg) );
+ break;
+
+ case 'e':
+ requestedActions.push_back( make_pair(ERASE, optarg) );
+ break;
+
+ case 'r':
+ requestedActions.push_back( make_pair(REPLACE, optarg) );
+ break;
+
+ case '?':
+ break;
+
+ default:
+ abort ();
+ }
+ }
+
+ if (requestedActions.size() == 0)
+ requestedActions.push_back( make_pair(LIST, "") );
+
+ for(int i = optind; i < argc; i++) {
+ cout << "******************** \"" << argv[i] << "\" ********************" << endl;
+ TagLib::FileRef f(argv[i]);
+
+ if(f.isNull())
+ continue;
+
+ for (actionqueue::iterator actit = requestedActions.begin(); actit != requestedActions.end(); ++actit) {
+ switch (actit->first) {
+ case LIST:
+ action_printTags(f);
+ break;
+
+ case AUDIO:
+ action_printAudio(f);
+ break;
+
+ case ERASE:
+ action_eraseTag(f, actit->second);
+ break;
+
+ case REPLACE:
+ action_replaceTag(f, splitToTagPair(actit->second));
+ break;
+
+ case INSERT:
+ action_insertTag(f, splitToTagPair(actit->second));
+ break;
+ }
+ }
+
+ f.file()->save();
+ }
+
+ return 0;
+}