1
0
mirror of https://github.com/tomahawk-player/tomahawk.git synced 2025-09-02 10:24:01 +02:00
Files
tomahawk/thirdparty/liblastfm2/src/scrobble/ScrobbleCache.cpp
2011-03-24 19:27:01 -04:00

164 lines
4.4 KiB
C++

/*
Copyright 2009 Last.fm Ltd.
- Primarily authored by Max Howell, Jono Cole and Doug Mansell
This file is part of liblastfm.
liblastfm is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
liblastfm is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with liblastfm. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScrobbleCache.h"
#include "ScrobblePoint.h"
#include <lastfm/misc.h>
#include <QCoreApplication>
#include <QFile>
#include <QDomElement>
#include <QDomDocument>
#if LASTFM_VERSION >= 0x00010000
using lastfm::ScrobbleCache;
#endif
ScrobbleCache::ScrobbleCache( const QString& username )
{
Q_ASSERT( username.length() );
m_path = lastfm::dir::runtimeData().filePath( username + "_subs_cache.xml" );
m_username = username;
QDomDocument xml;
read( xml );
}
bool
ScrobbleCache::isValid( const Track& track, Invalidity* v )
{
#define TEST( test, x ) \
if (test) { \
if (v) *v = x; \
return false; \
}
TEST( track.duration() < ScrobblePoint::kScrobbleMinLength, TooShort );
TEST( !track.timestamp().isValid(), NoTimestamp );
// actual spam prevention is something like 12 hours, but we are only
// trying to weed out obviously bad data, server side criteria for
// "the future" may change, so we should let the server decide, not us
TEST( track.timestamp() > QDateTime::currentDateTime().addMonths( 1 ), FromTheFuture );
TEST( track.timestamp() < QDateTime::fromString( "2003-01-01", Qt::ISODate ), FromTheDistantPast );
// Check if any required fields are empty
TEST( track.artist().isNull(), ArtistNameMissing );
TEST( track.title().isEmpty(), TrackNameMissing );
TEST( (QStringList() << "unknown artist"
<< "unknown"
<< "[unknown]"
<< "[unknown artist]").contains( track.artist().name().toLower() ),
ArtistInvalid );
return true;
}
void
ScrobbleCache::read( QDomDocument& xml )
{
m_tracks.clear();
QFile file( m_path );
file.open( QFile::Text | QFile::ReadOnly );
QTextStream stream( &file );
stream.setCodec( "UTF-8" );
xml.setContent( stream.readAll() );
for (QDomNode n = xml.documentElement().firstChild(); !n.isNull(); n = n.nextSibling())
if (n.nodeName() == "track")
m_tracks += Track( n.toElement() );
}
void
ScrobbleCache::write()
{
if (m_tracks.isEmpty())
{
QFile::remove( m_path );
}
else {
QDomDocument xml;
QDomElement e = xml.createElement( "submissions" );
e.setAttribute( "product", QCoreApplication::applicationName() );
e.setAttribute( "version", "2" );
foreach (Track i, m_tracks)
e.appendChild( i.toDomElement( xml ) );
xml.appendChild( e );
QFile file( m_path );
file.open( QIODevice::WriteOnly | QIODevice::Text );
QTextStream stream( &file );
stream.setCodec( "UTF-8" );
stream << "<?xml version='1.0' encoding='utf-8'?>\n";
stream << xml.toString( 2 );
file.close();
}
}
void
ScrobbleCache::add( const QList<Track>& tracks )
{
foreach (const Track& track, tracks)
{
ScrobbleCache::Invalidity invalidity;
if ( !isValid( track, &invalidity ) )
{
qWarning() << invalidity;
}
else if (track.isNull())
qDebug() << "Will not cache an empty track";
else
m_tracks += track;
}
write();
}
int
ScrobbleCache::remove( const QList<Track>& toremove )
{
QMutableListIterator<Track> i( m_tracks );
while (i.hasNext()) {
Track t = i.next();
for (int x = 0; x < toremove.count(); ++x)
if (toremove[x] == t)
i.remove();
}
write();
// yes we return # remaining, rather # removed, but this is an internal
// function and the behaviour is documented so it's alright imo --mxcl
return m_tracks.count();
}