fix #848 - added a way to specify common post-process filter when importing feeds

This commit is contained in:
Martin Rotter 2022-12-08 10:45:42 +01:00
parent c0a737e93e
commit 4f45ce40ea
7 changed files with 104 additions and 36 deletions

View File

@ -27,6 +27,12 @@ FormStandardImportExport::FormStandardImportExport(StandardServiceRoot* service_
GuiUtilities::applyDialogProperties(*this, qApp->icons()->fromTheme(QSL("document-export")));
m_ui->m_txtPostProcessScript->textEdit()->setTabChangesFocus(true);
m_ui->m_txtPostProcessScript->textEdit()->setPlaceholderText(tr("Full command to execute"));
m_ui->m_txtPostProcessScript->textEdit()->setToolTip(tr("You can enter full command including interpreter here."));
m_ui->m_txtPostProcessScript->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Here you can enter script executaion line, including interpreter."));
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::StatusType::Error,
tr("No file is selected."),
tr("No file is selected."));
@ -42,6 +48,11 @@ FormStandardImportExport::FormStandardImportExport(StandardServiceRoot* service_
connect(m_ui->m_btnSelectFile, &QPushButton::clicked, this, &FormStandardImportExport::selectFile);
connect(m_ui->m_btnCheckAllItems, &QPushButton::clicked, m_model, &FeedsImportExportModel::checkAllItems);
connect(m_ui->m_btnUncheckAllItems, &QPushButton::clicked, m_model, &FeedsImportExportModel::uncheckAllItems);
connect(m_ui->m_txtPostProcessScript->textEdit(), &QPlainTextEdit::textChanged, this, [this]() {
onPostProcessScriptChanged(m_ui->m_txtPostProcessScript->textEdit()->toPlainText());
});
onPostProcessScriptChanged({});
}
FormStandardImportExport::~FormStandardImportExport() = default;
@ -58,6 +69,7 @@ void FormStandardImportExport::setMode(FeedsImportExportModel::Mode mode) {
m_ui->m_treeFeeds->expandAll();
m_ui->m_cmbRootNode->setVisible(false);
m_ui->m_lblRootNode->setVisible(false);
m_ui->m_gbFetchMetadata->setVisible(false);
m_ui->m_groupFile->setTitle(tr("Destination file"));
m_ui->m_groupFeeds->setTitle(tr("Source feeds && categories"));
m_ui->m_buttonBox->button(QDialogButtonBox::StandardButton::Ok)->setText(tr("&Export to file"));
@ -142,6 +154,15 @@ void FormStandardImportExport::onParsingProgress(int completed, int total) {
m_ui->m_progressBar->setValue(completed);
}
void FormStandardImportExport::onPostProcessScriptChanged(const QString& new_pp) {
if (QRegularExpression(QSL(SCRIPT_SOURCE_TYPE_REGEXP)).match(new_pp).hasMatch() || !new_pp.simplified().isEmpty()) {
m_ui->m_txtPostProcessScript->setStatus(LineEditWithStatus::StatusType::Ok, tr("Command is ok."));
}
else {
m_ui->m_txtPostProcessScript->setStatus(LineEditWithStatus::StatusType::Ok, tr("Command is empty."));
}
}
void FormStandardImportExport::selectExportFile(bool without_dialog) {
const QString the_file = qApp->homeFolder() + QDir::separator() +
QSL("rssguard_feeds_%1.opml").arg(QDate::currentDate().toString(Qt::DateFormat::ISODate));
@ -218,18 +239,8 @@ void FormStandardImportExport::selectImportFile() {
m_ui->m_lblSelectFile->setStatus(WidgetWithStatus::StatusType::Ok,
QDir::toNativeSeparators(selected_file),
tr("File is selected."));
QMessageBox::StandardButton answer =
MsgBox::show(this,
QMessageBox::Icon::Warning,
tr("Get online metadata"),
tr("Metadata for your feeds can be fetched online. Note that the action "
"could take several minutes, depending on number of feeds."),
tr("Do you want to fetch feed metadata online?"),
QString(),
QMessageBox::StandardButton::Yes | QMessageBox::StandardButton::No,
QMessageBox::StandardButton::Yes);
parseImportFile(selected_file, answer == QMessageBox::StandardButton::Yes);
parseImportFile(selected_file, m_ui->m_gbFetchMetadata->isChecked());
}
}
@ -250,11 +261,15 @@ void FormStandardImportExport::parseImportFile(const QString& file_name, bool fe
switch (m_conversionType) {
case ConversionType::OPML20:
m_model->importAsOPML20(input_data, fetch_metadata_online);
m_model->importAsOPML20(input_data,
fetch_metadata_online,
m_ui->m_txtPostProcessScript->textEdit()->toPlainText());
break;
case ConversionType::TxtUrlPerLine:
m_model->importAsTxtURLPerLine(input_data, fetch_metadata_online);
m_model->importAsTxtURLPerLine(input_data,
fetch_metadata_online,
m_ui->m_txtPostProcessScript->textEdit()->toPlainText());
break;
default:

View File

@ -16,13 +16,10 @@ class Category;
class StandardServiceRoot;
class FormStandardImportExport : public QDialog {
Q_OBJECT
Q_OBJECT
public:
enum class ConversionType {
OPML20 = 0,
TxtUrlPerLine = 1
};
enum class ConversionType { OPML20 = 0, TxtUrlPerLine = 1 };
explicit FormStandardImportExport(StandardServiceRoot* service_root, QWidget* parent = nullptr);
virtual ~FormStandardImportExport();
@ -37,6 +34,8 @@ class FormStandardImportExport : public QDialog {
void onParsingFinished(int count_failed, int count_succeeded, bool parsing_error);
void onParsingProgress(int completed, int total);
void onPostProcessScriptChanged(const QString& new_pp);
private:
void selectExportFile(bool without_dialog);
void selectImportFile();

View File

@ -6,8 +6,8 @@
<rect>
<x>0</x>
<y>0</y>
<width>478</width>
<height>434</height>
<width>500</width>
<height>550</height>
</rect>
</property>
<property name="windowTitle">
@ -49,6 +49,44 @@
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="m_gbFetchMetadata">
<property name="title">
<string>Fetch online metadata</string>
</property>
<property name="checkable">
<bool>true</bool>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="label_4">
<property name="text">
<string>Optional post-processing script</string>
</property>
<property name="buddy">
<cstring>m_txtPostProcessScript</cstring>
</property>
</widget>
</item>
<item>
<widget class="TextEditWithStatus" name="m_txtPostProcessScript" native="true">
<property name="minimumSize">
<size>
<width>0</width>
<height>50</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>100</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QFormLayout" name="formLayout_3">
<item row="0" column="0">
@ -229,9 +267,16 @@
<header>labelwithstatus.h</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TextEditWithStatus</class>
<extends>QWidget</extends>
<header>lineeditwithstatus.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<tabstops>
<tabstop>m_btnSelectFile</tabstop>
<tabstop>m_gbFetchMetadata</tabstop>
<tabstop>m_cmbRootNode</tabstop>
<tabstop>m_cbExportIcons</tabstop>
<tabstop>m_btnCheckAllItems</tabstop>

View File

@ -40,8 +40,6 @@ StandardFeedDetails::StandardFeedDetails(QWidget* parent) : QWidget(parent) {
QVariant::fromValue(StandardFeed::SourceType::Url));
m_ui.m_cmbSourceType->addItem(StandardFeed::sourceTypeToString(StandardFeed::SourceType::Script),
QVariant::fromValue(StandardFeed::SourceType::Script));
m_ui.m_txtPostProcessScript->setStatus(WidgetWithStatus::StatusType::Ok,
tr("Here you can enter script executaion line, including interpreter."));
// Add standard feed types.
m_ui.m_cmbType->addItem(StandardFeed::typeToString(StandardFeed::Type::Atom10),
@ -265,13 +263,9 @@ void StandardFeedDetails::onUrlChanged(const QString& new_url) {
}
void StandardFeedDetails::onPostProcessScriptChanged(const QString& new_pp) {
if (QRegularExpression(QSL(SCRIPT_SOURCE_TYPE_REGEXP)).match(new_pp).hasMatch()) {
if (QRegularExpression(QSL(SCRIPT_SOURCE_TYPE_REGEXP)).match(new_pp).hasMatch() || !new_pp.simplified().isEmpty()) {
m_ui.m_txtPostProcessScript->setStatus(LineEditWithStatus::StatusType::Ok, tr("Command is ok."));
}
else if (!new_pp.simplified().isEmpty()) {
m_ui.m_txtPostProcessScript->setStatus(LineEditWithStatus::StatusType::Warning,
tr("Command not seem to use \"#\" separator for arguments."));
}
else {
m_ui.m_txtPostProcessScript->setStatus(LineEditWithStatus::StatusType::Ok, tr("Command is empty."));
}

View File

@ -15,9 +15,9 @@ class Category;
class RootItem;
class StandardFeedDetails : public QWidget {
Q_OBJECT
Q_OBJECT
friend class FormStandardFeedDetails;
friend class FormStandardFeedDetails;
public:
explicit StandardFeedDetails(QWidget* parent = nullptr);

View File

@ -145,7 +145,9 @@ bool FeedsImportExportModel::exportToOMPL20(QByteArray& result, bool export_icon
return true;
}
void FeedsImportExportModel::importAsOPML20(const QByteArray& data, bool fetch_metadata_online) {
void FeedsImportExportModel::importAsOPML20(const QByteArray& data,
bool fetch_metadata_online,
const QString& post_process_script) {
emit parsingStarted();
emit layoutAboutToBeChanged();
@ -200,10 +202,16 @@ void FeedsImportExportModel::importAsOPML20(const QByteArray& data, bool fetch_m
if (!feed_url.isEmpty()) {
try {
if (fetch_metadata_online) {
StandardFeed* guessed =
StandardFeed::guessFeed(StandardFeed::SourceType::Url, feed_url, {}, {}, {}, custom_proxy);
StandardFeed* guessed = StandardFeed::guessFeed(StandardFeed::SourceType::Url,
feed_url,
post_process_script,
{},
{},
custom_proxy);
guessed->setSource(feed_url);
guessed->setPostProcessScript(post_process_script);
active_model_item->appendChild(guessed);
succeded++;
add_offline_anyway = false;
@ -319,7 +327,9 @@ bool FeedsImportExportModel::exportToTxtURLPerLine(QByteArray& result) {
return true;
}
void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray& data, bool fetch_metadata_online) {
void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray& data,
bool fetch_metadata_online,
const QString& post_process_script) {
emit parsingStarted();
emit layoutAboutToBeChanged();
setRootItem(nullptr);
@ -341,9 +351,12 @@ void FeedsImportExportModel::importAsTxtURLPerLine(const QByteArray& data, bool
try {
if (fetch_metadata_online) {
StandardFeed* guessed = StandardFeed::guessFeed(StandardFeed::SourceType::Url, url, {}, {}, {}, custom_proxy);
StandardFeed* guessed =
StandardFeed::guessFeed(StandardFeed::SourceType::Url, url, post_process_script, {}, {}, custom_proxy);
guessed->setSource(url);
guessed->setPostProcessScript(post_process_script);
root_item->appendChild(guessed);
succeded++;
add_offline_anyway = false;

View File

@ -17,12 +17,14 @@ class FeedsImportExportModel : public AccountCheckSortedModel {
// Exports to OPML 2.0
// NOTE: http://dev.opml.org/spec2.html
bool exportToOMPL20(QByteArray& result, bool export_icons);
void importAsOPML20(const QByteArray& data, bool fetch_metadata_online);
void importAsOPML20(const QByteArray& data, bool fetch_metadata_online, const QString& post_process_script = {});
// Exports to plain text format
// where there is one feed URL per line.
bool exportToTxtURLPerLine(QByteArray& result);
void importAsTxtURLPerLine(const QByteArray& data, bool fetch_metadata_online);
void importAsTxtURLPerLine(const QByteArray& data,
bool fetch_metadata_online,
const QString& post_process_script = {});
Mode mode() const;
void setMode(Mode mode);