File indexing completed on 2024-05-19 04:49:24
0001 /**************************************************************************************** 0002 * Copyright (c) 2011 Bart Cerneels <bart.cerneels@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 "PlaylistFile.h" 0018 0019 #include "core/support/Debug.h" 0020 #include "core-impl/playlists/types/file/PlaylistFileLoaderJob.h" 0021 #include "playlistmanager/file/PlaylistFileProvider.h" 0022 #include "playlistmanager/PlaylistManager.h" 0023 0024 #include <QUrl> 0025 #include <QDir> 0026 0027 #include <ThreadWeaver/Queue> 0028 0029 using namespace Playlists; 0030 0031 PlaylistFile::PlaylistFile( const QUrl &url, PlaylistProvider *provider ) 0032 : Playlist() 0033 , m_provider( provider ) 0034 , m_url( url ) 0035 , m_tracksLoaded( false ) 0036 , m_name( m_url.fileName() ) 0037 , m_relativePaths( false ) 0038 , m_loadingDone( 0 ) 0039 { 0040 } 0041 0042 void 0043 PlaylistFile::saveLater() 0044 { 0045 PlaylistFileProvider *fileProvider = qobject_cast<PlaylistFileProvider *>( m_provider ); 0046 if( !fileProvider ) 0047 return; 0048 0049 fileProvider->saveLater( PlaylistFilePtr( this ) ); 0050 } 0051 0052 void 0053 PlaylistFile::triggerTrackLoad() 0054 { 0055 if( m_tracksLoaded ) 0056 { 0057 notifyObserversTracksLoaded(); 0058 return; 0059 } 0060 PlaylistFileLoaderJob *worker = new PlaylistFileLoaderJob( PlaylistFilePtr( this ) ); 0061 ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(worker) ); 0062 if ( !isLoadingAsync() ) 0063 m_loadingDone.acquire(); // after loading is finished worker will release semapore 0064 } 0065 0066 bool 0067 PlaylistFile::isWritable() const 0068 { 0069 if( m_url.isEmpty() ) 0070 return false; 0071 0072 return QFileInfo( m_url.path() ).isWritable(); 0073 } 0074 0075 int 0076 PlaylistFile::trackCount() const 0077 { 0078 if( m_tracksLoaded ) 0079 return m_tracks.count(); 0080 else 0081 return -1; 0082 } 0083 0084 void 0085 PlaylistFile::addTrack( const Meta::TrackPtr &track, int position ) 0086 { 0087 if( !track ) // playlists might contain invalid tracks. see BUG: 303056 0088 return; 0089 0090 int trackPos = position < 0 ? m_tracks.count() : position; 0091 if( trackPos > m_tracks.count() ) 0092 trackPos = m_tracks.count(); 0093 m_tracks.insert( trackPos, track ); 0094 // set in case no track was in the playlist before 0095 m_tracksLoaded = true; 0096 0097 notifyObserversTrackAdded( track, trackPos ); 0098 0099 if( !m_url.isEmpty() ) 0100 saveLater(); 0101 } 0102 0103 void 0104 PlaylistFile::removeTrack( int position ) 0105 { 0106 if( position < 0 || position >= m_tracks.count() ) 0107 return; 0108 0109 m_tracks.removeAt( position ); 0110 0111 notifyObserversTrackRemoved( position ); 0112 0113 if( !m_url.isEmpty() ) 0114 saveLater(); 0115 } 0116 0117 bool 0118 PlaylistFile::save( bool relative ) 0119 { 0120 m_relativePaths = relative; 0121 QMutexLocker locker( &m_saveLock ); 0122 0123 //if the location is a directory append the name of this playlist. 0124 if( m_url.fileName().isNull() ) 0125 { m_url = m_url.adjusted(QUrl::RemoveFilename); 0126 m_url.setPath(m_url.path() + name()); 0127 } 0128 QFile file( m_url.path() ); 0129 0130 if( !file.open( QIODevice::WriteOnly ) ) 0131 { 0132 warning() << QStringLiteral( "Cannot write playlist (%1)." ).arg( file.fileName() ) 0133 << file.errorString(); 0134 return false; 0135 } 0136 0137 savePlaylist( file ); 0138 file.close(); 0139 return true; 0140 } 0141 0142 void 0143 PlaylistFile::setName( const QString &name ) 0144 { 0145 //can't save to a new file if we don't know where. 0146 if( !m_url.isEmpty() && !name.isEmpty() ) 0147 { 0148 QString exten = QStringLiteral( ".%1" ).arg(extension()); 0149 m_url = m_url.adjusted(QUrl::RemoveFilename); 0150 m_url.setPath(m_url.path() + name + ( name.endsWith( exten, Qt::CaseInsensitive ) ? QLatin1String("") : exten )); 0151 } 0152 } 0153 0154 void 0155 PlaylistFile::addProxyTrack( const Meta::TrackPtr &proxyTrack ) 0156 { 0157 m_tracks << proxyTrack; 0158 notifyObserversTrackAdded( m_tracks.last(), m_tracks.size() - 1 ); 0159 } 0160 0161 QUrl 0162 PlaylistFile::getAbsolutePath( const QUrl &url ) 0163 { 0164 QUrl absUrl = url; 0165 0166 if( url.scheme().isEmpty() ) 0167 absUrl.setScheme( QStringLiteral( "file" ) ); 0168 0169 if( !absUrl.isLocalFile() ) 0170 return url; 0171 0172 if( !url.path().startsWith( QLatin1Char('/') ) ) 0173 { 0174 m_relativePaths = true; 0175 // example: url = QUrl( "file://../tunes/tune.ogg" ) 0176 absUrl = m_url.adjusted(QUrl::RemoveFilename); // file:///playlists/ 0177 absUrl = absUrl.adjusted(QUrl::StripTrailingSlash); 0178 absUrl.setPath( absUrl.path() + QLatin1Char('/') + url.path() ); 0179 absUrl.setPath( QDir::cleanPath(absUrl.path()) ); // file:///playlists/tunes/tune.ogg 0180 } 0181 return absUrl; 0182 } 0183 0184 QString 0185 PlaylistFile::trackLocation( const Meta::TrackPtr &track ) const 0186 { 0187 QUrl path = track->playableUrl(); 0188 if( path.isEmpty() ) 0189 return track->uidUrl(); 0190 0191 if( !m_relativePaths || m_url.isEmpty() || !path.isLocalFile() || !m_url.isLocalFile() ) 0192 return path.toEncoded(); 0193 0194 QDir playlistDir( m_url.adjusted(QUrl::RemoveFilename).path() ); 0195 return QUrl::toPercentEncoding( playlistDir.relativeFilePath( path.path() ), "/" ); 0196 }