Skip to content
Permalink
Browse files

ImportMusic: update the music import to use storage groups

This allows the import music screen to move the imported tracks to any backend
with a directory in the 'Music' storage group.  The master will be used by
default but you can save to any BE by using the "Select Where To Save Tracks"
option in the popup menu. The option is sticky so once changed the same one
will be used the next time until it's changed.

Still need to work on the album art side of things.
  • Loading branch information...
Paul Harrison
Paul Harrison committed Feb 1, 2014
1 parent bb32a29 commit 1c5b5e13277dcb6a94ecc0d726565ed771c18eb4
Showing with 171 additions and 81 deletions.
  1. +152 −81 mythplugins/mythmusic/mythmusic/importmusic.cpp
  2. +19 −0 mythplugins/mythmusic/mythmusic/importmusic.h
@@ -6,19 +6,7 @@
// myth
#include <mythcontext.h>
#include <mythdbcon.h>
#include <audiooutput.h>
#include <musicmetadata.h>

// mythmusic
#include "importmusic.h"
#include "decoder.h"
#include "genres.h"
#include "cdrip.h"
#include "editmetadata.h"
#include "musicplayer.h"
#include "metaio.h"
#include "musicutils.h"

#include <mythdialogbox.h>
#include <mythuitext.h>
#include <mythuiimage.h>
@@ -28,44 +16,18 @@
#include <mythuibuttonlist.h>
#include <mythprogressdialog.h>
#include <mythuifilebrowser.h>
#include "mythlogging.h"

static bool copyFile(const QString &src, const QString &dst)
{
const int bufferSize = 16*1024;

if (src == dst)
{
LOG(VB_GENERAL, LOG_ERR, "copyFile: Cannot copy a file to itself");
return false;
}

QFile s(src);
QFile d(dst);
char buffer[bufferSize];
int len;
#include <mythlogging.h>
#include <remotefile.h>
#include <storagegroup.h>

if (!s.open(QIODevice::ReadOnly))
return false;

if (!d.open(QIODevice::WriteOnly))
{
s.close();
return false;
}

len = s.read(buffer, bufferSize);
do
{
d.write(buffer, len);
len = s.read(buffer, bufferSize);
} while (len > 0);

s.close();
d.close();
// mythmusic
#include "importmusic.h"
#include "genres.h"
#include "editmetadata.h"
#include "musicplayer.h"
#include "metaio.h"
#include "musicutils.h"

return true;
}

///////////////////////////////////////////////////////////////////////////////

@@ -83,10 +45,25 @@ void FileScannerThread::run()

///////////////////////////////////////////////////////////////////////////////

FileCopyThread::FileCopyThread(const QString &src, const QString &dst) :
MThread("FileCopy"), m_srcFile(src), m_dstFile(dst), m_result(false)
{
}

void FileCopyThread::run()
{
RunProlog();
m_result = RemoteFile::CopyFile(m_srcFile, m_dstFile);
RunEpilog();
}

///////////////////////////////////////////////////////////////////////////////


ImportMusicDialog::ImportMusicDialog(MythScreenStack *parent) :
MythScreenType(parent, "musicimportfiles"),

m_musicStorageDir(""),
m_somethingWasImported(false),
m_tracks(new vector<TrackInfo*>),
m_currentTrack(0),
@@ -120,6 +97,10 @@ ImportMusicDialog::ImportMusicDialog(MythScreenStack *parent) :
m_defaultRating(0),
m_haveDefaults(false)
{
QString lastHost = gCoreContext->GetSetting("MythMusicLastImportHost", gCoreContext->GetMasterHostName());
QStringList dirs = StorageGroup::getGroupDirs("Music", lastHost);
if (dirs.count() > 0)
m_musicStorageDir = StorageGroup::getGroupDirs("Music", lastHost).at(0);
}

