diff options
| author | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2015-02-02 10:10:49 +0000 |
|---|---|---|
| committer | trialuser02 <trialuser02@90c681e8-e032-0410-971d-27865f9a5e38> | 2015-02-02 10:10:49 +0000 |
| commit | 264f3ddbe777c212620a2e5c66c1b9f358f833e7 (patch) | |
| tree | 6db54ed8111453e687c6ce8569cadf37df2f8c27 | |
| parent | 8eccc97170a4ea592aa3fe38fed1294e86df0b1c (diff) | |
| download | qmmp-264f3ddbe777c212620a2e5c66c1b9f358f833e7.tar.gz qmmp-264f3ddbe777c212620a2e5c66c1b9f358f833e7.tar.bz2 qmmp-264f3ddbe777c212620a2e5c66c1b9f358f833e7.zip | |
enabled new metadata formatter
git-svn-id: http://svn.code.sf.net/p/qmmp-dev/code/trunk/qmmp@4710 90c681e8-e032-0410-971d-27865f9a5e38
21 files changed, 440 insertions, 643 deletions
diff --git a/src/plugins/CommandLineOptions/PlayListOption/playlistoption.cpp b/src/plugins/CommandLineOptions/PlayListOption/playlistoption.cpp index 4082fde1c..67c4d1014 100644 --- a/src/plugins/CommandLineOptions/PlayListOption/playlistoption.cpp +++ b/src/plugins/CommandLineOptions/PlayListOption/playlistoption.cpp @@ -88,7 +88,7 @@ QString PlayListOption::executeCommand(const QString& opt_str, const QStringList PlayListTrack *track = model->track(i); if(!track) continue; - out += QString("%1. %2").arg(model->numberOfTrack(i) + 1).arg(formatter.parse(track)); + out += QString("%1. %2").arg(model->numberOfTrack(i) + 1).arg(formatter.format(track)); if(i == model->currentIndex()) out += " [*]"; out += "\n"; diff --git a/src/plugins/CommandLineOptions/StatusOption/statusoption.cpp b/src/plugins/CommandLineOptions/StatusOption/statusoption.cpp index 4fe1dcbcf..fbdc7e130 100644 --- a/src/plugins/CommandLineOptions/StatusOption/statusoption.cpp +++ b/src/plugins/CommandLineOptions/StatusOption/statusoption.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2010-2014 by Ilya Kotov * + * Copyright (C) 2010-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -72,7 +72,7 @@ QString StatusOption::executeCommand(const QString &opt_str, const QStringList & out += "TRACK = %n\n"; out += "FILE = %f\n"; MetaDataFormatter formatter(out); - out = formatter.parse(core->metaData(), core->totalTime()); + out = formatter.format(core->metaData(), core->totalTime()); } else out += "\n"; @@ -81,7 +81,7 @@ QString StatusOption::executeCommand(const QString &opt_str, const QStringList & { QString t = args.join(" "); MetaDataFormatter formatter(t); - out = formatter.parse(core->metaData(), core->totalTime()); + out = formatter.format(core->metaData(), core->totalTime()); out += "\n"; } else if(opt_str == "--nowplaying-syntax") diff --git a/src/plugins/General/converter/converter.cpp b/src/plugins/General/converter/converter.cpp index e7e51fea0..f0d21e50a 100644 --- a/src/plugins/General/converter/converter.cpp +++ b/src/plugins/General/converter/converter.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2011-2013 by Ilya Kotov * + * Copyright (C) 2011-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -166,12 +166,12 @@ void Converter::run() QMap<Qmmp::MetaData, QString> metadata = list[0]->metaData(); MetaDataFormatter formatter(pattern); - QString desc = tr("Track: %1").arg(desc_formatter.parse(list[0]->metaData(), list[0]->length())); + QString desc = tr("Track: %1").arg(desc_formatter.format(list[0]->metaData(), list[0]->length())); desc += "\n"; desc += tr("Preset: %1").arg(preset["name"].toString()); emit desriptionChanged(desc); - QString name = formatter.parse(list[0]->metaData(), list[0]->length()); + QString name = formatter.format(list[0]->metaData(), list[0]->length()); QString full_path = out_path + "/" + name + "." + preset["ext"].toString(); if(QFile::exists(full_path)) diff --git a/src/plugins/General/converter/converterdialog.cpp b/src/plugins/General/converter/converterdialog.cpp index 2c83e5416..ac2482e3e 100644 --- a/src/plugins/General/converter/converterdialog.cpp +++ b/src/plugins/General/converter/converterdialog.cpp @@ -37,7 +37,7 @@ ConverterDialog::ConverterDialog(QList <PlayListTrack *> items, QWidget *parent { if(item->length() == 0) continue; - QString text = formatter.parse(item); + QString text = formatter.format(item); QListWidgetItem *listItem = new QListWidgetItem(text); listItem->setData(Qt::UserRole, item->url()); listItem->setCheckState(Qt::Checked); diff --git a/src/plugins/General/covermanager/covermanager.cpp b/src/plugins/General/covermanager/covermanager.cpp index f89af8756..dd88e6643 100644 --- a/src/plugins/General/covermanager/covermanager.cpp +++ b/src/plugins/General/covermanager/covermanager.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2013 by Ilya Kotov * + * Copyright (C) 2009-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -49,7 +49,7 @@ void CoverManager::showWindow() pix = QPixmap(":/cm_no_cover.png"); w->setPixmap(pix); MetaDataFormatter formatter("%p%if(%p&%t, - ,)%if(%t,%t,%f)"); - w->setWindowTitle(formatter.parse(tracks.at(0))); + w->setWindowTitle(formatter.format(tracks.at(0))); w->show(); } } diff --git a/src/plugins/General/fileops/fileops.cpp b/src/plugins/General/fileops/fileops.cpp index 6e41178b7..e7c2d49f7 100644 --- a/src/plugins/General/fileops/fileops.cpp +++ b/src/plugins/General/fileops/fileops.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2012 by Ilya Kotov * + * Copyright (C) 2009-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -82,6 +82,7 @@ void FileOps::execAction(int n) { int type = m_types.at(n); QString pattern = m_patterns.at(n); + MetaDataFormatter formatter(pattern); QString destination = m_destinations.at(n); PlayListModel *model = MediaPlayer::instance()->playListManager()->selectedPlayList(); @@ -110,8 +111,7 @@ void FileOps::execAction(int n) if (!QFile::exists(item->url())) continue; //generate file name - MetaDataFormatter formatter(pattern); - QString fname = formatter.parse(item); + QString fname = formatter.format(item); //append extension QString ext = QString(".") + item->url().split('.',QString::SkipEmptyParts).takeLast (); if (!fname.endsWith(ext)) @@ -163,8 +163,7 @@ void FileOps::execAction(int n) if (!QFile::exists(item->url())) continue; //generate file name - MetaDataFormatter formatter(pattern); - QString fname = formatter.parse(item); + QString fname = formatter.format(item); //append extension QString ext = QString(".") + item->url().split('.',QString::SkipEmptyParts).takeLast (); if (!fname.endsWith(ext)) diff --git a/src/plugins/General/kdenotify/kdenotify.cpp b/src/plugins/General/kdenotify/kdenotify.cpp index 47e7987d6..d4bb4a482 100644 --- a/src/plugins/General/kdenotify/kdenotify.cpp +++ b/src/plugins/General/kdenotify/kdenotify.cpp @@ -121,7 +121,7 @@ QList<QVariant> KdeNotify::prepareNotification() args.append(tr("Qmmp now playing:")); //summary (notification title) MetaDataFormatter f(m_template); - QString body = f.parse(core->metaData(), core->totalTime()/1000); + QString body = f.format(core->metaData(), core->totalTime()/1000); QString coverPath; if(m_showCovers) diff --git a/src/plugins/General/notifier/popupwidget.cpp b/src/plugins/General/notifier/popupwidget.cpp index f93999ee8..b29b5c6f0 100644 --- a/src/plugins/General/notifier/popupwidget.cpp +++ b/src/plugins/General/notifier/popupwidget.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2014 by Ilya Kotov * + * Copyright (C) 2008-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -95,7 +95,7 @@ void PopupWidget::showMetaData() else title.replace("%l",""); MetaDataFormatter f(title); - title = f.parse(core->metaData()); + title = f.format(core->metaData()); m_label1->setText(title); diff --git a/src/plugins/General/rgscan/rgscandialog.cpp b/src/plugins/General/rgscan/rgscandialog.cpp index 75d9aa0e9..7b3824921 100644 --- a/src/plugins/General/rgscan/rgscandialog.cpp +++ b/src/plugins/General/rgscan/rgscandialog.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013 by Ilya Kotov * + * Copyright (C) 2013-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -73,7 +73,7 @@ RGScanDialog::RGScanDialog(QList <PlayListTrack *> tracks, QWidget *parent) : Q ext == "wv") //wavpack { paths.append(track->url()); - QString name = formatter.parse(track); + QString name = formatter.format(track); QTableWidgetItem *item = new QTableWidgetItem(name); item->setData(Qt::UserRole, track->url()); item->setData(Qt::ToolTipRole, track->url()); diff --git a/src/plugins/General/statusicon/statusicon.cpp b/src/plugins/General/statusicon/statusicon.cpp index 077babe5c..9fcbce60d 100644 --- a/src/plugins/General/statusicon/statusicon.cpp +++ b/src/plugins/General/statusicon/statusicon.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2013 by Ilya Kotov * + * Copyright (C) 2008-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -122,7 +122,7 @@ void StatusIcon::setState(Qmmp::State state) void StatusIcon::showMetaData() { MetaDataFormatter f("%p%if(%p&%t, - ,)%t"); - QString message = f.parse(m_core->metaData()); + QString message = f.format(m_core->metaData()); if (message.isEmpty()) message = m_core->metaData(Qmmp::URL).section('/',-1); diff --git a/src/plugins/General/statusicon/statusiconpopupwidget.cpp b/src/plugins/General/statusicon/statusiconpopupwidget.cpp index 694c19a5b..1b057c817 100644 --- a/src/plugins/General/statusicon/statusiconpopupwidget.cpp +++ b/src/plugins/General/statusicon/statusiconpopupwidget.cpp @@ -2,7 +2,7 @@ * Copyright (C) 2009 by Artur Guzik * * a.guzik88@gmail.com * * * - * Copyright (C) 2009-2012 by Ilya Kotov * + * Copyright (C) 2009-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -116,7 +116,7 @@ void StatusIconPopupWidget::updateMetaData() } MetaDataFormatter f(title); - title = f.parse(core->metaData(), core->totalTime()/1000); + title = f.format(core->metaData(), core->totalTime()/1000); m_textLabel->setText(title); QPixmap cover = MetaDataManager::instance()->getCover(core->metaData(Qmmp::URL)); m_cover->show(); diff --git a/src/plugins/General/trackchange/trackchange.cpp b/src/plugins/General/trackchange/trackchange.cpp index 9ec0f0da1..3aa4853d8 100644 --- a/src/plugins/General/trackchange/trackchange.cpp +++ b/src/plugins/General/trackchange/trackchange.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2013 by Ilya Kotov * + * Copyright (C) 2013-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -106,7 +106,7 @@ void TrackChange::onFinised() bool TrackChange::executeCommand(const QMap<Qmmp::MetaData, QString> &metaData, const QString &format) { MetaDataFormatter formatter(format); - QString command = formatter.parse(metaData); + QString command = formatter.format(metaData); #ifdef Q_OS_WIN bool ok = QProcess::startDetached(QString("cmd.exe \"%1\"").arg(command)); #else diff --git a/src/plugins/Ui/skinned/popupwidget.cpp b/src/plugins/Ui/skinned/popupwidget.cpp index d18a689c0..63cfc7142 100644 --- a/src/plugins/Ui/skinned/popupwidget.cpp +++ b/src/plugins/Ui/skinned/popupwidget.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2008-2014 by Ilya Kotov * + * Copyright (C) 2008-2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -95,7 +95,7 @@ void PopupWidget::prepare(PlayListTrack *item, QPoint pos) QString title = m_template; MetaDataFormatter f(title); - title = f.parse(item); + title = f.format(item); m_label1->setText(title); qApp->processEvents(); updateGeometry (); diff --git a/src/plugins/Ui/skinned/textscroller.cpp b/src/plugins/Ui/skinned/textscroller.cpp index b87d77431..ab86942a9 100644 --- a/src/plugins/Ui/skinned/textscroller.cpp +++ b/src/plugins/Ui/skinned/textscroller.cpp @@ -241,7 +241,7 @@ void TextScroller::processMetaData() MetaDataFormatter formater(TITLE_FORMAT); if(m_core->state() == Qmmp::Playing) { - m_titleText = formater.parse(m_core->metaData(), m_core->totalTime()/1000); + m_titleText = formater.format(m_core->metaData(), m_core->totalTime()/1000); updateText(); } } diff --git a/src/qmmpui/mediaplayer.cpp b/src/qmmpui/mediaplayer.cpp index acd89ef86..40cd40c26 100644 --- a/src/qmmpui/mediaplayer.cpp +++ b/src/qmmpui/mediaplayer.cpp @@ -22,7 +22,6 @@ #include <QString> #include <QTranslator> #include <QLocale> -#include "metadataformatter2.h" #include "playlistitem.h" #include "qmmpuisettings.h" #include "mediaplayer.h" @@ -49,8 +48,6 @@ MediaPlayer::MediaPlayer(QObject *parent) connect(m_core, SIGNAL(finished()), SLOT(playNext())); connect(m_core, SIGNAL(stateChanged(Qmmp::State)), SLOT(processState(Qmmp::State))); connect(m_core, SIGNAL(metaDataChanged()),SLOT(updateMetaData())); - - MetaDataFormatter2 formatter; } MediaPlayer::~MediaPlayer() diff --git a/src/qmmpui/metadataformatter.cpp b/src/qmmpui/metadataformatter.cpp index c19b49674..f1b70eeb0 100644 --- a/src/qmmpui/metadataformatter.cpp +++ b/src/qmmpui/metadataformatter.cpp @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2014 by Ilya Kotov * + * Copyright (C) 2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -21,66 +21,76 @@ /* Syntax: -%p - artist -%a - album -%aa - album artist -%t - title -%n - track, -%NN - 2-digit track -%g - genre -%c - comment -%C - composer -%D - disc number -%f - file name -%F - full path -%y - year -%l - duration -%if(A,B,C) -%if(A&B&C,D,E) +%p - artist, +%a - album, +%aa - album artist, +%t - title, +%n - track number, +%NN - 2-digit track number, +%g - genre, +%c - comment, +%C - composer, +%D - disc number, +%f - file name, +%F - full path, +%y - year, +%l - duration, +%if(A,B,C) or %if(A&B&C,D,E) - condition. */ #include <QStringList> #include <QUrl> #include "metadataformatter.h" -MetaDataFormatter::MetaDataFormatter(const QString &format) +MetaDataFormatter::MetaDataFormatter(const QString &pattern) { - m_format = format; + m_fieldNames.insert("t", Qmmp::TITLE); + m_fieldNames.insert("p", Qmmp::ARTIST); + m_fieldNames.insert("aa", Qmmp::ALBUMARTIST); + m_fieldNames.insert("a", Qmmp::ALBUM); + m_fieldNames.insert("c", Qmmp::COMMENT); + m_fieldNames.insert("g", Qmmp::GENRE); + m_fieldNames.insert("C", Qmmp::COMPOSER); + m_fieldNames.insert("y", Qmmp::YEAR); + m_fieldNames.insert("n", Qmmp::TRACK); + m_fieldNames.insert("D", Qmmp::DISCNUMBER); + m_fieldNames.insert("F", Qmmp::URL); + m_fieldNames.insert("NN", Param::TWO_DIGIT_TRACK); + m_fieldNames.insert("l", Param::DURATION); + m_fieldNames.insert("f", Param::FILE_NAME); + + if(!pattern.isEmpty()) + setPattern(pattern); +} + +void MetaDataFormatter::setPattern(const QString &pattern) +{ + m_pattern = pattern; + m_nodes.clear(); + + qDebug("MetaDataFormatter: pattern: %s", qPrintable(pattern)); + m_nodes = compile(pattern); + qDebug("MetaDataFormatter: dump of nodes"); + foreach (Node n, m_nodes) + { + qDebug("=>%s", qPrintable(dumpNode(n))); + } + qDebug("MetaDataFormatter: end of dump"); +} + +const QString MetaDataFormatter::pattern() const +{ + return m_pattern; } -QString MetaDataFormatter::parse(const PlayListTrack *item) +QString MetaDataFormatter::format(const PlayListTrack *item) { - return parse(*item, item->length()); + return format(*item, item->length()); } -QString MetaDataFormatter::parse(const QMap<Qmmp::MetaData, QString> &metaData, qint64 length) +QString MetaDataFormatter::format(const QMap<Qmmp::MetaData, QString> &metaData, qint64 length) { - QString title = m_format; - title.replace("\\(", "%28"); - title.replace("\\)", "%29"); - title.replace(")", "%)"); - title.replace("&", "%&"); - title.replace(",", "%,"); - title.replace("%p", metaData[Qmmp::ARTIST]); - title.replace("%aa", metaData[Qmmp::ALBUMARTIST]); - title.replace("%a", metaData[Qmmp::ALBUM]); - title.replace("%t", metaData[Qmmp::TITLE]); - title.replace("%n", metaData[Qmmp::TRACK]); - title.replace("%NN", QString("%1").arg(metaData[Qmmp::TRACK],2,'0')); - title.replace("%g", metaData[Qmmp::GENRE]); - title.replace("%c", metaData[Qmmp::COMMENT]); - title.replace("%C", metaData[Qmmp::COMPOSER]); - title.replace("%D", metaData[Qmmp::DISCNUMBER]); - title.replace("%f", metaData[Qmmp::URL].section('/',-1)); - title.replace("%F", metaData[Qmmp::URL]); - title.replace("%y", metaData[Qmmp::YEAR]); - if(title.contains("l")) - title.replace("%l",formatLength(length)); - if(title.contains("%if")) - title = processIfKeyWord(title); - title.replace("%28", "("); - title.replace("%29", ")"); - return title.trimmed(); + return evalute(&m_nodes, &metaData, length).trimmed(); } QString MetaDataFormatter::formatLength(qint64 length) const @@ -96,26 +106,300 @@ QString MetaDataFormatter::formatLength(qint64 length) const return str; } -QString MetaDataFormatter::processIfKeyWord(QString title) +bool MetaDataFormatter::parseField(QList<Node> *nodes, QString::const_iterator *i, QString::const_iterator end) +{ + QString fieldName; + int field = Qmmp::UNKNOWN; + + //try to find field with 2 symbols + if((*i) + 1 != end) + { + fieldName.append((**i)); + fieldName.append(*((*i)+1)); + field = m_fieldNames.value(fieldName, Qmmp::UNKNOWN); + } + //try to find field with 1 symbol + if(field == Qmmp::UNKNOWN) + { + fieldName.clear(); + fieldName.append((**i)); + field = m_fieldNames.value(fieldName, Qmmp::UNKNOWN); + } + + if(field != Qmmp::UNKNOWN) + { + Node node; + node.command = Node::PRINT_TEXT; + Param param; + param.type = Param::FIELD; + param.field = field; + node.params.append(param); + nodes->append(node); + (*i) += fieldName.size() - 1; + return true; + } + return false; +} + +bool MetaDataFormatter::parseIf(QList<MetaDataFormatter::Node> *nodes, QString::const_iterator *i, QString::const_iterator end) { - int pos = title.lastIndexOf("%if("); - int size = title.indexOf("%)",pos) - pos; + if((*i) + 1 == end || (*i) + 2 == end) + return false; + + if((**i) != QChar('i') || *((*i)+1) != QChar('f')) + return false; + + (*i)+=2; + + Node node; + node.command = Node::IF_KEYWORD; - QStringList args = title.mid (pos + 4, size - 4).split("%,"); - if(args.count() < 3) + int brackets_tracker = 0; + QString var1, var2, var3; + + enum { + STARTING = 0, + READING_VAR1, + READING_VAR2, + READING_VAR3, + FINISHED, + + } state = STARTING; + + while((*i) != end) { - qWarning("TitleFormatter: invalid title format"); - return title; + if((**i) == QChar('(')) + { + brackets_tracker++; + if(state == STARTING) + { + state = READING_VAR1; + (*i)++; + continue; + } + } + else if((**i) == QChar(')')) + brackets_tracker--; + + switch (state) + { + case STARTING: + { + break; + } + case READING_VAR1: + { + if((**i) == QChar(',') && brackets_tracker == 1) + { + state = READING_VAR2; + break; + } + var1.append((**i)); + break; + } + case READING_VAR2: + { + if((**i) == QChar(',') && brackets_tracker == 1) + { + state = READING_VAR3; + break; + } + var2.append((**i)); + break; + } + case READING_VAR3: + { + if((**i) == QChar(')') && brackets_tracker == 0) + { + state = FINISHED; + break; + } + var3.append((**i)); + break; + } + default: + break; + } + + if(state == FINISHED) + break; + + (*i)++; } - //process condition - bool cond = true; - foreach(QString arg, args.at(0).split("%&")) + + if(state != FINISHED) + { + qWarning("MetaDataFormatter: syntax error"); + return false; + } + + Param param1, param2, param3; + param1.type = Param::NODES, param2.type = Param::NODES, param3.type = Param::NODES; + param1.children = compile(var1); + param2.children = compile(var2); + param3.children = compile(var3); + node.params << param1 << param2 << param3; + nodes->append(node); + return true; +} + +void MetaDataFormatter::parseText(QList<MetaDataFormatter::Node> *nodes, QString::const_iterator *i, QString::const_iterator end) +{ + Node node; + node.command = Node::PRINT_TEXT; + Param param; + param.type = Param::TEXT; + node.params.append(param); + + forever { - cond &= !arg.isEmpty(); + if((*i) == end || (**i) == QChar('%')) + { + (*i)--; + break; + } + node.params[0].text.append(**i); + (*i)++; + } + if(!node.params[0].text.isEmpty()) + nodes->append(node); +} + +QString MetaDataFormatter::evalute(QList<Node> *nodes, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length) +{ + QString out; + for(int i = 0; i < nodes->count(); ++i) + { + Node node = nodes->at(i); + if(node.command == Node::PRINT_TEXT) + { + Param p = node.params.first(); + out.append(printParam(&p, metaData, length)); + + } + else if(node.command == Node::IF_KEYWORD) + { + QString var1 = printParam(&node.params[0], metaData, length); + if(var1.isEmpty()) + out.append(printParam(&node.params[2], metaData, length)); + else + out.append(printParam(&node.params[1], metaData, length)); + } + } + return out; +} + +QString MetaDataFormatter::printParam(MetaDataFormatter::Param *p, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length) +{ + switch (p->type) + { + case Param::FIELD: + return printField(p->field, metaData, length); + break; + case Param::TEXT: + return p->text; + break; + case Param::NODES: + return evalute(&p->children, metaData, length); + break; + default: + break; + } + return QString(); +} + +QString MetaDataFormatter::printField(int field, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length) +{ + if(field >= Qmmp::TITLE && field <= Qmmp::URL) + { + if(field == Qmmp::TITLE) + { + QString title = metaData->value(Qmmp::TITLE); + if(title.isEmpty()) //using file name if title is empty + { + title = metaData->value(Qmmp::URL).section('/',-1); + title = title.left(title.lastIndexOf('.')); + } + return title; + } + return metaData->value((Qmmp::MetaData) field); + } + else if(field == Param::TWO_DIGIT_TRACK) + { + return QString("%1").arg(metaData->value(Qmmp::TRACK),2,'0'); + } + else if(field == Param::DURATION) + { + return formatLength(length); + } + else if(field == Param::FILE_NAME) + { + return metaData->value(Qmmp::URL).section('/',-1); + } + return QString(); +} + +QString MetaDataFormatter::dumpNode(MetaDataFormatter::Node node) +{ + QString str; + QStringList params; + if(node.command == Node::PRINT_TEXT) + str += "PRINT_TEXT"; + else if(node.command == Node::IF_KEYWORD) + str += "IF_KEYWORD"; + str += "("; + foreach (Param p, node.params) + { + if(p.type == Param::FIELD) + params.append(QString("FIELD:%1").arg(p.field)); + else if(p.type == Param::TEXT) + params.append(QString("TEXT:%1").arg(p.text)); + else if(p.type == Param::NODES) + { + QStringList nodeStrList; + foreach (Node n, p.children) + { + nodeStrList.append(dumpNode(n)); + } + params.append(QString("NODES:%1").arg(nodeStrList.join(","))); + } + } + str.append(params.join(",")); + str.append(")"); + return str; +} + +QList<MetaDataFormatter::Node> MetaDataFormatter::compile(const QString &expr) +{ + QList <Node> nodes; + QString::const_iterator i = expr.constBegin(); + + while (i != expr.constEnd()) + { + if((*i) == QChar('%')) + { + i++; + if(i == expr.constEnd()) + continue; + + if(parseField(&nodes, &i, expr.constEnd())) + { + i++; + continue; + } + + if(parseIf(&nodes, &i, expr.constEnd())) + { + i++; + continue; + } + continue; + } + else + { + parseText(&nodes, &i, expr.constEnd()); + i++; + } } - QString r_str = cond ? args.at(1) : args.at(2); - title.replace (pos, size + 2, r_str); - if(title.contains("%if")) - return processIfKeyWord(title); - return title; + return nodes; } diff --git a/src/qmmpui/metadataformatter.h b/src/qmmpui/metadataformatter.h index 038c8ba34..39541a379 100644 --- a/src/qmmpui/metadataformatter.h +++ b/src/qmmpui/metadataformatter.h @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2009-2014 by Ilya Kotov * + * Copyright (C) 2015 by Ilya Kotov * * forkotov02@hotmail.ru * * * * This program is free software; you can redistribute it and/or modify * @@ -23,6 +23,7 @@ #include <QString> #include <QMap> +#include <QList> #include <qmmpui/playlisttrack.h> #include <qmmp/qmmp.h> @@ -34,7 +35,7 @@ class MetaDataFormatter public: /*! * Constructor. - * @param format Metadata template. + * @param pattern Metadata template. * Syntax: * %p - artist, * %a - album, @@ -52,17 +53,22 @@ public: * %l - duration, * %if(A,B,C) or %if(A&B&C,D,E) - condition. */ - MetaDataFormatter(const QString &format = QString()); + MetaDataFormatter(const QString &pattern = QString()); + + void setPattern(const QString &pattern); + + const QString pattern() const; + /*! * Converts metadata of item \b item to one string using template. */ - QString parse(const PlayListTrack *item); + QString format(const PlayListTrack *item); /*! * Converts metadata to one string using template. * @param metaData Metadata array. * @param length Length in seconds. */ - QString parse(const QMap<Qmmp::MetaData, QString> &metaData, qint64 length = 0); + QString format(const QMap<Qmmp::MetaData, QString> &metaData, qint64 length = 0); /*! * Returns formatted length (example: 05:02:03). * \param length Length in seconds. @@ -70,8 +76,54 @@ public: QString formatLength(qint64 length) const; private: - QString m_format; - QString processIfKeyWord(QString title); + struct Node; + struct Param; + + struct Node + { + enum { + PRINT_TEXT = 0, + IF_KEYWORD + } command; + + QList<Param> params; + }; + + struct Param + { + enum { + FIELD = 0, + TEXT, + NODES + } type; + + //extra fields + enum + { + TWO_DIGIT_TRACK = Qmmp::URL + 1, + DURATION, + FILE_NAME + }; + + int field; + QString text; + QList<Node> children; + }; + + bool parseField(QList<Node> *nodes, QString::const_iterator *i, QString::const_iterator end); + bool parseIf(QList<Node> *nodes, QString::const_iterator *i, QString::const_iterator end); + void parseText(QList<Node> *nodes, QString::const_iterator *i, QString::const_iterator end); + + QString evalute(QList<Node> *nodes, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length); + QString printParam(Param *p, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length); + QString printField(int field, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length); + + QString dumpNode(Node node); + + QList<MetaDataFormatter::Node> compile(const QString &expr); + QString m_pattern; + QList<MetaDataFormatter::Node> m_nodes; + QMap<QString, int> m_fieldNames; }; -#endif // METADATAFORMATTER_H +#endif // METADATAFORMATTER2_H diff --git a/src/qmmpui/metadataformatter2.cpp b/src/qmmpui/metadataformatter2.cpp deleted file mode 100644 index 67f78dd9f..000000000 --- a/src/qmmpui/metadataformatter2.cpp +++ /dev/null @@ -1,435 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - - -/* -Syntax: -%p - artist, -%a - album, -%aa - album artist, -%t - title, -%n - track number, -%NN - 2-digit track number, -%g - genre, -%c - comment, -%C - composer, -%D - disc number, -%f - file name, -%F - full path, -%y - year, -%l - duration, -%if(A,B,C) or %if(A&B&C,D,E) - condition. -*/ - -#include <QStringList> -#include <QUrl> -#include "metadataformatter2.h" - -struct MetaDataFormatter2::Param -{ - enum { - FIELD = 0, - TEXT, - NODES - } type; - - //extra fields - enum - { - TWO_DIGIT_TRACK = Qmmp::URL + 1, - DURATION, - FILE_NAME - }; - - int field; - QString text; - QList<Node> children; -}; - -struct MetaDataFormatter2::Node -{ - enum { - PRINT_TEXT = 0, - IF_KEYWORD - } command; - - QList<Param> params; -}; - -MetaDataFormatter2::MetaDataFormatter2(const QString &pattern) -{ - m_fieldNames.insert("t", Qmmp::TITLE); - m_fieldNames.insert("p", Qmmp::ARTIST); - m_fieldNames.insert("aa", Qmmp::ALBUMARTIST); - m_fieldNames.insert("a", Qmmp::ALBUM); - m_fieldNames.insert("c", Qmmp::COMMENT); - m_fieldNames.insert("g", Qmmp::GENRE); - m_fieldNames.insert("C", Qmmp::COMPOSER); - m_fieldNames.insert("y", Qmmp::YEAR); - m_fieldNames.insert("n", Qmmp::TRACK); - m_fieldNames.insert("D", Qmmp::DISCNUMBER); - m_fieldNames.insert("F", Qmmp::URL); - m_fieldNames.insert("NN", Param::TWO_DIGIT_TRACK); - m_fieldNames.insert("l", Param::DURATION); - m_fieldNames.insert("f", Param::FILE_NAME); - - setPattern(pattern); -} - -void MetaDataFormatter2::setPattern(const QString &pattern) -{ - m_pattern = pattern; - m_nodes.clear(); - - qDebug("MetaDataFormatter: pattern: %s", qPrintable(pattern)); - m_nodes = compile(pattern); - qDebug("MetaDataFormatter: dump of nodes"); - foreach (Node n, m_nodes) - { - qDebug("=>%s", qPrintable(dumpNode(n))); - } - qDebug("MetaDataFormatter: end of dump"); -} - -const QString MetaDataFormatter2::pattern() const -{ - return m_pattern; -} - -QString MetaDataFormatter2::format(const PlayListTrack *item) -{ - return format(*item, item->length()); -} - -QString MetaDataFormatter2::format(const QMap<Qmmp::MetaData, QString> &metaData, qint64 length) -{ - return evalute(&m_nodes, &metaData, length).trimmed(); -} - -QString MetaDataFormatter2::formatLength(qint64 length) const -{ - if(length <= 0) - return QString(); - QString str; - if(length >= 3600) - str = QString("%1:%2").arg(length/3600).arg(length%3600/60, 2, 10, QChar('0')); - else - str = QString("%1").arg(length%3600/60); - str += QString(":%1").arg(length%60, 2, 10, QChar('0')); - return str; -} - -bool MetaDataFormatter2::parseField(QList<Node> *nodes, QString::const_iterator *i, QString::const_iterator end) -{ - QString fieldName; - int field = Qmmp::UNKNOWN; - - //try to find field with 2 symbols - if((*i) + 1 != end) - { - fieldName.append((**i)); - fieldName.append(*((*i)+1)); - field = m_fieldNames.value(fieldName, Qmmp::UNKNOWN); - } - //try to find field with 1 symbol - if(field == Qmmp::UNKNOWN) - { - fieldName.clear(); - fieldName.append((**i)); - field = m_fieldNames.value(fieldName, Qmmp::UNKNOWN); - } - - if(field != Qmmp::UNKNOWN) - { - Node node; - node.command = Node::PRINT_TEXT; - Param param; - param.type = Param::FIELD; - param.field = field; - node.params.append(param); - nodes->append(node); - (*i) += fieldName.size() - 1; - return true; - } - return false; -} - -bool MetaDataFormatter2::parseIf(QList<MetaDataFormatter2::Node> *nodes, QString::const_iterator *i, QString::const_iterator end) -{ - if((*i) + 1 == end || (*i) + 2 == end) - return false; - - if((**i) != QChar('i') || *((*i)+1) != QChar('f')) - return false; - - (*i)+=2; - - Node node; - node.command = Node::IF_KEYWORD; - - int brackets_tracker = 0; - QString var1, var2, var3; - - enum { - STARTING = 0, - READING_VAR1, - READING_VAR2, - READING_VAR3, - FINISHED, - - } state = STARTING; - - while((*i) != end) - { - if((**i) == QChar('(')) - { - brackets_tracker++; - if(state == STARTING) - { - state = READING_VAR1; - (*i)++; - continue; - } - } - else if((**i) == QChar(')')) - brackets_tracker--; - - switch (state) - { - case STARTING: - { - break; - } - case READING_VAR1: - { - if((**i) == QChar(',') && brackets_tracker == 1) - { - state = READING_VAR2; - break; - } - var1.append((**i)); - break; - } - case READING_VAR2: - { - if((**i) == QChar(',') && brackets_tracker == 1) - { - state = READING_VAR3; - break; - } - var2.append((**i)); - break; - } - case READING_VAR3: - { - if((**i) == QChar(')') && brackets_tracker == 0) - { - state = FINISHED; - break; - } - var3.append((**i)); - break; - } - default: - break; - } - - if(state == FINISHED) - break; - - (*i)++; - } - - if(state != FINISHED) - { - qWarning("MetaDataFormatter: syntax error"); - return false; - } - - Param param1, param2, param3; - param1.type = Param::NODES, param2.type = Param::NODES, param3.type = Param::NODES; - param1.children = compile(var1); - param2.children = compile(var2); - param3.children = compile(var3); - node.params << param1 << param2 << param3; - nodes->append(node); - return true; -} - -void MetaDataFormatter2::parseText(QList<MetaDataFormatter2::Node> *nodes, QString::const_iterator *i, QString::const_iterator end) -{ - Node node; - node.command = Node::PRINT_TEXT; - Param param; - param.type = Param::TEXT; - node.params.append(param); - - forever - { - if((*i) == end || (**i) == QChar('%')) - { - (*i)--; - break; - } - node.params[0].text.append(**i); - (*i)++; - } - if(!node.params[0].text.isEmpty()) - nodes->append(node); -} - -QString MetaDataFormatter2::evalute(QList<Node> *nodes, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length) -{ - QString out; - for(int i = 0; i < nodes->count(); ++i) - { - Node node = nodes->at(i); - if(node.command == Node::PRINT_TEXT) - { - Param p = node.params.first(); - out.append(printParam(&p, metaData, length)); - - } - else if(node.command == Node::IF_KEYWORD) - { - QString var1 = printParam(&node.params[0], metaData, length); - if(var1.isEmpty()) - out.append(printParam(&node.params[2], metaData, length)); - else - out.append(printParam(&node.params[1], metaData, length)); - } - } - return out; -} - -QString MetaDataFormatter2::printParam(MetaDataFormatter2::Param *p, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length) -{ - switch (p->type) - { - case Param::FIELD: - return printField(p->field, metaData, length); - break; - case Param::TEXT: - return p->text; - break; - case Param::NODES: - return evalute(&p->children, metaData, length); - break; - default: - break; - } - return QString(); -} - -QString MetaDataFormatter2::printField(int field, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length) -{ - if(field >= Qmmp::TITLE && field <= Qmmp::URL) - { - if(field == Qmmp::TITLE) - { - QString title = metaData->value(Qmmp::TITLE); - if(title.isEmpty()) //using file name if title is empty - { - title = metaData->value(Qmmp::URL).section('/',-1); - title = title.left(title.lastIndexOf('.')); - } - return title; - } - return metaData->value((Qmmp::MetaData) field); - } - else if(field == Param::TWO_DIGIT_TRACK) - { - return QString("%1").arg(metaData->value(Qmmp::TRACK),2,'0'); - } - else if(field == Param::DURATION) - { - return formatLength(length); - } - else if(field == Param::FILE_NAME) - { - return metaData->value(Qmmp::URL).section('/',-1); - } - return QString(); -} - -QString MetaDataFormatter2::dumpNode(MetaDataFormatter2::Node node) -{ - QString str; - QStringList params; - if(node.command == Node::PRINT_TEXT) - str += "PRINT_TEXT"; - else if(node.command == Node::IF_KEYWORD) - str += "IF_KEYWORD"; - str += "("; - foreach (Param p, node.params) - { - if(p.type == Param::FIELD) - params.append(QString("FIELD:%1").arg(p.field)); - else if(p.type == Param::TEXT) - params.append(QString("TEXT:%1").arg(p.text)); - else if(p.type == Param::NODES) - { - QStringList nodeStrList; - foreach (Node n, p.children) - { - nodeStrList.append(dumpNode(n)); - } - params.append(QString("NODES:%1").arg(nodeStrList.join(","))); - } - } - str.append(params.join(",")); - str.append(")"); - return str; -} - -QList<MetaDataFormatter2::Node> MetaDataFormatter2::compile(const QString &expr) -{ - QList <Node> nodes; - QString::const_iterator i = expr.constBegin(); - - while (i != expr.constEnd()) - { - if((*i) == QChar('%')) - { - i++; - if(i == expr.constEnd()) - continue; - - if(parseField(&nodes, &i, expr.constEnd())) - { - i++; - continue; - } - - if(parseIf(&nodes, &i, expr.constEnd())) - { - i++; - continue; - } - continue; - } - else - { - parseText(&nodes, &i, expr.constEnd()); - i++; - } - } - return nodes; -} diff --git a/src/qmmpui/metadataformatter2.h b/src/qmmpui/metadataformatter2.h deleted file mode 100644 index 1e5bf7538..000000000 --- a/src/qmmpui/metadataformatter2.h +++ /dev/null @@ -1,97 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015 by Ilya Kotov * - * forkotov02@hotmail.ru * - * * - * 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, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * - ***************************************************************************/ - -#ifndef METADATAFORMATTER2_H -#define METADATAFORMATTER2_H - -#include <QString> -#include <QMap> -#include <qmmpui/playlisttrack.h> -#include <qmmp/qmmp.h> - -/*! @brief The MetaDataFormatter formats metadata using templates. - * @author Ilya Kotov <forkotov02@hotmail.ru> - */ -class MetaDataFormatter2 -{ -public: - /*! - * Constructor. - * @param pattern Metadata template. - * Syntax: - * %p - artist, - * %a - album, - * %aa - album artist, - * %t - title, - * %n - track number, - * %NN - 2-digit track number, - * %g - genre, - * %c - comment, - * %C - composer, - * %D - disc number, - * %f - file name, - * %F - full path, - * %y - year, - * %l - duration, - * %if(A,B,C) or %if(A&B&C,D,E) - condition. - */ - MetaDataFormatter2(const QString &pattern = QString()); - - void setPattern(const QString &pattern); - - const QString pattern() const; - - /*! - * Converts metadata of item \b item to one string using template. - */ - QString format(const PlayListTrack *item); - /*! - * Converts metadata to one string using template. - * @param metaData Metadata array. - * @param length Length in seconds. - */ - QString format(const QMap<Qmmp::MetaData, QString> &metaData, qint64 length = 0); - /*! - * Returns formatted length (example: 05:02:03). - * \param length Length in seconds. - */ - QString formatLength(qint64 length) const; - -private: - struct Node; - struct Param; - - bool parseField(QList<Node> *nodes, QString::const_iterator *i, QString::const_iterator end); - bool parseIf(QList<Node> *nodes, QString::const_iterator *i, QString::const_iterator end); - void parseText(QList<Node> *nodes, QString::const_iterator *i, QString::const_iterator end); - - QString evalute(QList<Node> *nodes, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length); - QString printParam(Param *p, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length); - QString printField(int field, const QMap<Qmmp::MetaData, QString> *metaData, qint64 length); - - QString dumpNode(Node node); - - QList<MetaDataFormatter2::Node> compile(const QString &expr); - QString m_pattern; - QList<Node> m_nodes; - QMap<QString, int> m_fieldNames; -}; - -#endif // METADATAFORMATTER2_H diff --git a/src/qmmpui/playlisttrack.cpp b/src/qmmpui/playlisttrack.cpp index e1bee339d..756dfcaab 100644 --- a/src/qmmpui/playlisttrack.cpp +++ b/src/qmmpui/playlisttrack.cpp @@ -167,7 +167,7 @@ const QString PlayListTrack::url() const void PlayListTrack::formatTitle() { MetaDataFormatter f(m_settings->titleFormat()); - m_formattedTitle = f.parse(this); + m_formattedTitle = f.format(this); if (m_formattedTitle.isEmpty()) m_formattedTitle = value(Qmmp::URL).section('/',-1); if (m_formattedTitle.isEmpty()) @@ -186,7 +186,7 @@ void PlayListTrack::formatGroup() return; } MetaDataFormatter f(m_settings->groupFormat()); - m_group = f.parse(this); + m_group = f.format(this); if (m_group.isEmpty()) m_group = qApp->translate("PlayListTrack", "Empty group"); if (m_settings->convertUnderscore()) diff --git a/src/qmmpui/qmmpui.pro b/src/qmmpui/qmmpui.pro index 58e9d2aa3..ebccd9594 100644 --- a/src/qmmpui/qmmpui.pro +++ b/src/qmmpui/qmmpui.pro @@ -49,7 +49,6 @@ HEADERS += general.h \ detailsdialog.h \ tageditor_p.h \ playlistmanager.h \ - metadataformatter.h \ templateeditor.h \ uifactory.h \ uiloader.h \ @@ -70,7 +69,7 @@ HEADERS += general.h \ groupedcontainer_p.h \ normalcontainer_p.h \ playlisttask_p.h \ - metadataformatter2.h + metadataformatter.h SOURCES += general.cpp \ playlistparser.cpp \ @@ -85,7 +84,6 @@ SOURCES += general.cpp \ detailsdialog.cpp \ tageditor.cpp \ playlistmanager.cpp \ - metadataformatter.cpp \ templateeditor.cpp \ uiloader.cpp \ uihelper.cpp \ @@ -105,7 +103,7 @@ SOURCES += general.cpp \ normalcontainer.cpp \ playlistcontainer.cpp \ playlisttask.cpp \ - metadataformatter2.cpp + metadataformatter.cpp FORMS += forms/detailsdialog.ui \ forms/tageditor.ui \ @@ -150,7 +148,6 @@ unix { mediaplayer.h \ detailsdialog.h \ playlistmanager.h \ - metadataformatter.h \ templateeditor.h \ uifactory.h \ uiloader.h \ |
