]> git.treefish.org Git - usetaglib.git/blob - usetaglib.cpp
a616a2ee98fb09da30cfe402cc810a0ed11ee94b
[usetaglib.git] / usetaglib.cpp
1 /*
2   This program is free software: you can redistribute it and/or modify
3   it under the terms of the GNU General Public License as published by
4   the Free Software Foundation, either version 3 of the License, or
5   (at your option) any later version.
6   
7   This program is distributed in the hope that it will be useful,
8   but WITHOUT ANY WARRANTY; without even the implied warranty of
9   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10   GNU General Public License for more details.
11   
12   You should have received a copy of the GNU General Public License
13   along with this program.  If not, see <http://www.gnu.org/licenses/>. 
14 */
15
16 #include <iostream>
17 #include <iomanip>
18 #include <iostream>
19 #include <taglib/fileref.h>
20 #include <taglib/tag.h>
21 #include <taglib/tpropertymap.h>
22 #include <taglib/tstringlist.h>
23 #include <getopt.h>
24 #include <vector>
25
26 using namespace std;
27
28 enum action {LIST, REPLACE, INSERT, ERASE, AUDIO};
29 typedef pair<action,string> actionpair;
30 typedef vector<actionpair> actionqueue;
31 typedef pair<string,string> tagpair;
32
33 TagLib::StringList argToStringList (const string &rawtagarg)
34 {
35   TagLib::StringList newlist;
36
37   size_t delpos = 0;
38   while (1) {
39     size_t nextdelpos = rawtagarg.find('=', delpos+1);
40     if (nextdelpos == -1)
41       break;
42     newlist.append(rawtagarg.substr(delpos,nextdelpos-delpos));
43     delpos = nextdelpos+1;
44   }
45   newlist.append(rawtagarg.substr(delpos,string::npos));  
46
47   return newlist;
48 }
49
50 tagpair splitToTagPair (const string &rawarg)
51 {
52   const size_t delpos = rawarg.find('=');
53   return make_pair(rawarg.substr(0, delpos), rawarg.substr(delpos+1, string::npos));
54 }
55
56 void action_eraseTag (const TagLib::FileRef f, const string &key)
57 {
58   TagLib::PropertyMap propmap = f.file()->properties();
59   propmap.erase(key);
60   f.file()->setProperties(propmap);
61 }
62
63 void action_replaceTag (const TagLib::FileRef f, const tagpair &tagPair)
64 {
65   TagLib::PropertyMap propmap = f.file()->properties();
66   propmap.replace(tagPair.first, argToStringList(tagPair.second));
67   f.file()->setProperties(propmap);
68 }
69
70 void action_insertTag (const TagLib::FileRef f, const tagpair &tagPair)
71 {
72   TagLib::PropertyMap propmap = f.file()->properties();
73   propmap.insert(tagPair.first, argToStringList(tagPair.second));
74   f.file()->setProperties(propmap);
75 }
76
77 int action_printTags (const TagLib::FileRef f)
78 {
79   if(f.tag()) {
80     TagLib::PropertyMap tags = f.file()->properties();
81     unsigned int longest = 0;
82     for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
83       if (i->first.size() > longest) {
84         longest = i->first.size();
85       }
86     }
87     cout << "-- TAG (properties) --" << endl;
88     for(TagLib::PropertyMap::ConstIterator i = tags.begin(); i != tags.end(); ++i) {
89       for(TagLib::StringList::ConstIterator j = i->second.begin(); j != i->second.end(); ++j) {
90         cout << i->first << "=" << *j << endl;
91       }
92     }
93     return 0;
94   }
95   else
96     return 1;
97 }
98
99 int action_printAudio (const TagLib::FileRef f)
100 {
101   if(f.audioProperties()) {
102     TagLib::AudioProperties *properties = f.audioProperties();
103     int seconds = properties->length() % 60;
104     int minutes = (properties->length() - seconds) / 60;
105     cout << "-- AUDIO --" << endl;
106     cout << "BITRATE=" << properties->bitrate() << endl;
107     cout << "SAMPLERATE=" << properties->sampleRate() << endl;
108     cout << "CHANNELS=" << properties->channels() << endl;
109     cout << "LENGTH=" << minutes << ":" << setfill('0') << setw(2) << seconds << endl;
110     return 0;
111   }
112   else
113     return 1;
114 }
115
116 void printHelp ()
117 {
118   cout << "Usage: usetaglib [ACTION]... [FILE]..." << endl;
119   cout << "List and edit tags on mediafiles in formats supported by libtag." << endl;
120   cout << endl;
121   cout << "-h, --help   Show this help" << endl;
122   cout << endl;
123   cout << "ACTIONS" << endl;
124   cout << setfill(' ') << setw(45) << left << "  -l, --list"
125        << "list all tags (implicit if no action specified)"<< endl;
126   cout << setfill(' ') << setw(45) << left << "  -e, --erase=TAGNAME"
127        << "erase tag with name TAGNAME"<< endl;
128   cout << setfill(' ') << setw(45) << left << "  -r, --replace=TAGNAME=TAGVAL[=TAGVAL...]"
129        << "replace tag TAGNAME with list of values TAGVAL"<< endl;
130   cout << setfill(' ') << setw(45) << left << "  -i, --insert=TAGNAME=TAGVAL[=TAGVAL...]"
131        << "insert list of values TAGVAL for tag TAGNAME"<< endl;
132 }
133   
134 int main(int argc, char *argv[])
135 {
136   int c;
137   actionqueue requestedActions;
138   
139   while (1)
140     {
141       static struct option long_options[] =
142         {
143           {"help",      no_argument,       0, 'h'},
144           {"list",      no_argument,       0, 'l'},
145           {"listaudio", no_argument,       0, 'a'},
146           {"insert",    required_argument, 0, 'i'},
147           {"erase",     required_argument, 0, 'e'},
148           {"replace",   required_argument, 0, 'r'},
149           {0, 0, 0, 0}
150         };
151
152       int option_index = 0;      
153       c = getopt_long (argc, argv, "hlai:e:r:",
154                        long_options, &option_index);
155
156       if (c == -1)
157         break;
158
159       switch (c)
160         {
161         case 0:
162           if (long_options[option_index].flag != 0)
163             break;
164
165         case 'h':
166           printHelp();
167           return 0;
168           break;
169           
170         case 'l':
171           requestedActions.push_back( make_pair(LIST, "") );
172           break;
173
174         case 'a':
175           requestedActions.push_back( make_pair(AUDIO, "") );
176           break;
177
178         case 'i':
179           requestedActions.push_back( make_pair(INSERT, optarg) );
180           break;
181
182         case 'e':
183           requestedActions.push_back( make_pair(ERASE, optarg) );
184           break;
185
186         case 'r':
187           requestedActions.push_back( make_pair(REPLACE, optarg) );
188           break;
189
190         case '?':
191           break;
192
193         default:
194           abort ();
195         }
196     }
197
198   if (requestedActions.size() == 0)
199     requestedActions.push_back( make_pair(LIST, "") );
200   
201   for(int i = optind; i < argc; i++) {
202     cout << "******************** \"" << argv[i] << "\" ********************" << endl;
203     TagLib::FileRef f(argv[i]);
204
205     if(f.isNull())
206       continue;
207     
208     for (actionqueue::iterator actit = requestedActions.begin(); actit != requestedActions.end(); ++actit) {
209       switch (actit->first) {
210       case LIST:
211         action_printTags(f);
212         break;
213         
214       case AUDIO:
215         action_printAudio(f);
216         break;
217         
218       case ERASE:
219         action_eraseTag(f, actit->second);
220         break;
221         
222       case REPLACE:
223         action_replaceTag(f, splitToTagPair(actit->second));
224         break;
225
226       case INSERT:
227         action_insertTag(f, splitToTagPair(actit->second));
228         break;
229       }
230     }
231     
232     f.file()->save();
233   }
234   
235   return 0;
236 }