mirror of
https://github.com/tomahawk-player/tomahawk.git
synced 2025-03-20 07:49:42 +01:00
Handle catalogs more gracefully in dynamic playlists
Standardize some code Propertify Misc catalog fixes Clean up by hacking
This commit is contained in:
parent
5f9c21120d
commit
625dc0304b
@ -369,5 +369,12 @@ EchonestCatalogSynchronizer::trackAttributes( PairList attributes )
|
||||
QByteArray
|
||||
EchonestCatalogSynchronizer::escape( const QString &in ) const
|
||||
{
|
||||
return QUrl::toPercentEncoding( in );
|
||||
// TODO echonest chokes on some chars in the output. But if we percent-encode those chars it works
|
||||
// We can't percent-encode the whole string, because then any UTF-8 chars that have been url-encoded, fail.
|
||||
// God this sucks. It's going to break...
|
||||
QString clean = in;
|
||||
clean.replace( "&", "%25" );
|
||||
clean.replace( ";", "%3B" );
|
||||
return clean.toUtf8();
|
||||
//return QUrl::toPercentEncoding( in. );
|
||||
}
|
||||
|
@ -50,6 +50,7 @@ public:
|
||||
Echonest::Catalog artistCatalog() const { return m_artistCatalog; }
|
||||
|
||||
signals:
|
||||
void knownCatalogsChanged();
|
||||
|
||||
private slots:
|
||||
void checkSettingsChanged();
|
||||
@ -83,6 +84,8 @@ private:
|
||||
QQueue< QList< QPair< QID, QString > > > m_queuedTrackInfo;
|
||||
|
||||
static EchonestCatalogSynchronizer* s_instance;
|
||||
|
||||
friend class ::DatabaseCommand_SetCollectionAttributes;
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "source.h"
|
||||
#include "network/servent.h"
|
||||
#include "sourcelist.h"
|
||||
#include "EchonestCatalogSynchronizer.h"
|
||||
|
||||
DatabaseCommand_SetCollectionAttributes::DatabaseCommand_SetCollectionAttributes( AttributeType type, const QByteArray& id )
|
||||
: DatabaseCommandLoggable( )
|
||||
@ -72,5 +73,10 @@ DatabaseCommand_SetCollectionAttributes::exec( DatabaseImpl *lib )
|
||||
void
|
||||
DatabaseCommand_SetCollectionAttributes::postCommitHook()
|
||||
{
|
||||
Servent::instance()->triggerDBSync();
|
||||
if ( m_type == EchonestSongCatalog ||
|
||||
m_type == EchonestArtistCatalog )
|
||||
Tomahawk::EchonestCatalogSynchronizer::instance()->knownCatalogsChanged();
|
||||
|
||||
if ( source()->isLocal() )
|
||||
Servent::instance()->triggerDBSync();
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ class DatabaseCommand_SetCollectionAttributes : public DatabaseCommandLoggable
|
||||
Q_OBJECT
|
||||
Q_PROPERTY( QByteArray id READ id WRITE setId )
|
||||
Q_PROPERTY( int type READ type WRITE setType )
|
||||
Q_PROPERTY( bool del READ del WRITE setDel )
|
||||
|
||||
public:
|
||||
enum AttributeType {
|
||||
@ -38,8 +39,7 @@ public:
|
||||
DatabaseCommand_SetCollectionAttributes( AttributeType type, const QByteArray& id );
|
||||
// Delete all attributes for the source+type
|
||||
DatabaseCommand_SetCollectionAttributes( AttributeType type, bool toDelete );
|
||||
|
||||
DatabaseCommand_SetCollectionAttributes() {} // JSON
|
||||
DatabaseCommand_SetCollectionAttributes() : m_delete( false ) {} // JSON
|
||||
virtual void exec( DatabaseImpl* lib );
|
||||
virtual bool doesMutates() const { return true; }
|
||||
virtual void postCommitHook();
|
||||
@ -52,6 +52,8 @@ public:
|
||||
void setType( int type ) { m_type = (AttributeType)type; }
|
||||
int type() const { return (int)m_type; }
|
||||
|
||||
void setDel( bool del ) { m_delete = del; }
|
||||
bool del() const { return m_delete; }
|
||||
private:
|
||||
bool m_delete;
|
||||
AttributeType m_type;
|
||||
|
@ -29,6 +29,7 @@
|
||||
#include "EchonestGenerator.h"
|
||||
|
||||
#include "utils/logger.h"
|
||||
#include <sourcelist.h>
|
||||
|
||||
|
||||
QHash< QString, QStringList > Tomahawk::EchonestControl::s_suggestCache = QHash< QString, QStringList >();
|
||||
@ -198,7 +199,7 @@ Tomahawk::EchonestControl::updateWidgets()
|
||||
input->hide();
|
||||
m_match = QWeakPointer< QWidget >( match );
|
||||
m_input = QWeakPointer< QWidget >( input );
|
||||
} else if( selectedType() == "Catalog Radio" ) {
|
||||
} else if( selectedType() == "User Radio" ) {
|
||||
m_currentType = Echonest::DynamicPlaylist::SourceCatalog;
|
||||
|
||||
QLabel* match = new QLabel( tr( "from user" ) );
|
||||
@ -209,6 +210,12 @@ Tomahawk::EchonestControl::updateWidgets()
|
||||
combo->addItem( str, EchonestGenerator::catalogId( str ) );
|
||||
}
|
||||
|
||||
if ( EchonestGenerator::userCatalogs().isEmpty() )
|
||||
combo->addItem( tr( "No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings" ) );
|
||||
|
||||
if ( combo->findData( m_data.second ) < 0 )
|
||||
combo->setCurrentIndex( 0 );
|
||||
|
||||
m_matchString = match->text();
|
||||
m_matchData = match->text();
|
||||
|
||||
@ -493,7 +500,7 @@ Tomahawk::EchonestControl::updateData()
|
||||
updateFromComboAndSlider();
|
||||
} else if( selectedType() == "Danceability" || selectedType() == "Energy" || selectedType() == "Artist Familiarity" || selectedType() == "Artist Hotttnesss" || selectedType() == "Song Hotttnesss" ) {
|
||||
updateFromComboAndSlider( true );
|
||||
} else if( selectedType() == "Mode" || selectedType() == "Key" || selectedType() == "Mood" || selectedType() == "Style" || selectedType() == "Catalog Radio" ) {
|
||||
} else if( selectedType() == "Mode" || selectedType() == "Key" || selectedType() == "Mood" || selectedType() == "Style" || selectedType() == "User Radio" ) {
|
||||
updateFromLabelAndCombo();
|
||||
} else if( selectedType() == "Sorting" ) {
|
||||
QComboBox* match = qobject_cast<QComboBox*>( m_match.data() );
|
||||
@ -556,6 +563,26 @@ Tomahawk::EchonestControl::updateWidgetsFromData()
|
||||
QLineEdit* edit = qobject_cast<QLineEdit*>( m_input.data() );
|
||||
if( edit )
|
||||
edit->setText( m_data.second.toString() );
|
||||
} else if ( selectedType() == "User Radio" )
|
||||
{
|
||||
QComboBox* combo = qobject_cast< QComboBox* >( m_input.data() );
|
||||
if ( combo )
|
||||
{
|
||||
combo->clear();
|
||||
|
||||
foreach( const QString& str, EchonestGenerator::userCatalogs() )
|
||||
{
|
||||
combo->addItem( str, EchonestGenerator::catalogId( str ) );
|
||||
}
|
||||
|
||||
if ( EchonestGenerator::userCatalogs().isEmpty() )
|
||||
combo->addItem( tr( "No users with Echo Nest Catalogs enabled. Try enabling option in Collection settings" ) );
|
||||
|
||||
if ( combo->findData( m_data.second ) < 0 )
|
||||
combo->setCurrentIndex( 0 );
|
||||
|
||||
combo->setCurrentIndex( combo->findData( m_data.second ) );
|
||||
}
|
||||
} else if( selectedType() == "Variety" || selectedType() == "Adventurousness" ) {
|
||||
LabeledSlider* s = qobject_cast<LabeledSlider*>( m_input.data() );
|
||||
if( s )
|
||||
@ -564,7 +591,7 @@ Tomahawk::EchonestControl::updateWidgetsFromData()
|
||||
updateToComboAndSlider();
|
||||
} else if( selectedType() == "Danceability" || selectedType() == "Energy" || selectedType() == "Artist Familiarity" || selectedType() == "Artist Hotttnesss" || selectedType() == "Song Hotttnesss" ) {
|
||||
updateToComboAndSlider( true );
|
||||
} else if( selectedType() == "Mode" || selectedType() == "Key" || selectedType() == "Mood" || selectedType() == "Style" || selectedType() == "Catalog Radio" ) {
|
||||
} else if( selectedType() == "Mode" || selectedType() == "Key" || selectedType() == "Mood" || selectedType() == "Style") {
|
||||
updateToLabelAndCombo();
|
||||
} else if( selectedType() == "Sorting" ) {
|
||||
QComboBox* match = qobject_cast<QComboBox*>( m_match.data() );
|
||||
@ -714,6 +741,24 @@ Tomahawk::EchonestControl::calculateSummary()
|
||||
summary = QString( "similar to ~%1" ).arg( m_data.second.toString() );
|
||||
} else if( selectedType() == "Artist Description" ) {
|
||||
summary = QString( "with genre ~%1" ).arg( m_data.second.toString() );
|
||||
} else if( selectedType() == "User Radio" ) {
|
||||
QComboBox* b = qobject_cast< QComboBox* >( m_input.data() );
|
||||
if ( b )
|
||||
{
|
||||
if ( b->currentText().isEmpty() || b->itemData( b->currentIndex() ).isNull() )
|
||||
summary = "from no one";
|
||||
else
|
||||
{
|
||||
QString subSum;
|
||||
if ( b->currentText() == "My Collection" )
|
||||
subSum = "my";
|
||||
else
|
||||
subSum = b->currentText();
|
||||
summary = QString( "from %1 radio" ).arg( subSum );
|
||||
}
|
||||
}
|
||||
else
|
||||
summary = "from no one";
|
||||
} else if( selectedType() == "Artist Description" || selectedType() == "Song" ) {
|
||||
summary = QString( "similar to ~%1" ).arg( m_data.second.toString() );
|
||||
} else if( selectedType() == "Variety" || selectedType() == "Danceability" || selectedType() == "Artist Hotttnesss" || selectedType() == "Energy" || selectedType() == "Artist Familiarity" || selectedType() == "Song Hotttnesss" ) {
|
||||
|
@ -22,6 +22,7 @@
|
||||
#include <echonest/Playlist.h>
|
||||
|
||||
#include "dynamic/DynamicControl.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
namespace Tomahawk
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "sourcelist.h"
|
||||
#include <QFile>
|
||||
#include <QDir>
|
||||
#include <EchonestCatalogSynchronizer.h>
|
||||
|
||||
using namespace Tomahawk;
|
||||
|
||||
@ -37,8 +38,7 @@ QStringList EchonestGenerator::s_styles = QStringList();
|
||||
QNetworkReply* EchonestGenerator::s_moodsJob = 0;
|
||||
QNetworkReply* EchonestGenerator::s_stylesJob = 0;
|
||||
|
||||
bool EchonestGenerator::s_catalogsFetched = false;
|
||||
QHash< QString, QString > EchonestGenerator::s_catalogs = QHash< QString, QString >();
|
||||
CatalogManager* EchonestGenerator::s_catalogs = 0;
|
||||
|
||||
|
||||
EchonestFactory::EchonestFactory()
|
||||
@ -63,18 +63,54 @@ EchonestFactory::createControl( const QString& controlType )
|
||||
QStringList
|
||||
EchonestFactory::typeSelectors() const
|
||||
{
|
||||
QStringList types = QStringList() << "Artist" << "Artist Description" << "Song" << "Mood" << "Style" << "Variety" << "Tempo" << "Duration" << "Loudness"
|
||||
QStringList types = QStringList() << "Artist" << "Artist Description" << "User Radio" << "Song" << "Mood" << "Style" << "Variety" << "Tempo" << "Duration" << "Loudness"
|
||||
<< "Danceability" << "Energy" << "Artist Familiarity" << "Artist Hotttnesss" << "Song Hotttnesss"
|
||||
<< "Longitude" << "Latitude" << "Mode" << "Key" << "Sorting";
|
||||
|
||||
if ( TomahawkSettings::instance()->enableEchonestCatalogs() )
|
||||
{
|
||||
types.insert( 2, "Catalog Radio" );
|
||||
types.insert( 3, "Adventurousness" );
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
CatalogManager::CatalogManager( QObject* parent )
|
||||
: QObject( parent )
|
||||
{
|
||||
connect( EchonestCatalogSynchronizer::instance(), SIGNAL( knownCatalogsChanged() ), this, SLOT( doCatalogUpdate() ) );
|
||||
connect( SourceList::instance(), SIGNAL( ready() ), this, SLOT( doCatalogUpdate() ) );
|
||||
|
||||
doCatalogUpdate();
|
||||
}
|
||||
|
||||
void
|
||||
CatalogManager::collectionAttributes( const PairList& data )
|
||||
{
|
||||
QPair<QString, QString> part;
|
||||
m_catalogs.clear();
|
||||
|
||||
foreach ( part, data )
|
||||
{
|
||||
if ( SourceList::instance()->get( part.first.toInt() ).isNull() )
|
||||
continue;
|
||||
|
||||
const QString name = SourceList::instance()->get( part.first.toInt() )->friendlyName();
|
||||
m_catalogs.insert( name, part.second );
|
||||
}
|
||||
|
||||
emit catalogsUpdated();
|
||||
}
|
||||
|
||||
void
|
||||
CatalogManager::doCatalogUpdate()
|
||||
{
|
||||
QSharedPointer< DatabaseCommand > cmd( new DatabaseCommand_CollectionAttributes( DatabaseCommand_SetCollectionAttributes::EchonestSongCatalog ) );
|
||||
connect( cmd.data(), SIGNAL( collectionAttributes( PairList ) ), this, SLOT( collectionAttributes( PairList ) ) );
|
||||
Database::instance()->enqueue( cmd );
|
||||
}
|
||||
|
||||
QHash< QString, QString >
|
||||
CatalogManager::catalogs() const
|
||||
{
|
||||
return m_catalogs;
|
||||
}
|
||||
|
||||
|
||||
EchonestGenerator::EchonestGenerator ( QObject* parent )
|
||||
: GeneratorInterface ( parent )
|
||||
@ -86,17 +122,13 @@ EchonestGenerator::EchonestGenerator ( QObject* parent )
|
||||
m_logo.load( RESPATH "/images/echonest_logo.png" );
|
||||
|
||||
loadStylesAndMoods();
|
||||
if ( s_catalogs.isEmpty() && TomahawkSettings::instance()->enableEchonestCatalogs() )
|
||||
{
|
||||
if ( !s_catalogsFetched )
|
||||
{
|
||||
QSharedPointer< DatabaseCommand > cmd( new DatabaseCommand_CollectionAttributes( DatabaseCommand_SetCollectionAttributes::EchonestSongCatalog ) );
|
||||
connect( cmd.data(), SIGNAL(collectionAttributes(PairList)),
|
||||
this, SLOT(collectionAttributes(PairList) ) );
|
||||
Database::instance()->enqueue( cmd );
|
||||
s_catalogsFetched = true;
|
||||
}
|
||||
}
|
||||
|
||||
// TODO Yes this is a race condition. If multiple threads initialize echonestgenerator at the exact same time we could run into some issues.
|
||||
// not dealing with that right now.
|
||||
if ( s_catalogs == 0 )
|
||||
s_catalogs = new CatalogManager( this );
|
||||
|
||||
connect( s_catalogs, SIGNAL( catalogsUpdated() ), this, SLOT( knownCatalogsChanged() ) );
|
||||
// qDebug() << "ECHONEST:" << m_logo.size();
|
||||
}
|
||||
|
||||
@ -120,6 +152,16 @@ QPixmap EchonestGenerator::logo()
|
||||
return m_logo;
|
||||
}
|
||||
|
||||
void
|
||||
EchonestGenerator::knownCatalogsChanged()
|
||||
{
|
||||
// Refresh all contrls
|
||||
foreach( const dyncontrol_ptr& control, m_controls )
|
||||
{
|
||||
control.staticCast< EchonestControl >()->updateWidgetsFromData();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
EchonestGenerator::generate( int number )
|
||||
@ -381,30 +423,17 @@ EchonestGenerator::resetSteering()
|
||||
m_steerData.second = QString();
|
||||
}
|
||||
|
||||
void
|
||||
EchonestGenerator::collectionAttributes(PairList data)
|
||||
{
|
||||
QPair<QString, QString> part;
|
||||
foreach ( part, data )
|
||||
{
|
||||
if ( SourceList::instance()->get( part.first.toInt() ).isNull() )
|
||||
continue;
|
||||
|
||||
const QString name = SourceList::instance()->get( part.first.toInt() )->friendlyName();
|
||||
s_catalogs.insert( name, part.second );
|
||||
}
|
||||
}
|
||||
|
||||
QByteArray
|
||||
EchonestGenerator::catalogId(const QString &collectionId)
|
||||
{
|
||||
return s_catalogs.value( collectionId ).toUtf8();
|
||||
return s_catalogs->catalogs().value( collectionId ).toUtf8();
|
||||
}
|
||||
|
||||
QStringList
|
||||
EchonestGenerator::userCatalogs()
|
||||
{
|
||||
return s_catalogs.keys();
|
||||
return s_catalogs->catalogs().keys();
|
||||
}
|
||||
|
||||
bool
|
||||
@ -446,7 +475,7 @@ EchonestGenerator::appendRadioType( Echonest::DynamicPlaylist::PlaylistParams& p
|
||||
/// 5. song-radio: If all the artist entries are Similar To. If some were but not all, error out.
|
||||
bool someCatalog = false;
|
||||
foreach( const dyncontrol_ptr& control, m_controls ) {
|
||||
if ( control->selectedType() == "Catalog Radio" )
|
||||
if ( control->selectedType() == "User Radio" )
|
||||
someCatalog = true;
|
||||
}
|
||||
if( someCatalog )
|
||||
|
@ -34,6 +34,25 @@ namespace Tomahawk
|
||||
|
||||
class EchonestSteerer;
|
||||
|
||||
class CatalogManager : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
CatalogManager( QObject* parent );
|
||||
|
||||
QHash< QString, QString > catalogs() const;
|
||||
|
||||
signals:
|
||||
void catalogsUpdated();
|
||||
|
||||
private slots:
|
||||
void doCatalogUpdate();
|
||||
void collectionAttributes( const PairList& );
|
||||
|
||||
private:
|
||||
QHash< QString, QString > m_catalogs;
|
||||
};
|
||||
|
||||
class DLLEXPORT EchonestFactory : public GeneratorFactoryInterface
|
||||
{
|
||||
public:
|
||||
@ -83,7 +102,7 @@ private slots:
|
||||
|
||||
void stylesReceived();
|
||||
void moodsReceived();
|
||||
void collectionAttributes(PairList);
|
||||
void knownCatalogsChanged();
|
||||
|
||||
void songLookupFinished();
|
||||
private:
|
||||
@ -105,8 +124,7 @@ private:
|
||||
static QNetworkReply* s_stylesJob;
|
||||
static QNetworkReply* s_moodsJob;
|
||||
|
||||
static bool s_catalogsFetched;
|
||||
static QHash< QString, QString > s_catalogs;
|
||||
static CatalogManager* s_catalogs;
|
||||
|
||||
// used for the intermediary song id lookup
|
||||
QSet< QNetworkReply* > m_waiting;
|
||||
|
Loading…
x
Reference in New Issue
Block a user