Commit e725f336 authored by Soren Harward's avatar Soren Harward
Browse files

Whole bunch of APG improvements and bugfixes

See ChangeLog for details

BUG: 283618
BUG: 293616
BUG: 294743
BUG: 301829
parent 6cb16f83
......@@ -4,6 +4,7 @@ Amarok ChangeLog
VERSION 2.7-Beta 1
FEATURES:
* New APG constraint: Specify a total file size for playlist. (BR 283618)
* Amazon store: Added support for Amazon MP3 in Italy and Spain. (BR 307981)
* Mark downloaded podcast episodes to keep, even when purge is enabled. (BR 261062)
* Nepomuk plugin: Play and manage tracks using the Nepomuk database.
......@@ -15,6 +16,9 @@ VERSION 2.7-Beta 1
* Amazon store: We now ship a utility to handle downloads from Amazon.
CHANGES:
* APG now saves its presets each time it's run, to lessen preset loss if
Amarok crashes. (BR 294743)
* APG playlists no longer limited to 100 tracks. (BR 301829)
* The confusing "Local Collection Backends" category of plugins was removed
from the Configure dialog. All backends are enabled from now on.
* Statistics of tracks outside of collections are only read/saved to file
......@@ -25,6 +29,9 @@ VERSION 2.7-Beta 1
* New optional dependency for Amazon downloads: clamz.
BUGFIXES:
* Fixed some incorrect logic in the PlaylistLength constraint, which was
causing the APG to create playlists that were shorter than expected.
(BR 293616)
* Improve Duplicate files found dialog. (BR 308762)
* Fix crashes in SqlRegistry because of its false thread-safety. (BR 230991)
* Fix crash on malformed DAAP reply. (BR 284186)
......
......@@ -513,6 +513,7 @@ set(apg_SRCS
playlistgenerator/constraints/Checkpoint.cpp
playlistgenerator/constraints/Matching.cpp
playlistgenerator/constraints/PlaylistDuration.cpp
playlistgenerator/constraints/PlaylistFileSize.cpp
playlistgenerator/constraints/PlaylistLength.cpp
playlistgenerator/constraints/PreventDuplicates.cpp
playlistgenerator/constraints/TagMatch.cpp
......@@ -525,6 +526,7 @@ kde4_add_ui_files(apg_SRCS
playlistgenerator/PresetEditDialog.ui
playlistgenerator/constraints/CheckpointEditWidget.ui
playlistgenerator/constraints/PlaylistDurationEditWidget.ui
playlistgenerator/constraints/PlaylistFileSizeEditWidget.ui
playlistgenerator/constraints/PlaylistLengthEditWidget.ui
playlistgenerator/constraints/PreventDuplicatesEditWidget.ui
playlistgenerator/constraints/TagMatchEditWidget.ui
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -147,5 +147,6 @@ PlaylistBrowserNS::APGCategory::setQualityFactor( int f )
void
PlaylistBrowserNS::APGCategory::runGenerator()
{
APG::PresetModel::instance()->savePresetsToXml();
APG::PresetModel::instance()->runGenerator( m_qualityFactor );
}
/****************************************************************************************
* Copyright (c) 2008-2010 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -22,6 +22,7 @@
#include "ConstraintNode.h"
#include "constraints/Checkpoint.h"
#include "constraints/PlaylistDuration.h"
#include "constraints/PlaylistFileSize.h"
#include "constraints/PlaylistLength.h"
#include "constraints/PreventDuplicates.h"
#include "constraints/TagMatch.h"
......@@ -99,6 +100,11 @@ ConstraintFactory::ConstraintFactory()
m_registryNames[r->m_name] = r;
m_registryUntranslateNames[r->m_i18nName] = r->m_name;
r = ConstraintTypes::PlaylistFileSize::registerMe();
m_registryIds[5] = r;
m_registryNames[r->m_name] = r;
m_registryUntranslateNames[r->m_i18nName] = r->m_name;
// ADD NEW CONSTRAINT TYPES HERE FOLLOWING SAME PATTERN (DON'T FORGET TO INCREMENT ID)
}
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -198,12 +198,12 @@ ConstraintGroup::satisfaction( const Meta::TrackList& l ) const
}
quint32
ConstraintGroup::suggestInitialPlaylistSize() const
ConstraintGroup::suggestPlaylistSize() const
{
quint32 s = 0;
quint32 c = 0;
foreach( ConstraintNode* child, m_children ) {
quint32 x = child->suggestInitialPlaylistSize();
quint32 x = child->suggestPlaylistSize();
if ( x > 0 ) {
s += x;
c++;
......@@ -216,16 +216,6 @@ ConstraintGroup::suggestInitialPlaylistSize() const
}
}
#ifndef KDE_NO_DEBUG_OUTPUT
void
ConstraintGroup::audit( const Meta::TrackList& tl ) const
{
foreach( ConstraintNode* child, m_children ) {
child->audit( tl );
}
}
#endif
double
ConstraintGroup::combineInterdependentConstraints( const Meta::TrackList& l, const double s, const QHash<int,int>& cmt ) const
{
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -50,11 +50,7 @@ class ConstraintGroup : public ConstraintNode {
virtual Collections::QueryMaker* initQueryMaker( Collections::QueryMaker* ) const;
virtual double satisfaction( const Meta::TrackList& ) const;
virtual quint32 suggestInitialPlaylistSize() const;
#ifndef KDE_NO_DEBUG_OUTPUT
virtual void audit(const Meta::TrackList&) const;
#endif
virtual quint32 suggestPlaylistSize() const;
private slots:
void setMatchAny();
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -113,7 +113,7 @@ ConstraintNode::where_is( const ConstraintNode* n ) const
}
quint32
ConstraintNode::suggestInitialPlaylistSize() const
ConstraintNode::suggestPlaylistSize() const
{
return 0;
}
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -80,11 +80,7 @@ class ConstraintNode : public QObject {
virtual double satisfaction( const Meta::TrackList& ) const = 0;
// heuristic functions for the ConstraintSolver
virtual quint32 suggestInitialPlaylistSize() const;
#ifndef KDE_NO_DEBUG_OUTPUT
virtual void audit(const Meta::TrackList&) const {}
#endif
virtual quint32 suggestPlaylistSize() const;
signals:
void dataChanged();
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -50,9 +50,7 @@ APG::ConstraintSolver::ConstraintSolver( ConstraintNode* r, int qualityFactor )
, m_abortRequested( false )
, m_maxGenerations( 100 )
, m_populationSize( 40 )
, m_minPlaylistSize( 4 )
, m_suggestedPlaylistSize( 15 )
, m_maxPlaylistSize( 100 )
{
Q_UNUSED( qualityFactor); // FIXME
......@@ -149,11 +147,6 @@ APG::ConstraintSolver::run()
debug() << "Running ConstraintSolver" << m_serialNumber;
quint32 sips = m_constraintTreeRoot->suggestInitialPlaylistSize();
if ( ( sips >= m_minPlaylistSize ) && ( sips <= m_maxPlaylistSize ) ) {
m_suggestedPlaylistSize = sips;
}
emit totalSteps( m_maxGenerations );
// GENETIC ALGORITHM LOOP
......@@ -161,6 +154,7 @@ APG::ConstraintSolver::run()
quint32 generation = 0;
Meta::TrackList* best = NULL;
while ( !m_abortRequested && ( generation < m_maxGenerations ) ) {
m_suggestedPlaylistSize = m_constraintTreeRoot->suggestPlaylistSize();
fill_population( population );
best = find_best( population );
if ( population.value( best ) < m_satisfactionThreshold ) {
......@@ -177,10 +171,6 @@ APG::ConstraintSolver::run()
m_solvedPlaylist = best->mid( 0 );
m_finalSatisfaction = m_constraintTreeRoot->satisfaction( m_solvedPlaylist );
#ifndef KDE_NO_DEBUG_OUTPUT
m_constraintTreeRoot->audit( m_solvedPlaylist );
#endif
/* clean up */
Population::iterator it = population.begin();
while ( it != population.end() ) {
......@@ -337,11 +327,7 @@ APG::ConstraintSolver::sample( Meta::TrackList domain, const int sampleSize ) co
quint32
APG::ConstraintSolver::playlist_size() const
{
quint32 size = 0;
do {
size = rng_poisson( (double)m_suggestedPlaylistSize );
} while ( ( size < m_minPlaylistSize ) || ( size > m_maxPlaylistSize ) );
return size;
return rng_poisson( (double)m_suggestedPlaylistSize );
}
bool
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -106,9 +106,7 @@ namespace APG {
// internal mathematical parameters
quint32 m_maxGenerations;
quint32 m_populationSize;
quint32 m_minPlaylistSize;
quint32 m_suggestedPlaylistSize;
quint32 m_maxPlaylistSize;
};
} // namespace APG
......
/****************************************************************************************
* Copyright (c) 2008-2010 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -191,6 +191,12 @@ APG::PresetModel::setActivePreset( const QModelIndex& index )
m_activePresetIndex = new QPersistentModelIndex( index );
}
void
APG::PresetModel::savePresetsToXml() const
{
savePresetsToXml( Amarok::saveLocation() + "playlistgenerator.xml", m_presetList );
}
void
APG::PresetModel::savePresetsToXml( const QString& filename, const QList<APG::PresetPtr> &pl ) const
{
......
/****************************************************************************************
* Copyright (c) 2008-2010 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -60,6 +60,7 @@ namespace APG {
void removeActive();
void runGenerator( int );
void setActivePreset( const QModelIndex& );
void savePresetsToXml() const; // force saving to default location
private slots:
void savePresetsToXml( const QString&, const QList<APG::PresetPtr> & ) const;
......
Backend:
- make the QualityFactor in the ConstraintSolver work again
- replace values in constraints with Qt properties, and use properties for saving/loading
from XML, and put XML in Constraint superclass
- replace values in constraints with Qt properties, and use properties for
saving/loading from XML, and put XML in Constraint superclass
- collection-specific heuristics for playlist size estimation in
PlaylistDuration and PlaylistSize constraints
Constraints:
- last.fm or echonest similar artists constraint
- specify file size of playlist (BR 283618)
GUI:
- context menu for APGCategory
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -25,11 +25,8 @@
#include "core/support/Debug.h"
#include "core-impl/collections/support/CollectionManager.h"
#include <KRandom>
#include <KUrl>
#include <QtGlobal>
#include <algorithm>
#include <climits>
#include <math.h>
......@@ -70,7 +67,6 @@ ConstraintTypes::Checkpoint::Checkpoint( QDomElement& xmlelem, ConstraintNode* p
, m_checkpointType( CheckpointTrack )
, m_matcher( 0 )
{
DEBUG_BLOCK
QDomAttr a;
a = xmlelem.attributeNode( "position" );
......@@ -93,7 +89,6 @@ ConstraintTypes::Checkpoint::Checkpoint( QDomElement& xmlelem, ConstraintNode* p
} else {
m_checkpointObject = Meta::DataPtr::dynamicCast( trk );
}
debug() << "loaded" << m_checkpointObject->prettyName() << "from XML";
}
}
......@@ -112,8 +107,6 @@ ConstraintTypes::Checkpoint::Checkpoint( ConstraintNode* p )
, m_checkpointType( CheckpointTrack )
, m_matcher( 0 )
{
DEBUG_BLOCK
debug() << "new default Checkpoint";
}
ConstraintTypes::Checkpoint::~Checkpoint()
......@@ -263,28 +256,11 @@ ConstraintTypes::Checkpoint::penalty( const qint64 d ) const
}
quint32
ConstraintTypes::Checkpoint::suggestInitialPlaylistSize() const
ConstraintTypes::Checkpoint::suggestPlaylistSize() const
{
return static_cast<quint32>( m_position / 300000 ) + 1;
}
void
ConstraintTypes::Checkpoint::audit( const Meta::TrackList& tl ) const
{
qint64 position = 0;
foreach ( Meta::TrackPtr t, tl ) {
qint64 start = position;
qint64 end = ( position += t->length() );
QStringList out;
out << t->prettyName();
if ( m_matcher->match( t ) )
out << "MATCHES";
if ( ( start <= m_position ) && ( end >= m_position ) )
out << "[checkpoint is here]";
debug() << out.join(" ");
}
}
void
ConstraintTypes::Checkpoint::setPosition( const int v )
{
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -50,9 +50,7 @@ namespace ConstraintTypes {
virtual QString getName() const;
virtual double satisfaction( const Meta::TrackList& ) const;
virtual quint32 suggestInitialPlaylistSize() const;
virtual void audit( const Meta::TrackList& ) const;
virtual quint32 suggestPlaylistSize() const;
private slots:
void setPosition( const int );
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -21,12 +21,6 @@
#include "playlistgenerator/Constraint.h"
#include "playlistgenerator/ConstraintFactory.h"
#include "core/support/Debug.h"
#include <KRandom>
#include <QtGlobal>
#include <stdlib.h>
#include <math.h>
......@@ -61,8 +55,10 @@ ConstraintTypes::PlaylistDuration::registerMe()
ConstraintTypes::PlaylistDuration::PlaylistDuration( QDomElement& xmlelem, ConstraintNode* p )
: Constraint( p )
, m_duration( 0 )
, m_comparison( CompareNumEquals )
, m_strictness( 1.0 )
{
DEBUG_BLOCK
QDomAttr a;
a = xmlelem.attributeNode( "duration" );
......@@ -83,8 +79,6 @@ ConstraintTypes::PlaylistDuration::PlaylistDuration( QDomElement& xmlelem, Const
a = xmlelem.attributeNode( "strictness" );
if ( !a.isNull() )
m_strictness = a.value().toDouble();
debug() << getName();
}
ConstraintTypes::PlaylistDuration::PlaylistDuration( ConstraintNode* p )
......@@ -93,8 +87,6 @@ ConstraintTypes::PlaylistDuration::PlaylistDuration( ConstraintNode* p )
, m_comparison( CompareNumEquals )
, m_strictness( 1.0 )
{
DEBUG_BLOCK
debug() << "new default PlaylistLength";
}
QWidget*
......@@ -146,7 +138,7 @@ ConstraintTypes::PlaylistDuration::satisfaction( const Meta::TrackList& tl ) con
}
quint32
ConstraintTypes::PlaylistDuration::suggestInitialPlaylistSize() const
ConstraintTypes::PlaylistDuration::suggestPlaylistSize() const
{
if ( m_comparison == CompareNumLessThan ) {
return static_cast<quint32>( m_duration ) / 300000 ;
......
/****************************************************************************************
* Copyright (c) 2008-2011 Soren Harward <stharward@gmail.com> *
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 *
......@@ -47,7 +47,7 @@ namespace ConstraintTypes {
virtual QString getName() const;
virtual double satisfaction(const Meta::TrackList&) const;
virtual quint32 suggestInitialPlaylistSize() const;
virtual quint32 suggestPlaylistSize() const;
private slots:
void setComparison( const int );
......
/****************************************************************************************
* Copyright (c) 2008-2012 Soren Harward <stharward@gmail.com> *
* *
* This program 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 2 of the License, or (at your option) any later *
* version. *
* *
* This program 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 *
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
#define DEBUG_PREFIX "Constraint::PlaylistFileSize"
#include "PlaylistFileSize.h"
#include "playlistgenerator/Constraint.h"
#include "playlistgenerator/ConstraintFactory.h"
#include <stdlib.h>
#include <math.h>
Constraint*
ConstraintTypes::PlaylistFileSize::createFromXml( QDomElement& xmlelem, ConstraintNode* p )
{
if ( p ) {
return new PlaylistFileSize( xmlelem, p );
} else {
return 0;
}
}
Constraint*
ConstraintTypes::PlaylistFileSize::createNew( ConstraintNode* p )
{
if ( p ) {
return new PlaylistFileSize( p );
} else {
return 0;
}
}
ConstraintFactoryEntry*
ConstraintTypes::PlaylistFileSize::registerMe()
{
return new ConstraintFactoryEntry( "PlaylistFileSize",
i18n("Playlist Total File Size"),
i18n("Sets the preferred total file size of the playlist"),
&PlaylistFileSize::createFromXml, &PlaylistFileSize::createNew );
}
ConstraintTypes::PlaylistFileSize::PlaylistFileSize( QDomElement& xmlelem, ConstraintNode* p )
: Constraint( p )
, m_size( 700 )
, m_unit( 1 )
, m_comparison( CompareNumEquals )
, m_strictness( 1.0 )
{
QDomAttr a;
a = xmlelem.attributeNode( "size" );
if ( !a.isNull() )
m_size = a.value().toInt();
a = xmlelem.attributeNode( "unit" );
if ( !a.isNull() )
m_unit = a.value().toInt();
a = xmlelem.attributeNode( "comparison" );
if ( !a.isNull() )
m_comparison = a.value().toInt();
a = xmlelem.attributeNode( "strictness" );
if ( !a.isNull() )
m_strictness = a.value().toDouble();
}
ConstraintTypes::PlaylistFileSize::PlaylistFileSize( ConstraintNode* p )
: Constraint( p )
, m_size( 700 )
, m_unit( 1 )
, m_comparison( CompareNumEquals )
, m_strictness( 1.0 )
{
}
QWidget*
ConstraintTypes::PlaylistFileSize::editWidget() const
{
PlaylistFileSizeEditWidget* e = new PlaylistFileSizeEditWidget( m_size, m_unit, m_comparison, static_cast<int>( 10*m_strictness ) );
connect( e, SIGNAL( comparisonChanged( const int ) ), this, SLOT( setComparison( const int ) ) );
connect( e, SIGNAL( sizeChanged( const int ) ), this, SLOT( setSize( const int ) ) );
connect( e, SIGNAL( unitChanged( const int ) ), this, SLOT( setUnit( const int ) ) );
connect( e, SIGNAL( strictnessChanged( const int ) ), this, SLOT( setStrictness( const int ) ) );
return e;
}
void
ConstraintTypes::PlaylistFileSize::toXml( QDomDocument& doc, QDomElement& elem ) const
{
QDomElement c = doc.createElement( "constraint" );
c.setAttribute( "type", "PlaylistFileSize" );
c.setAttribute( "size", QString::number( m_size ) );
c.setAttribute( "unit", QString::number( m_unit ) );
c.setAttribute( "comparison", QString::number( m_comparison ) );
c.setAttribute( "strictness", QString::number( m_strictness ) );
elem.appendChild( c );
}
QString
ConstraintTypes::PlaylistFileSize::getName() const
{
QString v( i18nc( "%2 is e.g. 'more than' or 'less than' or 'equals'; %3 is e.g. 'KB' (kilobytes) or 'MB' or 'GB' or 'TB'",
"Playlist FileSize: %2 %1 %3",
m_size, comparisonToString(), unitToString() ) );
return v;
}
double
ConstraintTypes::PlaylistFileSize::satisfaction( const Meta::TrackList& tl ) const
{
quint64 tlSize = 0;
foreach ( const Meta::TrackPtr t, tl ) {
// Boy it sure would be nice if Qt had a "reduce" function built in
tlSize += static_cast<quint64>( t->filesize() );
}
quint64 wantedSize = getWantedSize();