Revert previous commit, was incorrect
[amarok.git] / src / TagGuesser.cpp
blob8f9eea55314e8249113aa024d9ce556d3faba9bd
1 /*
2 * (c) 2005 Alexandre Oliveira <aleprj@gmail.com>
3 * (c) 2003 Frerich Raabe <raabe@kde.org>
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 */
11 #define DEBUG_PREFIX "TagGuesser"
13 #include "TagGuesser.h"
15 #include "amarok.h"
16 #include "debug.h"
18 #include <KApplication>
19 #include <KConfig>
20 #include <KConfigGroup>
21 #include <KGlobal>
22 #include <KMacroExpanderBase>
24 FileNameScheme::FileNameScheme( const QString &s )
25 : m_cod( s )
26 , m_titleField( -1 )
27 , m_artistField( -1 )
28 , m_albumField( -1 )
29 , m_trackField( -1 )
30 , m_commentField( -1 )
31 , m_yearField( -1 )
32 , m_composerField( -1 )
33 , m_genreField( -1 )
35 int artist = s.indexOf( "%artist" );
36 int title = s.indexOf( "%title" );
37 int track = s.indexOf( "%track" );
38 int album = s.indexOf( "%album" );
39 int comment = s.indexOf( "%comment" );
40 int year = s.indexOf( "%year" );
41 int composer = s.indexOf( "%composer" );
42 int genre = s.indexOf( "%genre" );
44 int fieldNumber = 1;
45 int i = s.indexOf( '%' );
46 while ( i > -1 ) {
47 if ( title == i )
48 m_titleField = fieldNumber++;
49 if ( artist == i )
50 m_artistField = fieldNumber++;
51 if ( album == i )
52 m_albumField = fieldNumber++;
53 if ( track == i )
54 m_trackField = fieldNumber++;
55 if ( comment == i )
56 m_commentField = fieldNumber++;
57 if ( year == i )
58 m_yearField = fieldNumber++;
59 if ( composer == i )
60 m_composerField = fieldNumber++;
61 if ( genre == i )
62 m_genreField = fieldNumber++;
64 i = s.indexOf('%', i + 1);
66 m_regExp.setPattern( composeRegExp( s ) );
69 bool FileNameScheme::matches( const QString &fileName ) const
71 /* Strip extension ('.mp3') because '.' may be part of a title, and thus
72 * does not work as a separator.
74 QString stripped = fileName;
75 stripped.truncate( stripped.lastIndexOf( '.' ) );
76 return m_regExp.exactMatch( stripped );
79 QString FileNameScheme::title() const
81 if( m_titleField == -1 )
82 return QString();
83 return m_regExp.capturedTexts()[ m_titleField ];
86 QString FileNameScheme::artist() const
88 if( m_artistField == -1 )
89 return QString();
90 return m_regExp.capturedTexts()[ m_artistField ];
93 QString FileNameScheme::album() const
95 if( m_albumField == -1 )
96 return QString();
97 return m_regExp.capturedTexts()[ m_albumField ];
100 QString FileNameScheme::track() const
102 if( m_trackField == -1 )
103 return QString();
104 return m_regExp.capturedTexts()[ m_trackField ];
107 QString FileNameScheme::comment() const
109 if( m_commentField == -1 )
110 return QString();
111 return m_regExp.capturedTexts()[ m_commentField ];
114 QString FileNameScheme::year() const
116 if( m_yearField == -1 )
117 return QString();
118 return m_regExp.capturedTexts()[ m_yearField ];
121 QString FileNameScheme::composer() const
123 if( m_composerField == -1 )
124 return QString();
125 return m_regExp.capturedTexts()[ m_composerField ];
128 QString FileNameScheme::genre() const
130 if( m_genreField == -1 )
131 return QString();
132 return m_regExp.capturedTexts()[ m_genreField ];
135 QString FileNameScheme::composeRegExp( const QString &s ) const
137 QHash<QString, QString> substitutions;
139 KConfigGroup config(KGlobal::config(), "TagGuesser");
141 substitutions[ "title" ] = config.readEntry( "Title regexp", "([\\w\\s'&_,\\.]+)" );
142 substitutions[ "artist" ] = config.readEntry( "Artist regexp", "([\\w\\s'&_,\\.]+)" );
143 substitutions[ "album" ] = config.readEntry( "Album regexp", "([\\w\\s'&_,\\.]+)" );
144 substitutions[ "track" ] = config.readEntry( "Track regexp", "(\\d+)" );
145 substitutions[ "comment" ] = config.readEntry( "Comment regexp", "([\\w\\s_]+)" );
146 substitutions[ "year" ] = config.readEntry( "Year regexp", "(\\d+)" );
147 substitutions[ "composer" ] = config.readEntry( "Composer regexp", "([\\w\\s'&_,\\.]+)" );
148 substitutions[ "genre" ] = config.readEntry( "Genre regexp", "([\\w\\s'&_,\\.]+)" );
151 QString regExp = QRegExp::escape( s.simplified() );
152 regExp = ".*" + regExp;
153 regExp.replace( ' ', "\\s+" );
154 regExp = KMacroExpander::expandMacros( regExp, substitutions );
155 regExp += "[^/]*$";
156 return regExp;
159 QStringList TagGuesser::schemeStrings()
161 QStringList schemes;
163 schemes = Amarok::config( "TagGuesser" ).readEntry( "Filename schemes", QStringList() );
165 if ( schemes.isEmpty() ) {
166 schemes += "%track - %title";
167 schemes += "%artist - (%track) - %title [%comment]";
168 schemes += "%artist - (%track) - %title (%comment)";
169 schemes += "%artist - (%track) - %title";
170 schemes += "%artist - [%track] - %title [%comment]";
171 schemes += "%artist - [%track] - %title (%comment)";
172 schemes += "%artist - [%track] - %title";
173 schemes += "%artist - %track - %title [%comment]";
174 schemes += "%artist - %track - %title (%comment)";
175 schemes += "%artist - %track - %title";
176 schemes += "(%track) %artist - %title [%comment]";
177 schemes += "(%track) %artist - %title (%comment)";
178 schemes += "(%track) %artist - %title";
179 schemes += "[%track] %artist - %title [%comment]";
180 schemes += "[%track] %artist - %title (%comment)";
181 schemes += "[%track] %artist - %title";
182 schemes += "%track %artist - %title [%comment]";
183 schemes += "%track %artist - %title (%comment)";
184 schemes += "%track %artist - %title";
185 schemes += "(%artist) %title [%comment]";
186 schemes += "(%artist) %title (%comment)";
187 schemes += "(%artist) %title";
188 schemes += "%artist - %title [%comment]";
189 schemes += "%artist - %title (%comment)";
190 schemes += "%artist - %title";
191 schemes += "%artist/%album/[%track] %title [%comment]";
192 schemes += "%artist/%album/[%track] %title (%comment)";
193 schemes += "%artist/%album/[%track] %title";
195 return schemes;
198 void TagGuesser::setSchemeStrings( const QStringList &schemes )
200 KConfigGroup cfg = Amarok::config("TagGuesser");
201 cfg.writeEntry( "Filename schemes", schemes );
202 cfg.sync();
205 TagGuesser::TagGuesser()
207 loadSchemes();
210 TagGuesser::TagGuesser( const QString &absFileName )
212 loadSchemes();
213 guess( absFileName );
216 void TagGuesser::loadSchemes()
218 const QStringList schemes = schemeStrings();
219 QStringList::ConstIterator it = schemes.begin();
220 QStringList::ConstIterator end = schemes.end();
221 for ( ; it != end; ++it )
222 m_schemes += FileNameScheme( *it );
225 void TagGuesser::guess( const QString &absFileName )
227 m_title = m_artist = m_album = m_track = m_comment = m_year = m_composer = m_genre = QString();
229 FileNameScheme::List::ConstIterator it = m_schemes.begin();
230 FileNameScheme::List::ConstIterator end = m_schemes.end();
231 for ( ; it != end; ++it ) {
232 const FileNameScheme schema( *it );
233 if( schema.matches( absFileName ) ) {
234 debug() <<"Schema used: " << " " << schema.pattern();
235 m_title = capitalizeWords( schema.title().replace( '_', " " ) ).trimmed();
236 m_artist = capitalizeWords( schema.artist().replace( '_', " " ) ).trimmed();
237 m_album = capitalizeWords( schema.album().replace( '_', " " ) ).trimmed();
238 m_track = schema.track().trimmed();
239 m_comment = schema.comment().replace( '_', " " ).trimmed();
240 m_year = schema.year().trimmed();
241 m_composer = capitalizeWords( schema.composer().replace( '_', " " ) ).trimmed();
242 m_genre = capitalizeWords( schema.genre().replace( '_', " " ) ).trimmed();
243 break;
248 QString TagGuesser::capitalizeWords( const QString &s )
250 if( s.isEmpty() )
251 return s;
253 QString result = s;
254 result[ 0 ] = result[ 0 ].toUpper();
256 const QRegExp wordRegExp( "\\s\\w" );
257 int i = result.indexOf( wordRegExp );
258 while ( i > -1 ) {
259 result[ i + 1 ] = result[ i + 1 ].toUpper();
260 i = result.indexOf( wordRegExp, ++i );
263 return result;