File indexing completed on 2024-05-19 04:50:13

0001 /****************************************************************************************
0002  * Copyright (c) 2007 Nikolaj Hald Nielsen <nhn@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 "JamendoService.h"
0018 
0019 #include "browsers/CollectionTreeItem.h"
0020 #include "browsers/CollectionTreeView.h"
0021 #include "browsers/SingleCollectionTreeItemModel.h"
0022 #include "core-impl/collections/support/CollectionManager.h"
0023 #include "core/support/Debug.h"
0024 #include "core/support/Components.h"
0025 #include "core/logger/Logger.h"
0026 #include "EngineController.h"
0027 #include "JamendoInfoParser.h"
0028 #include "ServiceSqlRegistry.h"
0029 #include "widgets/SearchWidget.h"
0030 
0031 #include <QAction>
0032 #include <QDesktopServices>
0033 #include <QHBoxLayout>
0034 #include <QMenuBar>
0035 #include <QStandardPaths>
0036 #include <QTemporaryFile>
0037 #include <QToolBar>
0038 #include <QToolButton>
0039 
0040 #include <KPluginFactory>
0041 #include <KShell>
0042 #include <ThreadWeaver/ThreadWeaver>
0043 
0044 using namespace Meta;
0045 
0046 
0047 JamendoServiceFactory::JamendoServiceFactory()
0048     : ServiceFactory()
0049 {
0050 }
0051 
0052 void JamendoServiceFactory::init()
0053 {
0054     ServiceBase* service = new JamendoService( this, "Jamendo.com" );
0055     m_initialized = true;
0056     emit newService( service );
0057 }
0058 
0059 QString
0060 JamendoServiceFactory::name()
0061 {
0062     return "Jamendo.com";
0063 }
0064 
0065 KConfigGroup
0066 JamendoServiceFactory::config()
0067 {
0068     return Amarok::config( "Service_Jamendo" );
0069 }
0070 
0071 JamendoService::JamendoService( JamendoServiceFactory* parent, const QString & name)
0072     : ServiceBase( name, parent )
0073     , m_currentAlbum( 0 )
0074     , m_xmlParser( 0 )
0075 {
0076     setShortDescription(  i18n( "An archive of free, Creative Commons licensed music" ) );
0077     setIcon( QIcon::fromTheme( "view-services-jamendo-amarok" ) );
0078 
0079     setLongDescription( i18n( "Jamendo.com puts artists and music lovers in touch with each other. The site allows artists to upload their own albums to share them with the world and users to download all of them for free. Listen to and download all Jamendo.com contents from within Amarok." ) );
0080 
0081     setImagePath( QStandardPaths::locate( QStandardPaths::GenericDataLocation, "amarok/images/hover_info_jamendo.png" ) );
0082 
0083     ServiceMetaFactory * metaFactory = new JamendoMetaFactory( "jamendo", this );
0084     ServiceSqlRegistry * registry = new ServiceSqlRegistry( metaFactory );
0085     m_collection = new Collections::ServiceSqlCollection( "jamendo", "Jamendo.com", metaFactory, registry );
0086     CollectionManager::instance()->addTrackProvider( m_collection );
0087     setServiceReady( true );
0088 }
0089 
0090 JamendoService::~JamendoService()
0091 {
0092     DEBUG_BLOCK
0093 
0094     if( m_collection )
0095     {
0096         CollectionManager::instance()->removeTrackProvider( m_collection );
0097         m_collection->deleteLater();
0098         m_collection = 0;
0099     }
0100 
0101     //if currently running, stop it or we will get crashes
0102     if( m_xmlParser ) {
0103         m_xmlParser->requestAbort();
0104         delete m_xmlParser;
0105         m_xmlParser = 0;
0106     }
0107 }
0108 
0109 void
0110 JamendoService::polish()
0111 {
0112     generateWidgetInfo();
0113     if ( m_polished )
0114         return;
0115 
0116     BoxWidget *bottomPanelLayout = new BoxWidget( false, m_bottomPanel );
0117 
0118     m_updateListButton = new QPushButton;
0119     m_updateListButton->setParent( bottomPanelLayout );
0120     m_updateListButton->setText( i18nc( "Fetch new information from the website", "Update" ) );
0121     m_updateListButton->setObjectName( "updateButton" );
0122     m_updateListButton->setIcon( QIcon::fromTheme( "view-refresh-amarok" ) );
0123 
0124     m_downloadButton = new QPushButton;
0125     m_downloadButton->setParent( bottomPanelLayout );
0126     m_downloadButton->setText( i18n( "Download" ) );
0127     m_downloadButton->setObjectName( "downloadButton" );
0128     m_downloadButton->setIcon( QIcon::fromTheme( "download-amarok" ) );
0129     m_downloadButton->setEnabled( false );
0130 
0131     connect( m_updateListButton, &QPushButton::clicked, this, &JamendoService::updateButtonClicked );
0132     connect( m_downloadButton, &QPushButton::clicked, this, &JamendoService::download );
0133 
0134     setInfoParser( new JamendoInfoParser() );
0135 
0136     QList<CategoryId::CatMenuId> levels;
0137     levels << CategoryId::Genre << CategoryId::Artist << CategoryId::Album;
0138 
0139     setModel( new SingleCollectionTreeItemModel( m_collection, levels ) );
0140 
0141     connect( static_cast<ServiceCollectionTreeView*>( m_contentView ), &ServiceCollectionTreeView::itemSelected,
0142              this, &JamendoService::itemSelected );
0143 
0144     QMenu *filterMenu = new QMenu( 0 );
0145 
0146 //     QAction *action = filterMenu->addAction( i18n("Artist") );
0147 //     connect( action, SIGNAL(triggered(bool)), SLOT(sortByArtist()) );
0148 // 
0149 //     action = filterMenu->addAction( i18n( "Artist / Album" ) );
0150 //     connect( action, SIGNAL(triggered(bool)), SLOT(sortByArtistAlbum()) );
0151 // 
0152 //     action = filterMenu->addAction( i18n( "Album" ) );
0153 //     connect( action, SIGNAL(triggered(bool)), SLOT(sortByAlbum()) );
0154 
0155     QAction *action = filterMenu->addAction( i18n( "Genre / Artist" ) );
0156     connect( action, &QAction::triggered, this, &JamendoService::sortByGenreArtist );
0157 
0158     action = filterMenu->addAction( i18n( "Genre / Artist / Album" ) );
0159     connect( action, &QAction::triggered, this, &JamendoService::sortByGenreArtistAlbum );
0160 
0161     QAction *filterMenuAction = new QAction( QIcon::fromTheme( "preferences-other" ), i18n( "Sort Options" ), this );
0162     filterMenuAction->setMenu( filterMenu );
0163 
0164     m_searchWidget->toolBar()->addSeparator();
0165     m_searchWidget->toolBar()->addAction( filterMenuAction );
0166 
0167     QToolButton *tbutton = qobject_cast< QToolButton* >( m_searchWidget->toolBar()->widgetForAction( filterMenuAction ) );
0168     if( tbutton )
0169         tbutton->setPopupMode( QToolButton::InstantPopup );
0170 
0171 //     m_menubar->show();
0172 
0173     m_polished = true;
0174 }
0175 
0176 void
0177 JamendoService::updateButtonClicked()
0178 {
0179     m_updateListButton->setEnabled( false );
0180 
0181     debug() << "JamendoService: start downloading xml file";
0182 
0183     QTemporaryFile tempFile;
0184 //     tempFile.setSuffix( ".gz" );
0185     tempFile.setAutoRemove( false );  //file will be removed in JamendoXmlParser
0186     if( !tempFile.open() )
0187         return; //error
0188     m_tempFileName = tempFile.fileName();
0189     m_listDownloadJob = KIO::file_copy(
0190                 /* Deprecated */ QUrl("http://imgjam.com/data/dbdump_artistalbumtrack.xml.gz"),
0191                 QUrl::fromLocalFile( m_tempFileName ), 0700 , KIO::HideProgressInfo | KIO::Overwrite );
0192 
0193     Amarok::Logger::newProgressOperation( m_listDownloadJob, i18n( "Downloading Jamendo.com database..." ), this, SLOT(listDownloadCancelled()) );
0194 
0195     connect( m_listDownloadJob, &KJob::result,
0196             this, &JamendoService::listDownloadComplete );
0197 }
0198 
0199 void
0200 JamendoService::listDownloadComplete(KJob * downloadJob)
0201 {
0202     if( downloadJob != m_listDownloadJob )
0203         return ; //not the right job, so let's ignore it
0204     debug() << "JamendoService: xml file download complete";
0205 
0206     m_listDownloadJob = 0;
0207     //testing
0208     if ( downloadJob->error() != 0 )
0209     {
0210         //TODO: error handling here
0211         m_updateListButton->setEnabled( true ); // otherwise button will remain inactive in case of error
0212         return;
0213     }
0214 
0215     Amarok::Logger::shortMessage( i18n( "Updating the local Jamendo database."  ) );
0216     debug() << "JamendoService: create xml parser";
0217 
0218     if( m_xmlParser == 0 )
0219         m_xmlParser = new JamendoXmlParser( m_tempFileName );
0220     connect( m_xmlParser, &JamendoXmlParser::doneParsing, this, &JamendoService::doneParsing );
0221 
0222     ThreadWeaver::Queue::instance()->enqueue( QSharedPointer<ThreadWeaver::Job>(m_xmlParser) );
0223     downloadJob->deleteLater();
0224 }
0225 
0226 void
0227 JamendoService::listDownloadCancelled()
0228 {
0229     m_listDownloadJob->kill();
0230     m_listDownloadJob = 0;
0231     debug() << "Aborted xml download";
0232 
0233     m_updateListButton->setEnabled( true );
0234 }
0235 
0236 void
0237 JamendoService::doneParsing()
0238 {
0239     debug() << "JamendoService: done parsing";
0240     m_updateListButton->setEnabled( true );
0241     // model->setGenre("All");
0242     //delete sender
0243     sender()->deleteLater();
0244     m_xmlParser = 0;
0245     m_collection->emitUpdated();
0246 }
0247 
0248 void
0249 JamendoService::itemSelected( CollectionTreeItem * selectedItem )
0250 {
0251     DEBUG_BLOCK
0252 
0253     //we only enable the download button if there is only one item selected and it happens to
0254     //be an album or a track
0255     DataPtr dataPtr = selectedItem->data();
0256 
0257     if ( typeid( *dataPtr.data() ) == typeid( JamendoTrack ) )
0258     {
0259         debug() << "is right type (track)";
0260         JamendoTrack * track = static_cast<JamendoTrack *> ( dataPtr.data() );
0261         m_currentAlbum = static_cast<JamendoAlbum *> ( track->album().data() );
0262         m_downloadButton->setEnabled( true );
0263     }
0264     else if ( typeid( * dataPtr.data() ) == typeid( JamendoAlbum ) )
0265     {
0266         m_currentAlbum = static_cast<JamendoAlbum *> ( dataPtr.data() );
0267         debug() << "is right type (album) named " << m_currentAlbum->name();
0268         m_downloadButton->setEnabled( true );
0269     }
0270     else
0271     {
0272         debug() << "is wrong type";
0273         m_downloadButton->setEnabled( false );
0274     }
0275     return;
0276 }
0277 
0278 void
0279 JamendoService::download() // SLOT
0280 {
0281     DEBUG_BLOCK
0282 
0283     if ( !m_polished )
0284         polish();
0285 
0286     CollectionTreeView *treeView = static_cast<CollectionTreeView*>( view() );
0287     treeView->copySelectedToLocalCollection();
0288 }