ImportMusicDialog::~ImportMusicDialog()
@@ -410,39 +391,48 @@ void ImportMusicDialog::addPressed()
// is the current track a new file?
if (m_tracks->at(m_currentTrack)->isNewTune)
{
// get the save filename - this also creates the correct directory stucture
QString saveFilename = filenameFromMetadata(meta);

// we need to manually copy the file extension
QFileInfo fi(meta->Filename());
saveFilename += "." + fi.suffix();

// copy the file to the new location
if (!copyFile(meta->Filename(), getMusicDirectory() + saveFilename))
{
ShowOkPopup(tr("Copy Failed\nCould not copy file to: %1")
.arg(getMusicDirectory() + saveFilename));
return;
}

meta->setFilename(saveFilename);

// do we need to update the tags?
if (m_tracks->at(m_currentTrack)->metadataHasChanged)
{
MetaIO *tagger = MetaIO::createTagger(getMusicDirectory() + saveFilename);
MetaIO *tagger = MetaIO::createTagger(meta->Filename());
if (tagger)
{
tagger->write(meta);
delete tagger;
}
}

// get the save filename
QString origFilename = meta->Filename();
QString saveFilename = filenameFromMetadata(meta, false);
QString fullFilename;

QUrl url(m_musicStorageDir);
fullFilename = gCoreContext->GenMythURL(url.host(), 0, saveFilename, "Music");


// we need to manually copy the file extension
QFileInfo fi(origFilename);
saveFilename += "." + fi.suffix();
fullFilename += "." + fi.suffix();

LOG(VB_FILE, LOG_INFO, QString("Copying file from: %1").arg(origFilename));
LOG(VB_FILE, LOG_INFO, QString("to: ").arg(fullFilename));

// copy the file to the new location
if (!copyFile(origFilename, fullFilename))
{
ShowOkPopup(tr("Copy Failed\nCould not copy file to: %1").arg(fullFilename));
return;
}

meta->setFilename(saveFilename);
meta->setHostname(url.host());
meta->setFileSize((quint64)QFileInfo(saveFilename).size());

// update the database
meta->dumpToDatabase();

#if 0
// read any embedded images from the tag
MetaIO *tagger = MetaIO::createTagger(meta->Filename(true));
if (tagger && tagger->supportsEmbeddedImages())
@@ -454,7 +444,7 @@ void ImportMusicDialog::addPressed()

if (tagger)
delete tagger;

#endif
m_somethingWasImported = true;

m_tracks->at(m_currentTrack)->isNewTune =
@@ -514,24 +504,53 @@ void ImportMusicDialog::nextNewPressed()
}
}

bool ImportMusicDialog::copyFile(const QString &src, const QString &dst)
{
bool res = false;
QString host = QUrl(dst).host();

MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
MythUIBusyDialog *busy =
new MythUIBusyDialog(tr("Copying music file to the 'Music' storage group on %1").arg(host),
popupStack,
"scanbusydialog");

if (busy->Create())
{
popupStack->AddScreen(busy, false);
}
else
{
delete busy;
busy = NULL;
}

FileCopyThread *copy = new FileCopyThread(src, dst);
copy->start();

while (!copy->isFinished())
{
usleep(500);
qApp->processEvents();
}

res = copy->GetResult();

delete copy;

if (busy)
busy->Close();

return res;
}

void ImportMusicDialog::startScan()
{
// sanity check - make sure the user isn't trying to import tracks from the music directory
QString location = m_locationEdit->GetText();
if (!location.endsWith('/'))
location.append('/');

if (location.startsWith(getMusicDirectory()))
{
ShowOkPopup(tr("Cannot import music from the music directory. "
"You probably want to use 'Scan For New Music' "
"instead."));
m_tracks->clear();
m_sourceFiles.clear();
fillWidgets();
return;
}

MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
MythUIBusyDialog *busy =
new MythUIBusyDialog(tr("Searching for music files"),
@@ -671,6 +690,7 @@ void ImportMusicDialog::showMenu()
}

menu->SetReturnEvent(this, "menu");
menu->AddButton(tr("Select Where To Save Tracks"), SLOT(chooseBackend()));
menu->AddButton(tr("Save Defaults"), SLOT(saveDefaults()));

if (m_haveDefaults)
@@ -686,6 +706,57 @@ void ImportMusicDialog::showMenu()
}
}

