File indexing completed on 2023-05-30 11:30:52

0001 /**
0002  * Copyright (C) 2003 Frerich Raabe <raabe@kde.org>
0003  *
0004  * This program is free software; you can redistribute it and/or modify it under
0005  * the terms of the GNU General Public License as published by the Free Software
0006  * Foundation; either version 2 of the License, or (at your option) any later
0007  * version.
0008  *
0009  * This program is distributed in the hope that it will be useful, but WITHOUT ANY
0010  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
0011  * PARTICULAR PURPOSE. See the GNU General Public License for more details.
0012  *
0013  * You should have received a copy of the GNU General Public License along with
0014  * this program.  If not, see <http://www.gnu.org/licenses/>.
0015  */
0016 
0017 #include "tagguesser.h"
0018 #include "juk_debug.h"
0019 
0020 #include <kconfig.h>
0021 #include <kmacroexpander.h>
0022 #include <qhash.h>
0023 #include <kconfiggroup.h>
0024 #include <KSharedConfig>
0025 
0026 FileNameScheme::FileNameScheme(const QString &s)
0027     : m_regExp(),
0028     m_titleField(-1),
0029     m_artistField(-1),
0030     m_albumField(-1),
0031     m_trackField(-1),
0032     m_commentField(-1)
0033 {
0034     int fieldNumber = 1;
0035     int i = s.indexOf('%');
0036     while (i > -1) {
0037         switch (s[ i + 1 ].toLatin1()) {
0038             case 't': m_titleField = fieldNumber++;
0039                       break;
0040             case 'a': m_artistField = fieldNumber++;
0041                       break;
0042             case 'A': m_albumField = fieldNumber++;
0043                       break;
0044             case 'T': m_trackField = fieldNumber++;
0045                       break;
0046             case 'c': m_commentField = fieldNumber++;
0047                       break;
0048             default:
0049                       break;
0050         }
0051         i = s.indexOf('%', i + 1);
0052     }
0053     m_regExp.setPattern(composeRegExp(s));
0054 }
0055 
0056 bool FileNameScheme::matches(const QString &fileName) const
0057 {
0058     /* Strip extension ('.mp3') because '.' may be part of a title, and thus
0059      * does not work as a separator.
0060      */
0061     QString stripped = fileName;
0062     stripped.truncate(stripped.lastIndexOf('.'));
0063     return m_regExp.exactMatch(stripped);
0064 }
0065 
0066 QString FileNameScheme::title() const
0067 {
0068     if(m_titleField == -1)
0069         return QString();
0070     return m_regExp.capturedTexts().at(m_titleField);
0071 }
0072 
0073 QString FileNameScheme::artist() const
0074 {
0075     if(m_artistField == -1)
0076         return QString();
0077     return m_regExp.capturedTexts().at(m_artistField);
0078 }
0079 
0080 QString FileNameScheme::album() const
0081 {
0082     if(m_albumField == -1)
0083         return QString();
0084     return m_regExp.capturedTexts().at(m_albumField);
0085 }
0086 
0087 QString FileNameScheme::track() const
0088 {
0089     if(m_trackField == -1)
0090         return QString();
0091     return m_regExp.capturedTexts().at(m_trackField);
0092 }
0093 
0094 QString FileNameScheme::comment() const
0095 {
0096     if(m_commentField == -1)
0097         return QString();
0098     return m_regExp.capturedTexts().at(m_commentField);
0099 }
0100 
0101 QString FileNameScheme::composeRegExp(const QString &s) const
0102 {
0103     QHash<QChar, QString> substitutions;
0104 
0105     KConfigGroup config(KSharedConfig::openConfig(), "TagGuesser");
0106 
0107     substitutions[ 't' ] = config.readEntry("Title regexp", "([\\w\\s'&_,\\.]+)");
0108     substitutions[ 'a' ] = config.readEntry("Artist regexp", "([\\w\\s'&_,\\.]+)");
0109     substitutions[ 'A' ] = config.readEntry("Album regexp", "([\\w\\s'&_,\\.]+)");
0110     substitutions[ 'T' ] = config.readEntry("Track regexp", "(\\d+)");
0111     substitutions[ 'c' ] = config.readEntry("Comment regexp", "([\\w\\s_]+)");
0112 
0113     QString regExp = QRegExp::escape(s.simplified());
0114     regExp = ".*" + regExp;
0115     regExp.replace(' ', "\\s+");
0116     regExp = KMacroExpander::expandMacros(regExp, substitutions);
0117     regExp += "[^/]*$";
0118     return regExp;
0119 }
0120 
0121 QStringList TagGuesser::schemeStrings()
0122 {
0123     QStringList schemes;
0124 
0125     KConfigGroup config(KSharedConfig::openConfig(), "TagGuesser");
0126     schemes = config.readEntry("Filename schemes", QStringList());
0127 
0128     if ( schemes.isEmpty() ) {
0129         schemes += "%a - (%T) - %t [%c]";
0130         schemes += "%a - (%T) - %t (%c)";
0131         schemes += "%a - (%T) - %t";
0132         schemes += "%a - [%T] - %t [%c]";
0133         schemes += "%a - [%T] - %t (%c)";
0134         schemes += "%a - [%T] - %t";
0135         schemes += "%a - %T - %t [%c]";
0136         schemes += "%a - %T - %t (%c)";
0137         schemes += "%a - %T - %t";
0138         schemes += "(%T) %a - %t [%c]";
0139         schemes += "(%T) %a - %t (%c)";
0140         schemes += "(%T) %a - %t";
0141         schemes += "[%T] %a - %t [%c]";
0142         schemes += "[%T] %a - %t (%c)";
0143         schemes += "[%T] %a - %t";
0144         schemes += "%T %a - %t [%c]";
0145         schemes += "%T %a - %t (%c)";
0146         schemes += "%T %a - %t";
0147         schemes += "(%a) %t [%c]";
0148         schemes += "(%a) %t (%c)";
0149         schemes += "(%a) %t";
0150         schemes += "%a - %t [%c]";
0151         schemes += "%a - %t (%c)";
0152         schemes += "%a - %t";
0153         schemes += "%a/%A/[%T] %t [%c]";
0154         schemes += "%a/%A/[%T] %t (%c)";
0155         schemes += "%a/%A/[%T] %t";
0156     }
0157     return schemes;
0158 }
0159 
0160 void TagGuesser::setSchemeStrings(const QStringList &schemes)
0161 {
0162     KSharedConfig::Ptr cfg = KSharedConfig::openConfig();
0163     KConfigGroup group(cfg, "TagGuesser");
0164     group.writeEntry("Filename schemes", schemes);
0165     cfg->sync();
0166 }
0167 
0168 TagGuesser::TagGuesser()
0169 {
0170     loadSchemes();
0171 }
0172 
0173 TagGuesser::TagGuesser(const QString &absFileName)
0174 {
0175     loadSchemes();
0176     guess(absFileName);
0177 }
0178 
0179 void TagGuesser::loadSchemes()
0180 {
0181     const QStringList schemes = schemeStrings();
0182     QStringList::ConstIterator it = schemes.begin();
0183     QStringList::ConstIterator end = schemes.end();
0184     for ( ; it != end; ++it )
0185         m_schemes += FileNameScheme( *it );
0186 }
0187 
0188 void TagGuesser::guess(const QString &absFileName)
0189 {
0190     m_title.clear();
0191     m_artist.clear();
0192     m_album.clear();
0193     m_track.clear();
0194     m_comment.clear();
0195 
0196     FileNameScheme::List::ConstIterator it = m_schemes.constBegin();
0197     FileNameScheme::List::ConstIterator end = m_schemes.constEnd();
0198     for (; it != end; ++it) {
0199         const FileNameScheme schema(*it);
0200         if(schema.matches(absFileName)) {
0201             m_title = capitalizeWords(schema.title().replace('_', " ")).trimmed();
0202             m_artist = capitalizeWords(schema.artist().replace('_', " ")).trimmed();
0203             m_album = capitalizeWords(schema.album().replace('_', " ")).trimmed();
0204             m_track = schema.track().trimmed();
0205             m_comment = schema.comment().replace('_', " ").trimmed();
0206             break;
0207         }
0208     }
0209 }
0210 
0211 QString TagGuesser::capitalizeWords(const QString &s)
0212 {
0213     if(s.isEmpty())
0214         return s;
0215 
0216     QString result = s;
0217     result[ 0 ] = result[ 0 ].toUpper();
0218 
0219     const QRegExp wordRegExp("\\s\\w");
0220     int i = result.indexOf( wordRegExp );
0221     while ( i > -1 ) {
0222         result[ i + 1 ] = result[ i + 1 ].toUpper();
0223         i = result.indexOf( wordRegExp, ++i );
0224     }
0225 
0226     return result;
0227 }
0228 
0229 // vim: set et sw=4 tw=0 sta: