1 /* Copyright (C) 2015 Alexander Schmidt <alex@treefish.org>
3 * This program is free software: you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation, either version 3 of the License, or
6 * (at your option) any later version.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 #include <taglib/fileref.h>
21 #include <taglib/tag.h>
22 #include <taglib/tpropertymap.h>
23 #include <taglib/tstringlist.h>
29 enum action {LIST, REPLACE, INSERT, ERASE, AUDIO};
30 typedef pair<action,string> actionpair;
31 typedef vector<actionpair> actionqueue;
32 typedef pair<string,string> tagpair;
34 TagLib::StringList argToStringList (const string &rawtagarg)
36 TagLib::StringList newlist;
40 size_t nextdelpos = rawtagarg.find('=', delpos+1);
43 newlist.append(rawtagarg.substr(delpos,nextdelpos-delpos));
44 delpos = nextdelpos+1;
46 newlist.append(rawtagarg.substr(delpos,string::npos));
51 tagpair splitToTagPair (const string &rawarg)
53 const size_t delpos = rawarg.find('=');
54 return make_pair(rawarg.substr(0, delpos), rawarg.substr(delpos+1, string::npos));
57 void action_eraseTag (TagLib::PropertyMap &propmap, const string &key)
62 void action_replaceTag (TagLib::PropertyMap &propmap, const tagpair &tagPair)
64 propmap.replace(tagPair.first, argToStringList(tagPair.second));
67 void action_insertTag (TagLib::PropertyMap &propmap, const tagpair &tagPair)
69 propmap.insert(tagPair.first, argToStringList(tagPair.second));
72 int action_printTags (const TagLib::FileRef f, TagLib::PropertyMap &propmap)
75 unsigned int longest = 0;
76 for(TagLib::PropertyMap::ConstIterator i = propmap.begin(); i != propmap.end(); ++i) {
77 if (i->first.size() > longest) {
78 longest = i->first.size();
81 cout << "-- TAG (properties) --" << endl;
82 for(TagLib::PropertyMap::ConstIterator i = propmap.begin(); i != propmap.end(); ++i) {
83 for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
84 cout << i->first << "=" << *j << endl;
93 int action_printAudio (const TagLib::FileRef f)
95 if(f.audioProperties()) {
96 TagLib::AudioProperties *properties = f.audioProperties();
97 int seconds = properties->length() % 60;
98 int minutes = (properties->length() - seconds) / 60;
99 cout << "-- AUDIO --" << endl;
100 cout << "BITRATE=" << properties->bitrate() << endl;
101 cout << "SAMPLERATE=" << properties->sampleRate() << endl;
102 cout << "CHANNELS=" << properties->channels() << endl;
103 cout << "LENGTH=" << minutes << ":" << setfill('0') << setw(2) << seconds << endl;
112 cout << "Usage: usetaglib [ACTION]... [FILE]..." << endl;
113 cout << "Read and edit meta-data of audio formats supported by taglib." << endl;
115 cout << "-h, --help Show this help" << endl;
117 cout << "ACTIONS" << endl;
118 cout << " If multiple actions are specified they are executed in given order." << endl;
120 cout << setfill(' ') << setw(37) << left << " -l, --list"
121 << "list all tags (implicit if no action specified)"<< endl;
122 cout << setfill(' ') << setw(37) << left << " -a, --listaudio"
123 << "show audio information"<< endl;
124 cout << setfill(' ') << setw(37) << left << " -e, --erase=TAGNAME"
125 << "erase tag TAGNAME"<< endl;
126 cout << setfill(' ') << setw(37) << left << " -r, --replace=TAGNAME=TAGVALSPEC"
127 << "replace tag TAGNAME with value TAGVALSPEC"<< endl;
128 cout << setfill(' ') << setw(37) << left << " -i, --insert=TAGNAME=TAGVALSPEC"
129 << "insert value TAGVALSPEC for tag TAGNAME"<< endl;
131 cout << "TAGVALSPEC" << endl;
132 cout << " a list of values separated by '=': val1=val2=val3..." << endl;
134 cout << "EXAMPLES" << endl;
135 cout << " usetaglib file.ogg" << endl;
136 cout << " usetaglib -e ALBUM file.flac" << endl;
137 cout << " usetaglib -r \"ALBUM=New Album\" -i ARTIST=Horst=Hubert file.mp3" << endl;
138 cout << " usetaglib -r ARTIST=Horst -l file1.ogg file2.mp3" << endl;
139 cout << " usetaglib -i \"ALBUMARTIST=Horst und Hubert\" file.ogg" << endl;
140 cout << " usetaglib --insert=\"ALBUMARTIST=Horst und Hubert\" file.ogg" << endl;
143 int main(int argc, char *argv[])
146 actionqueue requestedActions;
150 static struct option long_options[] =
152 {"help", no_argument, 0, 'h'},
153 {"list", no_argument, 0, 'l'},
154 {"listaudio", no_argument, 0, 'a'},
155 {"insert", required_argument, 0, 'i'},
156 {"erase", required_argument, 0, 'e'},
157 {"replace", required_argument, 0, 'r'},
161 int option_index = 0;
162 c = getopt_long (argc, argv, "hlai:e:r:",
163 long_options, &option_index);
171 if (long_options[option_index].flag != 0)
180 requestedActions.push_back( make_pair(LIST, "") );
184 requestedActions.push_back( make_pair(AUDIO, "") );
188 requestedActions.push_back( make_pair(INSERT, optarg) );
192 requestedActions.push_back( make_pair(ERASE, optarg) );
196 requestedActions.push_back( make_pair(REPLACE, optarg) );
207 if ( optind == argc ) {
212 if (requestedActions.size() == 0)
213 requestedActions.push_back( make_pair(LIST, "") );
215 for(int i = optind; i < argc; i++) {
216 cout << "******************** \"" << argv[i] << "\" ********************" << endl;
217 TagLib::FileRef f(argv[i]);
222 TagLib::PropertyMap propmap = f.file()->properties();
223 bool FCHANGED = false;
225 for (actionqueue::iterator actit = requestedActions.begin(); actit != requestedActions.end(); ++actit) {
226 switch (actit->first) {
228 action_printTags(f, propmap);
232 action_printAudio(f);
236 action_eraseTag(propmap, actit->second);
241 action_replaceTag(propmap, splitToTagPair(actit->second));
246 action_insertTag(propmap, splitToTagPair(actit->second));
253 f.file()->setProperties(propmap);