void ImportMusicDialog::chooseBackend(void)
{
QStringList hostList;

// get a list of hosts with a directory defined for the 'Music' storage group
MSqlQuery query(MSqlQuery::InitCon());
QString sql = "SELECT DISTINCT hostname "
"FROM storagegroup "
"WHERE groupname = 'Music'";
if (!query.exec(sql) || !query.isActive())
MythDB::DBError("ImportMusicDialog::chooseBackend get host list", query);
else
{
while(query.next())
{
hostList.append(query.value(0).toString());
}
}

if (hostList.isEmpty())
{
LOG(VB_GENERAL, LOG_ERR, "ImportMusicDialog::chooseBackend: No backends found");
return;
}

QString msg = tr("Select where to save tracks");

MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
MythUISearchDialog *searchDlg = new MythUISearchDialog(popupStack, msg, hostList, false, "");

if (!searchDlg->Create())
{
delete searchDlg;
return;
}

connect(searchDlg, SIGNAL(haveResult(QString)), SLOT(setSaveHost(QString)));

popupStack->AddScreen(searchDlg);
}

void ImportMusicDialog::setSaveHost(QString host)
{
gCoreContext->SaveSetting("MythMusicLastImportHost", host);

QStringList dirs = StorageGroup::getGroupDirs("Music", host);
if (dirs.count() > 0)
m_musicStorageDir = StorageGroup::getGroupDirs("Music", host).at(0);

}

void ImportMusicDialog::saveDefaults(void)
{
MusicMetadata *data = m_tracks->at(m_currentTrack)->metadata;
@@ -1012,7 +1083,7 @@ void ImportCoverArtDialog::copyPressed()
{
if (m_filelist.size() > 0)
{
if (!copyFile(m_filelist[m_currentFile], m_saveFilename))
if (!RemoteFile::CopyFile(m_filelist[m_currentFile], m_saveFilename))
{
//: %1 is the filename
ShowOkPopup(tr("Copy CoverArt Failed.\nCopying to %1")
@@ -1093,7 +1164,7 @@ void ImportCoverArtDialog::updateStatus()
m_coverartImage->SetFilename(m_filelist[m_currentFile]);
m_coverartImage->Load();

QString saveFilename = getMusicDirectory() + filenameFromMetadata(m_metadata, false);
QString saveFilename = /*getMusicDirectory() + */filenameFromMetadata(m_metadata, false);
QFileInfo fi(saveFilename);
QString saveDir = fi.absolutePath();

@@ -38,6 +38,20 @@ class FileScannerThread: public MThread
ImportMusicDialog *m_parent;
};

class FileCopyThread: public MThread
{
public:
FileCopyThread(const QString &src, const QString &dst);
virtual void run();

bool GetResult(void) { return m_result; }

private:
QString m_srcFile;
QString m_dstFile;
bool m_result;
};

class ImportMusicDialog : public MythScreenType
{

@@ -53,6 +67,7 @@ class ImportMusicDialog : public MythScreenType

bool somethingWasImported() { return m_somethingWasImported; }
void doScan(void);
void doFileCopy(const QString &src, const QString &dst);

public slots:
void addAllNewPressed(void);
@@ -82,6 +97,8 @@ class ImportMusicDialog : public MythScreenType
void setTitleWordCaps(void);
void setTitleInitialCap(void);
void metadataChanged(void);
void chooseBackend(void);
void setSaveHost(QString host);

signals:
void importFinished(void);
@@ -90,7 +107,9 @@ class ImportMusicDialog : public MythScreenType
void fillWidgets();
void scanDirectory(QString &directory, vector<TrackInfo*> *tracks);
void showImportCoverArtDialog();
bool copyFile(const QString &src, const QString &dst);

QString m_musicStorageDir;
bool m_somethingWasImported;
vector<TrackInfo*> *m_tracks;
QStringList m_sourceFiles;

0 comments on commit 1c5b5e1

Please sign in to comment.
You can’t perform that action at this time.