Commit 76fb57b5 authored by Bart Cerneels's avatar Bart Cerneels
Browse files

Add podcast episode filename configuration.

Patch by Sandeep Raghuraman.
FIXED-IN: 2.4.2
FEATURE: 155075
REVIEW: 100686
parent 56ef2ab7
......@@ -5,6 +5,8 @@ Amarok ChangeLog
VERSION 2.4.2-Beta 1
FEATURES:
* Make podcast episodes download filename configurable. Patch by
Sandeep Raghuraman. (BR 155075)
* Automatic scrolling in lyrics applet (Thanks to Jan Gerrit Marker)
* Option to scrobble composer as artist to Last.fm (Thanks to Nicholas Wilson)
......
......@@ -364,6 +364,7 @@ set(libpodcasts_SRCS
core-impl/podcasts/sql/SqlPodcastMeta.cpp
core-impl/podcasts/sql/SqlPodcastProvider.cpp
core-impl/podcasts/sql/PodcastSettingsDialog.cpp
core-impl/podcasts/sql/PodcastFilenameLayoutConfigDialog.cpp
)
#####################################################################
......@@ -898,6 +899,7 @@ kde4_add_ui_files(amaroklib_LIB_SRCS
playlist/layouts/PlaylistLayoutEditDialog.ui
core-impl/podcasts/sql/PodcastSettingsBase.ui
core-impl/podcasts/sql/SqlPodcastProviderSettingsWidget.ui
core-impl/podcasts/sql/PodcastFilenameLayoutConfigWidget.ui
browsers/playlistbrowser/PodcastCategoryBase.ui
)
......
#include "PodcastFilenameLayoutConfigDialog.h"
#include "ui_PodcastFilenameLayoutConfigWidget.h"
#include <QApplication>
PodcastFilenameLayoutConfigDialog::PodcastFilenameLayoutConfigDialog( Podcasts::SqlPodcastChannelPtr channel, QWidget* parent )
: KDialog( parent )
, m_channel( channel )
, m_pflc( new Ui::PodcastFilenameLayoutConfigWidget )
{
QWidget* main = new QWidget( this );
m_pflc->setupUi( main );
setMainWidget( main );
setCaption( i18nc( "Change filename layout", "Podcast Episode Filename Configuration" ) );
setModal( true );
setButtons( Cancel | Ok );
setDefaultButton( Ok );
showButtonSeparator( true );
setSizePolicy( QSizePolicy::MinimumExpanding, QSizePolicy::Fixed );
init();
}
void PodcastFilenameLayoutConfigDialog::init()
{
//initialize state of the various gui items based on the channel settings
QString filenameLayout = m_channel->filenameLayout();
if( filenameLayout == QLatin1String( "%default%" ) )
{
m_pflc->m_filenameLayoutDefault->setChecked( true );
m_pflc->m_filenameLayoutCustom->setChecked( false );
choice = 0;
}
else
{
m_pflc->m_filenameLayoutDefault->setChecked( false );
m_pflc->m_filenameLayoutCustom->setChecked( true );
m_pflc->m_filenameLayoutText->setText( filenameLayout );
choice = 1;
}
connect( this, SIGNAL( okClicked() ), this, SLOT( slotApply() ) );
}
void PodcastFilenameLayoutConfigDialog::slotApply()
{
if( m_pflc->m_filenameLayoutCustom->isChecked() )
{
m_channel->setFilenameLayout( m_pflc->m_filenameLayoutText->text() );
}
else
{
m_channel->setFilenameLayout( "%default%" );
}
}
bool PodcastFilenameLayoutConfigDialog::configure()
{
return exec() == QDialog::Accepted;
}
#include "PodcastFilenameLayoutConfigDialog.moc"
\ No newline at end of file
#ifndef AMAROK_PODCASTFILENAMELAYOUTCONFIGDIALOG_H
#define AMAROK_PODCASTFILENAMELAYOUTCONFIGDIALOG_H
#include "SqlPodcastMeta.h"
#include <KDialog>
namespace Ui
{
class PodcastFilenameLayoutConfigWidget;
}
class PodcastFilenameLayoutConfigDialog : public KDialog
{
Q_OBJECT
public:
explicit PodcastFilenameLayoutConfigDialog( Podcasts::SqlPodcastChannelPtr channel, QWidget* parent = 0 );
bool configure();
protected slots:
void slotApply();
private:
void init();
Podcasts::SqlPodcastChannelPtr m_channel;
Ui::PodcastFilenameLayoutConfigWidget *m_pflc;
int choice;
};
#endif
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PodcastFilenameLayoutConfigWidget</class>
<widget class="QWidget" name="PodcastFilenameLayoutConfigWidget">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>110</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>250</horstretch>
<verstretch>100</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>400</width>
<height>100</height>
</size>
</property>
<property name="windowTitle">
<string>Podcast Filename Layout Configuration</string>
</property>
<widget class="QRadioButton" name="m_filenameLayoutDefault">
<property name="geometry">
<rect>
<x>20</x>
<y>20</y>
<width>231</width>
<height>22</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>85</width>
<height>0</height>
</size>
</property>
<property name="text">
<string>Specified by podcast channel</string>
</property>
</widget>
<widget class="QRadioButton" name="m_filenameLayoutCustom">
<property name="geometry">
<rect>
<x>20</x>
<y>60</y>
<width>115</width>
<height>22</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
<property name="text">
<string>custom</string>
</property>
</widget>
<widget class="QLineEdit" name="m_filenameLayoutText">
<property name="geometry">
<rect>
<x>110</x>
<y>60</y>
<width>261</width>
<height>27</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
<horstretch>200</horstretch>
<verstretch>20</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>200</width>
<height>20</height>
</size>
</property>
<property name="baseSize">
<size>
<width>200</width>
<height>20</height>
</size>
</property>
<property name="toolTip">
<string>Available fields : %artist%,%title%,%genre%,%year%,%composer%,%pubdate%,%number%,%album%</string>
</property>
</widget>
</widget>
<resources/>
<connections>
<connection>
<sender>m_filenameLayoutCustom</sender>
<signal>toggled(bool)</signal>
<receiver>m_filenameLayoutText</receiver>
<slot>setEnabled(bool)</slot>
<hints>
<hint type="sourcelabel">
<x>20</x>
<y>20</y>
</hint>
<hint type="destinationlabel">
<x>20</x>
<y>20</y>
</hint>
</hints>
</connection>
</connections>
</ui>
......@@ -10,8 +10,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>501</width>
<height>254</height>
<width>527</width>
<height>305</height>
</rect>
</property>
<property name="sizePolicy">
......@@ -227,6 +227,31 @@
</item>
</layout>
</item>
<item>
<widget class="QPushButton" name="m_filenameLayoutConfigWidgetButton">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>240</width>
<height>30</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>Episode Filename Configuration</string>
</property>
</widget>
</item>
</layout>
</widget>
<layoutdefault spacing="6" margin="11"/>
......
......@@ -16,6 +16,7 @@
#include "PodcastSettingsDialog.h"
#include "ui_PodcastSettingsBase.h"
#include "PodcastFilenameLayoutConfigDialog.h"
#include "core/support/Debug.h"
......@@ -88,6 +89,7 @@ PodcastSettingsDialog::init()
connect( m_ps->m_purgeCheck, SIGNAL(clicked()), SLOT(checkModified()) );
connect( m_ps->m_purgeCountSpinBox, SIGNAL(valueChanged( int )), SLOT(checkModified()) );
connect( m_ps->m_writeTagsCheck, SIGNAL(clicked()), SLOT(checkModified()) );
connect( m_ps->m_filenameLayoutConfigWidgetButton, SIGNAL(clicked()), SLOT(launchFilenameLayoutConfigDialog()) );
connect( this, SIGNAL(applyClicked()), this ,SLOT(slotApply()) );
connect( this, SIGNAL(okClicked()), this, SLOT(slotApply()) );
......@@ -151,5 +153,12 @@ bool PodcastSettingsDialog::configure()
return exec() == QDialog::Accepted;
}
void PodcastSettingsDialog::launchFilenameLayoutConfigDialog()
{
PodcastFilenameLayoutConfigDialog pflcDialog( m_channel, this );
pflcDialog.configure();
}
#include "PodcastSettingsDialog.moc"
......@@ -41,6 +41,7 @@ class PodcastSettingsDialog : public KDialog
void checkModified();
void slotApply();
void slotFeedUrlClicked( const QString &url );
void launchFilenameLayoutConfigDialog();
private:
void init();
......
......@@ -498,6 +498,7 @@ SqlPodcastChannel::SqlPodcastChannel( SqlPodcastProvider *provider,
m_purge = sqlStorage->boolTrue() == *(iter++);
m_purgeCount = (*(iter++)).toInt();
m_writeTags = sqlStorage->boolTrue() == *(iter++);
m_filenameLayout = *(iter++);
}
SqlPodcastChannel::SqlPodcastChannel( Podcasts::SqlPodcastProvider *provider,
......@@ -505,6 +506,7 @@ SqlPodcastChannel::SqlPodcastChannel( Podcasts::SqlPodcastProvider *provider,
: Podcasts::PodcastChannel()
, m_dbId( 0 )
, m_provider( provider )
, m_filenameLayout( "%default%" )
{
// PodcastMetaCommon
m_title = channel->title();
......@@ -717,13 +719,13 @@ SqlPodcastChannel::updateInDb()
#define escape(x) sqlStorage->escape(x)
QString insert = "INSERT INTO podcastchannels("
"url,title,weblink,image,description,copyright,directory,labels,"
"subscribedate,autoscan,fetchtype,haspurge,purgecount,writetags) "
"VALUES ( '%1','%2','%3','%4','%5','%6','%7','%8','%9',%10,%11,%12,%13,%14 );";
"subscribedate,autoscan,fetchtype,haspurge,purgecount,writetags,filenamelayout) "
"VALUES ( '%1','%2','%3','%4','%5','%6','%7','%8','%9',%10,%11,%12,%13,%14,'%15' );";
QString update = "UPDATE podcastchannels SET url='%1',title='%2'"
",weblink='%3',image='%4',description='%5',copyright='%6',directory='%7'"
",labels='%8',subscribedate='%9',autoscan=%10,fetchtype=%11,haspurge=%12,"
"purgecount=%13, writetags=%14 WHERE id=%15;";
"purgecount=%13, writetags=%14, filenamelayout='%15' WHERE id=%16;";
//if we don't have a database ID yet we should insert;
QString command = m_dbId ? update : insert;
......@@ -741,6 +743,7 @@ SqlPodcastChannel::updateInDb()
command = command.arg( m_purge ? boolTrue : boolFalse ); //%12
command = command.arg( QString::number(m_purgeCount) ); //%13
command = command.arg( m_writeTags ? boolTrue : boolFalse ); //%14
command = command.arg( escape(m_filenameLayout) ); //%15
if( m_dbId )
sqlStorage->query( command.arg( m_dbId ) );
......
......@@ -102,6 +102,7 @@ class SqlPodcastChannel : public Podcasts::PodcastChannel
virtual int trackCount() const;
virtual Meta::TrackList tracks() {
return Podcasts::SqlPodcastEpisode::toTrackList( m_episodes ); }
virtual QString filenameLayout() const { return m_filenameLayout; }
virtual void triggerTrackLoad();
virtual Playlists::PlaylistProvider *provider() const;
......@@ -117,6 +118,8 @@ class SqlPodcastChannel : public Podcasts::PodcastChannel
virtual QImage image() const { return m_image; }
virtual KUrl imageUrl() const { return m_imageUrl; }
virtual void setImageUrl( const KUrl &imageUrl );
virtual void setFilenameLayout( const QString &filenameLayout ) { m_filenameLayout = filenameLayout; }
PodcastEpisodePtr addEpisode( PodcastEpisodePtr episode );
......@@ -141,6 +144,7 @@ class SqlPodcastChannel : public Podcasts::PodcastChannel
SqlPodcastEpisodeList m_episodes;
SqlPodcastProvider *m_provider;
QString m_filenameLayout; //specifies filename layout for episodes
};
} //namespace Podcasts
......
......@@ -33,6 +33,7 @@
#include "statusbar/StatusBar.h"
#include "SvgHandler.h"
#include "OpmlWriter.h"
#include "QStringx.h"
#include "ui_SqlPodcastProviderSettingsWidget.h"
......@@ -52,10 +53,11 @@
#include <QDir>
#include <QTimer>
#include <QCheckBox>
#include <QMap>
using namespace Podcasts;
static const int PODCAST_DB_VERSION = 4;
static const int PODCAST_DB_VERSION = 5;
static const QString key( "AMAROK_PODCAST" );
static const QString PODCAST_TMP_POSTFIX( ".tmp" );
......@@ -168,9 +170,9 @@ SqlPodcastProvider::loadPodcasts()
QStringList results = sqlStorage->query( "SELECT id, url, title, weblink, image"
", description, copyright, directory, labels, subscribedate, autoscan, fetchtype"
", haspurge, purgecount, writetags FROM podcastchannels;" );
", haspurge, purgecount, writetags, filenamelayout FROM podcastchannels;" );
int rowLength = 15;
int rowLength = 16;
for( int i = 0; i < results.size(); i += rowLength )
{
QStringList channelResult = results.mid( i, rowLength );
......@@ -1496,7 +1498,43 @@ SqlPodcastProvider::downloadResult( KJob *job )
return;
}
QString finalName = sqlChannel->saveLocation().toLocalFile(KUrl::AddTrailingSlash )
Amarok::QStringx filenameLayout = Amarok::QStringx( sqlChannel->filenameLayout() );
QMap<QString,QString> layoutmap;
QString sequenceNumber;
if( sqlEpisode->artist() )
layoutmap.insert( "artist", sqlEpisode->artist()->prettyName() );
layoutmap.insert( "title", sqlEpisode->title() );
if( sqlEpisode->genre() )
layoutmap.insert( "genre", sqlEpisode->genre()->prettyName() );
if( sqlEpisode->year() )
layoutmap.insert( "year", sqlEpisode->year()->prettyName() );
if( sqlEpisode->composer() )
layoutmap.insert( "composer", sqlEpisode->composer()->prettyName() );
layoutmap.insert( "pubdate", sqlEpisode->pubDate().toString() );
sequenceNumber.sprintf( "%.6d", sqlEpisode->sequenceNumber() );
layoutmap.insert( "number", sequenceNumber );
if( sqlEpisode->album() )
layoutmap.insert( "album", sqlEpisode->album()->prettyName() );
if( !filenameLayout.isEmpty() &&
Amarok::QStringx::compare( filenameLayout, "%default%", Qt::CaseInsensitive ) )
{
filenameLayout = filenameLayout.namedArgs( layoutmap );
//add the file extension to the filename
filenameLayout.append( QString( "." ) );
filenameLayout.append( sqlEpisode->type() );
download.fileName = QString( filenameLayout );
}
QString finalName = sqlChannel->saveLocation().toLocalFile( KUrl::AddTrailingSlash )
+ download.fileName;
if( tmpFile->rename( finalName ) )
{
......@@ -1553,7 +1591,7 @@ SqlPodcastProvider::createTables() const
",subscribedate " + sqlStorage->textColumnType() +
",autoscan BOOL, fetchtype INTEGER"
",haspurge BOOL, purgecount INTEGER"
",writetags BOOL ) ENGINE = MyISAM;" ) );
",writetags BOOL, filenamelayout VARCHAR(1024) ) ENGINE = MyISAM;" ) );
sqlStorage->query( QString( "CREATE TABLE podcastepisodes ("
"id " + sqlStorage->idType() +
......@@ -1658,6 +1696,15 @@ SqlPodcastProvider::updateDatabase( int fromVersion, int toVersion )
sqlStorage->query( setWriteTagsQuery );
}
if(fromVersion < 5 && toVersion == 5 )
{
QString updateChannelQuery = QString ( "ALTER TABLE podcastchannels"
" ADD filenamelayout VARCHAR(1024);" );
sqlStorage->query( updateChannelQuery );
QString setWriteTagsQuery = QString( "UPDATE podcastchannels SET filenamelayout='%default%'" );
sqlStorage->query( setWriteTagsQuery );
}
QString updateAdmin = QString( "UPDATE admin SET version=%1 WHERE component='%2';" );
sqlStorage->query( updateAdmin.arg( toVersion ).arg( escape( key ) ) );
......
......@@ -292,7 +292,6 @@ class AMAROK_CORE_EXPORT PodcastChannel : public PodcastMetaCommon, public Playl
PodcastChannel::FetchType m_fetchType; //'download when available' or 'stream or download on demand'
bool m_purge; //remove old episodes?
int m_purgeCount; //how many episodes do we keep on disk?
PodcastEpisodeList m_episodes;
};
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment