File indexing completed on 2024-05-05 04:48:27

0001 /***************************************************************************
0002  *   Copyright (c) 2010 Casey Link <unnamedrambler@gmail.com>              *
0003  *   Copyright (c) 2008 Bonne Eggleston <b.eggleston@gmail.com>            *
0004  *                                                                         *
0005  *   This program is free software; you can redistribute it and/or modify  *
0006  *   it under the terms of the GNU General Public License as published by  *
0007  *   the Free Software Foundation; either version 2 of the License, or     *
0008  *   (at your option) any later version.                                   *
0009  *                                                                         *
0010  *   This program is distributed in the hope that it will be useful,       *
0011  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
0012  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
0013  *   GNU General Public License for more details.                          *
0014  *                                                                         *
0015  *   You should have received a copy of the GNU General Public License     *
0016  *   along with this program; if not, write to the                         *
0017  *   Free Software Foundation, Inc.,                                       *
0018  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.         *
0019  ***************************************************************************/
0020 
0021 #include "TrackOrganizer.h"
0022 
0023 #include "QStringx.h"
0024 #include "core/meta/Meta.h"
0025 #include "core/meta/Statistics.h"
0026 #include "core/support/Amarok.h"
0027 
0028 #include <KLocalizedString>
0029 
0030 TrackOrganizer::TrackOrganizer( const Meta::TrackList &tracks, QObject* parent )
0031     : QObject( parent )
0032     , m_allTracks( tracks )
0033     , m_trackOffset( 0 )
0034     , m_postfixThe( false )
0035     , m_AsciiOnly( false )
0036     , m_UnderscoresNotSpaces( false )
0037     , m_vfatSafe( false )
0038 {
0039 
0040 }
0041 
0042 QString TrackOrganizer::buildDestination(const QString& format, const Meta::TrackPtr& track) const
0043 {
0044     // get hold of the shared pointers
0045     Meta::AlbumPtr album = track->album();
0046     Meta::ArtistPtr artist = track->artist();
0047     Meta::ComposerPtr composer = track->composer();
0048     Meta::ArtistPtr albumArtist = album ? album->albumArtist() : Meta::ArtistPtr();
0049     Meta::GenrePtr genre = track->genre();
0050     Meta::YearPtr year = track->year();
0051 
0052     bool isCompilation = album && album->isCompilation();
0053 
0054     QMap<QString, QString> args;
0055     QString strArtist = artist ? artist->name() : QString();
0056     QString strAlbumArtist = isCompilation ? i18n( "Various Artists" ) :
0057         ( albumArtist ? albumArtist->name() : strArtist );
0058 
0059     args["theartist"] = strArtist;
0060     args["thealbumartist"] = strAlbumArtist;
0061 
0062     if( m_postfixThe )
0063     {
0064         Amarok::manipulateThe( strArtist, true );
0065         Amarok::manipulateThe( strAlbumArtist, true );
0066     }
0067 
0068     if ( track->trackNumber() )
0069     {
0070         QString trackNum = QStringLiteral("%1").arg( track->trackNumber(), 2, 10, QChar('0') );
0071         args["track"] = trackNum;
0072     }
0073     args["title"] = track->name();
0074     args["artist"] = strArtist;
0075     args["composer"] = composer ? composer->name() : QString();
0076     // if year == 0 then we don't want include it
0077     QString strYear = year ? year->name() : QString();
0078     args["year"] = strYear.localeAwareCompare( "0" ) == 0 ? QString() : strYear;
0079     args["album"] = track->album() ? track->album()->name() : QString();
0080     args["albumartist"] = strAlbumArtist;
0081     args["comment"] = track->comment();
0082     args["genre"] = genre ? genre->name() : QString();
0083     if( m_targetFileExtension.isEmpty() )
0084         args["filetype"] = track->type();
0085     else
0086         args["filetype"] = m_targetFileExtension;
0087     QString strFolder = QFileInfo( track->playableUrl().toLocalFile() ).path();
0088     strFolder = strFolder.mid( commonPrefixLength( m_folderPrefix, strFolder ) );
0089     args["folder"] = strFolder;
0090     args["initial"] = strAlbumArtist.mid( 0, 1 ).toUpper(); //artists starting with The are already handled above
0091     if( track->discNumber() )
0092         args["discnumber"] = QString::number( track->discNumber() );
0093     args["collectionroot"] = m_folderPrefix;
0094 
0095     // some additional properties not supported by organize dialog.
0096     args["rating"] = track->statistics()->rating();
0097     args["filesize"] = track->filesize();
0098     args["length"] = track->length() / 1000;
0099 
0100     // Fill up default empty values for StringX formatter
0101     // TODO make this values changeable by user
0102     args["default_album"]           = i18n( "Unknown album" );
0103     args["default_albumartist"]     = i18n( "Unknown artist" );
0104     args["default_artist"]          = args["albumartist"];
0105     args["default_thealbumartist"]  = args["albumartist"];
0106     args["default_theartist"]       = args["albumartist"];
0107     args["default_comment"]         = i18n( "No comments" );
0108     args["default_composer"]        = i18n( "Unknown composer" );
0109     args["default_discnumber"]      = i18n( "Unknown disc number" );
0110     args["default_genre"]           = i18n( "Unknown genre" );
0111     args["default_title"]           = i18n( "Unknown title" );
0112     args["default_year"]            = i18n( "Unknown year" );
0113 
0114     foreach( const QString &key, args.keys() )
0115         if( key != "collectionroot" && key != "folder" )
0116             args[key] = args[key].replace( QLatin1Char('/'), '-' );
0117 
0118     Amarok::QStringx formatx( format );
0119     QString result = formatx.namedOptArgs( args );
0120     return cleanPath( result );
0121 }
0122 
0123 QString TrackOrganizer::cleanPath( const QString& path ) const
0124 {
0125     QString result = path;
0126 
0127     if( m_AsciiOnly )
0128     {
0129         result = Amarok::cleanPath( result );
0130         result = Amarok::asciiPath( result );
0131     }
0132 
0133     if( !m_regexPattern.isEmpty() )
0134         result.replace( QRegExp( m_regexPattern ), m_replaceString );
0135 
0136     result = result.simplified();
0137     if( m_UnderscoresNotSpaces )
0138         result.replace( QRegExp( "\\s" ), "_" );
0139 
0140     if( m_vfatSafe )
0141         // we use UnixBehaviour even on windows, because even there we use / as directory
0142         // separator currently (QFile mangles it internally)
0143         result = Amarok::vfatPath( result, Amarok::UnixBehaviour );
0144 
0145     QFileInfo info( result ); // Used to polish path string. (e.g. remove '//')
0146     return info.absoluteFilePath();
0147 }
0148 
0149 int TrackOrganizer::commonPrefixLength( const QString &a, const QString &b )
0150 {
0151     int prefix = 0;
0152     while( prefix < a.length() && prefix < b.length() &&
0153            a.at(prefix) == b.at(prefix) )
0154         prefix++;
0155     return prefix;
0156 }
0157 
0158 QMap< Meta::TrackPtr, QString > TrackOrganizer::getDestinations( unsigned int batchSize )
0159 {
0160     QMap<Meta::TrackPtr, QString> destinations;
0161 
0162     int newOffset = m_trackOffset + batchSize;
0163     //don't go out of bounds in the for loop
0164     if( newOffset >= m_allTracks.count() )
0165         newOffset = m_allTracks.count();
0166 
0167     if( batchSize == 0 )
0168     {
0169         m_trackOffset = 0;
0170         newOffset = m_allTracks.count();
0171     }
0172 
0173     for( ; m_trackOffset < newOffset ; m_trackOffset++ )
0174     {
0175         Meta::TrackPtr track = m_allTracks.value( m_trackOffset );
0176         if( track )
0177             destinations.insert( track, buildDestination( m_format, track ) );
0178     }
0179 
0180     return destinations;
0181 }
0182 
0183 void TrackOrganizer::setFormatString( const QString& format )
0184 {
0185     m_format = format;
0186 }
0187 
0188 void TrackOrganizer::setFolderPrefix(const QString& prefix)
0189 {
0190     m_folderPrefix = prefix;
0191 }
0192 
0193 void TrackOrganizer::setAsciiOnly(bool flag)
0194 {
0195     m_AsciiOnly = flag;
0196 }
0197 
0198 void TrackOrganizer::setPostfixThe(bool flag)
0199 {
0200     m_postfixThe = flag;
0201 }
0202 
0203 void TrackOrganizer::setReplaceSpaces(bool flag)
0204 {
0205     m_UnderscoresNotSpaces = flag;
0206 }
0207 
0208 void TrackOrganizer::setVfatSafe(bool flag)
0209 {
0210     m_vfatSafe = flag;
0211 }
0212 
0213 void TrackOrganizer::setReplace(const QString& regex, const QString& string)
0214 {
0215     m_regexPattern = regex;
0216     m_replaceString = string;
0217 }
0218 
0219 void TrackOrganizer::setTargetFileExtension( const QString &fileExtension )
0220 {
0221     m_targetFileExtension = fileExtension;
0222 }