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>
30 enum action {LIST, REPLACE, INSERT, ERASE, AUDIO};
31 typedef pair<action,string> actionpair;
32 typedef vector<actionpair> actionqueue;
33 typedef pair<TagLib::String,TagLib::StringList> keyandvalues;
35 keyandvalues toKeyAndValues (const string &rawstring)
39 TagLib::StringList values;
42 for (int ipos=0; ipos < rawstring.length(); ipos++) {
43 if ( rawstring[ipos] == '\\' ) {
44 switch (rawstring[ipos+1]) {
52 tmpss << '\\' << rawstring[ipos+1];
58 if ( rawstring[ipos] == '=' ) {
62 values.append(tmpss.str());
67 tmpss << rawstring[ipos];
73 values.append(tmpss.str());
75 return make_pair(key, values);
78 void action_eraseTag (TagLib::PropertyMap &propmap, const string &key)
83 void action_replaceTag (TagLib::PropertyMap &propmap, const keyandvalues &keyAndValues)
85 propmap.replace(keyAndValues.first, keyAndValues.second);
88 void action_insertTag (TagLib::PropertyMap &propmap, const keyandvalues &keyAndValues)
90 propmap.insert(keyAndValues.first, keyAndValues.second);
93 int action_printTags (const TagLib::FileRef f, TagLib::PropertyMap &propmap)
96 unsigned int longest = 0;
97 for(TagLib::PropertyMap::ConstIterator i = propmap.begin(); i != propmap.end(); ++i) {
98 if (i->first.size() > longest) {
99 longest = i->first.size();
102 cout << " \\_____/ TAGS \\_____ _ _ _" << endl;
103 for(TagLib::PropertyMap::ConstIterator i = propmap.begin(); i != propmap.end(); ++i) {
104 for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
105 cout << i->first << "=" << *j << endl;
114 int action_printAudio (const TagLib::FileRef f)
116 if(f.audioProperties()) {
117 TagLib::AudioProperties *properties = f.audioProperties();
118 int seconds = properties->length() % 60;
119 int minutes = (properties->length() - seconds) / 60;
120 cout << " \\_____/ AUDIO PROPERTIES \\_____ _ _ _" << endl;
121 cout << "BITRATE=" << properties->bitrate() << endl;
122 cout << "SAMPLERATE=" << properties->sampleRate() << endl;
123 cout << "CHANNELS=" << properties->channels() << endl;
124 cout << "LENGTH=" << minutes << ":" << setfill('0') << setw(2) << seconds << endl;
134 "Usage: usetaglib [ACTION]... [FILE]...\n"
135 "Read and edit meta-data of audio formats supported by taglib.\n"
136 "Multiple ACTIONS and FILES may be given in arbitrary order.\n"
138 "-h, --help show help\n"
139 "-H, --longhelp show long help\n"
142 " If multiple actions are specified they are executed in given order.\n"
144 " -l, --list list all tags (implicit if no action given)\n"
145 " -a, --audio show audio properties\n"
146 " -e, --erase=TAGNAME erase tag TAGNAME\n"
147 " -r, --replace=TAGNAME=TAGVAL replace tag TAGNAME with value TAGVAL\n"
148 " -i, --insert=TAGNAME=TAGVAL insert tag TAGNAME with value TAGVAL\n";
151 void printExtraHelp ()
156 " TAGNAME is a media format independent id encoding the type of a tag.\n"
157 " Note that also in --list output, format specific tag ids are translated\n"
158 " to unified TAGNAMES.\n"
160 " Some \"well-known\" tags you might want to use are:\n"
161 " TITLE ALBUM ARTIST ALBUMARTIST SUBTITLE TRACKNUMBER DISCNUMBER DATE\n"
162 " ORIGINALDATE GENRE COMMENT TITLESORT ALBUMSORT ARTISTSORT\n"
163 " ALBUMARTISTSORT COMPOSER LYRICIST CONDUCTOR REMIXER PERFORMER ISRC ASIN\n"
164 " BPM COPYRIGHT ENCODEDBY MOOD COMMENT MEDIA LABEL CATALOGNUMBER BARCODE\n"
167 " TAGVAL has to be either a single string or a list of strings separated\n"
168 " by equal signs (=). If a list is given, multiple tags of type TAGNAME\n"
169 " will be created and set to the respective values given by the list.\n"
170 " Note that equal signs have to be escaped with a leading backslash (\\=),\n"
171 " if they shall not be interpreted as list separators.\n"
174 " usetaglib file.ogg\n"
175 " usetaglib -e ALBUM file.flac\n"
176 " usetaglib -r \"ALBUM=New Album\" -i ARTIST=Horst=Hubert file.mp3\n"
177 " usetaglib -r ARTIST=Horst -l file1.ogg file2.mp3\n"
178 " usetaglib -i \"ALBUMARTIST=Horst und Hubert\" file.ogg\n"
179 " usetaglib --insert=\"ALBUMARTIST=Horst und Hubert\" file.ogg\n"
180 " usetaglib --replace='ARTIST=This Band \\= Great' file.ogg\n";
183 int main(int argc, char *argv[])
186 actionqueue requestedActions;
190 static struct option long_options[] =
192 {"help", no_argument, 0, 'h'},
193 {"longhelp", no_argument, 0, 'H'},
194 {"list", no_argument, 0, 'l'},
195 {"audio", no_argument, 0, 'a'},
196 {"insert", required_argument, 0, 'i'},
197 {"erase", required_argument, 0, 'e'},
198 {"replace", required_argument, 0, 'r'},
202 int option_index = 0;
203 c = getopt_long (argc, argv, "hHlai:e:r:",
204 long_options, &option_index);
212 if (long_options[option_index].flag != 0)
224 requestedActions.push_back( make_pair(LIST, "") );
227 requestedActions.push_back( make_pair(AUDIO, "") );
230 requestedActions.push_back( make_pair(INSERT, optarg) );
233 requestedActions.push_back( make_pair(ERASE, optarg) );
236 requestedActions.push_back( make_pair(REPLACE, optarg) );
245 if ( optind == argc ) {
250 if (requestedActions.size() == 0)
251 requestedActions.push_back( make_pair(LIST, "") );
253 for(int i = optind; i < argc; i++) {
254 cout << " _________________________________________ _ _ _" << endl;
256 cout << " " << argv[i] << endl;
257 cout << "\\_________________________________________ _ _ _" << endl;
259 TagLib::FileRef f(argv[i]);
264 TagLib::PropertyMap propmap = f.file()->properties();
265 bool FCHANGED = false;
267 for (actionqueue::iterator actit = requestedActions.begin(); actit != requestedActions.end(); ++actit) {
268 switch (actit->first) {
270 action_printTags(f, propmap);
273 action_printAudio(f);
276 action_eraseTag(propmap, actit->second);
280 action_replaceTag(propmap, toKeyAndValues(actit->second));
284 action_insertTag(propmap, toKeyAndValues(actit->second));
291 f.file()->setProperties(propmap);