File indexing completed on 2024-05-12 16:18:06
0001 /*************************************************************************** 0002 * Copyright (C) 2003-2005 Max Howell <max.howell@methylblue.com> * 0003 * (C) 2003-2010 Mark Kretschmann <kretschmann@kde.org> * 0004 * (C) 2005-2007 Alexandre Oliveira <aleprj@gmail.com> * 0005 * (C) 2008 Dan Meltzer <parallelgrapefruit@gmail.com> * 0006 * (C) 2008-2009 Jeff Mitchell <mitchell@kde.org> * 0007 * * 0008 * This program is free software; you can redistribute it and/or modify * 0009 * it under the terms of the GNU General Public License as published by * 0010 * the Free Software Foundation; either version 2 of the License, or * 0011 * (at your option) any later version. * 0012 * * 0013 * This program is distributed in the hope that it will be useful, * 0014 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0016 * GNU General Public License for more details. * 0017 * * 0018 * You should have received a copy of the GNU General Public License * 0019 * along with this program; if not, write to the * 0020 * Free Software Foundation, Inc., * 0021 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * 0022 ***************************************************************************/ 0023 0024 #include "Directory.h" 0025 0026 #include "collectionscanner/ScanningState.h" 0027 #include "collectionscanner/Track.h" 0028 #include "collectionscanner/utils.h" 0029 0030 #include <QDebug> 0031 #include <QString> 0032 #include <QStringList> 0033 #include <QSettings> 0034 #include <QDir> 0035 #include <QFile> 0036 #include <QDateTime> 0037 #include <QFileInfo> 0038 0039 #include <QXmlStreamReader> 0040 #include <QXmlStreamWriter> 0041 0042 CollectionScanner::Directory::Directory( const QString &path, 0043 CollectionScanner::ScanningState *state, 0044 bool skip ) 0045 : m_ignored( false ) 0046 { 0047 m_path = path; 0048 m_rpath = QDir::current().relativeFilePath( path ); 0049 m_mtime = QFileInfo( path ).lastModified().toSecsSinceEpoch(); 0050 m_skipped = skip; 0051 0052 if( m_skipped ) 0053 return; 0054 0055 QDir dir( path ); 0056 if( dir.exists( QStringLiteral("fmps_ignore") ) ) 0057 { 0058 m_ignored = true; 0059 return; 0060 } 0061 0062 QStringList validImages; 0063 validImages << QStringLiteral("jpg") << QStringLiteral("png") << QStringLiteral("gif") << QStringLiteral("jpeg") << QStringLiteral("bmp") << QStringLiteral("svg") << QStringLiteral("xpm"); 0064 QStringList validPlaylists; 0065 validPlaylists << QStringLiteral("m3u") << QStringLiteral("pls") << QStringLiteral("xspf"); 0066 0067 // --- check if we were restarted and failed at a file 0068 QStringList badFiles; 0069 0070 if( state->lastDirectory() == path ) 0071 { 0072 badFiles << state->badFiles(); 0073 QString lastFile = state->lastFile(); 0074 if( !lastFile.isEmpty() ) 0075 { 0076 badFiles << state->lastFile(); 0077 state->setBadFiles( badFiles ); 0078 } 0079 } 0080 else 0081 state->setLastDirectory( path ); 0082 state->setLastFile( QString() ); // reset so we don't add a leftover file 0083 0084 dir.setFilter( QDir::NoDotAndDotDot | QDir::Files ); 0085 QFileInfoList fileInfos = dir.entryInfoList(); 0086 0087 foreach( const QFileInfo &fi, fileInfos ) 0088 { 0089 if( !fi.exists() ) 0090 continue; 0091 0092 const QFileInfo &f = fi.isSymLink() ? QFileInfo( fi.symLinkTarget() ) : fi; 0093 0094 if( badFiles.contains( f.absoluteFilePath() ) ) 0095 continue; 0096 0097 const QString suffix = fi.suffix().toLower(); 0098 const QString filePath = f.absoluteFilePath(); 0099 0100 // -- cover image ? 0101 if( validImages.contains( suffix ) ) 0102 m_covers.append( filePath ); 0103 0104 // -- playlist ? 0105 else if( validPlaylists.contains( suffix ) ) 0106 m_playlists.append( CollectionScanner::Playlist( filePath ) ); 0107 0108 // -- audio track ? 0109 else 0110 { 0111 // remember the last file before it get's dangerous. Before starting taglib 0112 state->setLastFile( f.absoluteFilePath() ); 0113 0114 CollectionScanner::Track *newTrack = new CollectionScanner::Track( filePath, this ); 0115 if( newTrack->isValid() ) 0116 m_tracks.append( newTrack ); 0117 else 0118 delete newTrack; 0119 } 0120 } 0121 } 0122 0123 CollectionScanner::Directory::Directory( QXmlStreamReader *reader ) 0124 : m_mtime( 0 ) 0125 , m_skipped( false ) 0126 , m_ignored( false ) 0127 { 0128 // improve scanner with skipCurrentElement as soon as Amarok requires Qt 4.6 0129 while (!reader->atEnd()) { 0130 reader->readNext(); 0131 0132 if( reader->isStartElement() ) 0133 { 0134 QStringRef name = reader->name(); 0135 if( name == QLatin1String("path") ) 0136 m_path = reader->readElementText(QXmlStreamReader::SkipChildElements); 0137 else if( name == QLatin1String("rpath") ) 0138 m_rpath = reader->readElementText(QXmlStreamReader::SkipChildElements); 0139 else if( name == QLatin1String("mtime") ) 0140 m_mtime = reader->readElementText(QXmlStreamReader::SkipChildElements).toUInt(); 0141 else if( name == QLatin1String("cover") ) 0142 m_covers.append(reader->readElementText(QXmlStreamReader::SkipChildElements)); 0143 else if( name == QLatin1String("skipped") ) 0144 { 0145 m_skipped = true; 0146 reader->skipCurrentElement(); 0147 } 0148 else if( name == QLatin1String("ignored") ) 0149 { 0150 m_ignored = true; 0151 reader->skipCurrentElement(); 0152 } 0153 else if( name == QLatin1String("track") ) 0154 m_tracks.append( new CollectionScanner::Track( reader, this ) ); 0155 else if( name == QLatin1String("playlist") ) 0156 m_playlists.append( CollectionScanner::Playlist( reader ) ); 0157 else 0158 { 0159 qDebug() << "Unexpected xml start element"<<name<<"in input"; 0160 reader->skipCurrentElement(); 0161 } 0162 } 0163 0164 else if( reader->isEndElement() ) 0165 { 0166 break; 0167 } 0168 } 0169 } 0170 0171 CollectionScanner::Directory::~Directory() 0172 { 0173 foreach( CollectionScanner::Track *track, m_tracks ) 0174 delete track; 0175 } 0176 0177 QString 0178 CollectionScanner::Directory::path() const 0179 { 0180 return m_path; 0181 } 0182 0183 QString 0184 CollectionScanner::Directory::rpath() const 0185 { 0186 return m_rpath; 0187 } 0188 0189 uint 0190 CollectionScanner::Directory::mtime() const 0191 { 0192 return m_mtime; 0193 } 0194 0195 bool 0196 CollectionScanner::Directory::isSkipped() const 0197 { 0198 return m_skipped; 0199 } 0200 0201 const QStringList& 0202 CollectionScanner::Directory::covers() const 0203 { 0204 return m_covers; 0205 } 0206 0207 const QList<CollectionScanner::Track *>& 0208 CollectionScanner::Directory::tracks() const 0209 { 0210 return m_tracks; 0211 } 0212 0213 const QList<CollectionScanner::Playlist>& 0214 CollectionScanner::Directory::playlists() const 0215 { 0216 return m_playlists; 0217 } 0218 0219 void 0220 CollectionScanner::Directory::toXml( QXmlStreamWriter *writer ) const 0221 { 0222 writer->writeTextElement( QStringLiteral("path"), escapeXml10(m_path) ); 0223 writer->writeTextElement( QStringLiteral("rpath"), escapeXml10(m_rpath) ); 0224 writer->writeTextElement( QStringLiteral("mtime"), QString::number( m_mtime ) ); 0225 if( m_skipped ) 0226 writer->writeEmptyElement( QStringLiteral("skipped") ); 0227 if( m_ignored ) 0228 writer->writeEmptyElement( QStringLiteral("ignored") ); 0229 0230 foreach( const QString &cover, m_covers ) 0231 { 0232 writer->writeTextElement( QStringLiteral("cover"), escapeXml10(cover) ); 0233 } 0234 foreach( CollectionScanner::Track *track, m_tracks ) 0235 { 0236 writer->writeStartElement( QStringLiteral("track") ); 0237 track->toXml( writer ); 0238 writer->writeEndElement(); 0239 } 0240 0241 foreach( const CollectionScanner::Playlist &playlist, m_playlists ) 0242 { 0243 writer->writeStartElement( QStringLiteral("playlist") ); 0244 playlist.toXml( writer ); 0245 writer->writeEndElement(); 0246 } 0247 }