2023-05-062023-05-06 Fred Gleason <fredg@paravelsystems.com>

* Refactored the RSS reports in rdadmin(1) to include information on
	missing	items.
	* Modified the feed report in rdcastmanager to include information
	on missing items.

Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
Fred Gleason 2023-05-06 11:17:44 -04:00
parent 3cf2fe1ce4
commit 47d30f803e
20 changed files with 881 additions and 287 deletions

View File

@ -24056,3 +24056,8 @@
* Added a 'Generate Back Report' item to the right-click menu in * Added a 'Generate Back Report' item to the right-click menu in
the 'Podcast Feeds' list in the 'Rivendell Feed List' dialog in the 'Podcast Feeds' list in the 'Rivendell Feed List' dialog in
rdadmin(1). rdadmin(1).
2023-05-06 Fred Gleason <fredg@paravelsystems.com>
* Refactored the RSS reports in rdadmin(1) to include information on
missing items.
* Modified the feed report in rdcastmanager to include information
on missing items.

View File

@ -2,7 +2,7 @@
## ##
## docs/dtds/Makefile.am for Rivendell ## docs/dtds/Makefile.am for Rivendell
## ##
## (C) Copyright 2020 Fred Gleason <fredg@paravelsystems.com> ## (C) Copyright 2020-2023 Fred Gleason <fredg@paravelsystems.com>
## ##
## This program is free software; you can redistribute it and/or modify ## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License version 2 as ## it under the terms of the GNU General Public License version 2 as
@ -29,15 +29,20 @@
all-local: direct.html\ all-local: direct.html\
direct.pdf\ direct.pdf\
rivendell.html\
rivendell.pdf\
superfeed.html\ superfeed.html\
superfeed.pdf superfeed.pdf
EXTRA_DIST = superfeed.html\ EXTRA_DIST = direct.html\
superfeed.pdf\
superfeed.xml\
direct.html\
direct.pdf\ direct.pdf\
direct.xml direct.xml\
rivendell.html\
rivendell.pdf\
rivendell.xml\
superfeed.html\
superfeed.pdf\
superfeed.xml
CLEANFILES = *~ CLEANFILES = *~
MAINTAINERCLEANFILES = *~\ MAINTAINERCLEANFILES = *~\

183
docs/dtds/rivendell.xml Normal file
View File

@ -0,0 +1,183 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
<article xmlns="http://docbook.org/ns/docbook" version="5.0">
<info>
<title>The Rivendell &quot;rivendell&quot; Namespace</title>
<subtitle>Version 0.1</subtitle>
<revnumber>v0.1</revnumber>
<author>
<personname>
<firstname>Fred</firstname>
<surname>Gleason</surname>
<email>fredg@paravelsystems.com</email>
</personname>
</author>
<edition>
v0.1
</edition>
<copyright><year>2023</year><holder>Fred Gleason</holder></copyright>
<legalnotice>
<para>
Permission is granted to copy, distribute and/or modify this document
under the terms of the GNU Free Documentation License, Version 1.3
or any later version published by the Free Software Foundation;
with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts.
</para>
</legalnotice>
</info>
<sect1 xml:id="overview">
<title>Overview</title>
<para>
The &quot;superfeed&quot; XML namespace adds support for additional
fields used by Rivendell RSS podcasting report generation. It's use is
limited to internal documents generated within Rivendell.
</para>
</sect1>
<sect1 xml:id="namespace_declaration">
<title>Namespace Declaration</title>
<para>
The namespace declaration is:
</para>
<para>
<code>xmlns:rivendell=&quot;http://www.rivendellaudio.org/dtds/rivendell-0.1.dtd&quot;</code>
</para>
</sect1>
<sect1 xml:id="fields">
<title>Fields</title>
<para>
The namespace adds the following fields:
</para>
<variablelist>
<varlistentry>
<term>
<code>&lt;item rivendell:id=<replaceable>id</replaceable>&gt;</code>
</term>
<listitem>
<para>
This attribute is added to the &lt;channel&gt; and &lt;item&gt;
tags. It is a unique unsigned integer ID that associates the object
to a record in the <computeroutput>FEEDS</computeroutput> and
<computeroutput>PODCASTS</computeroutput> database tables,
respectively.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>
<code>&lt;item rivendell:status=<replaceable>class-name</replaceable>&gt;</code>
</term>
<listitem>
<para>
This attribute is added to the &lt;item&gt; tag. It indicates
a class name to use for this item when rendering reports.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect1>
<sect1 xml:id="example">
<title>Example</title>
<literallayout>
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;rss version=&quot;2.0&quot; xmlns:itunes=&quot;http://www.itunes.com/dtds/podcast-1.0.dtd&quot; xmlns:content=&quot;http://purl.org/rss/1.0/modules/content/&quot; xmlns:atom=&quot;http://www.w3.org/2005/Atom&quot; xmlns:superfeed=&quot;http://www.rivendellaudio.org/dtds/superfeed-0.1.dtd&quot; xmlns:rivendell=&quot;http://www.rivendellaudio.org/dtds/rivendell-0.1.dtd&quot;&gt;
&lt;channel rivendell:id=&quot;1234&quot;&gt;
&lt;title&gt;Rivendell Radio Automation&lt;/title&gt;
&lt;description&gt;All about the Rivendell Radio Automation System&lt;/description&gt;
&lt;itunes:summary&gt;All about the Rivendell Radio Automation System&lt;/itunes:summary&gt;
&lt;category&gt;Technology&lt;/category&gt;
&lt;link&gt;http://feeds.example.com/rivendel&lt;/link&gt;
&lt;language&gt;en-us&lt;/language&gt;
&lt;copyright&gt;© 2020 John Q. Author&lt;/copyright&gt;
&lt;lastBuildDate&gt;Thu, 4 Jun 2020 12:18:54 GMT&lt;/lastBuildDate&gt;
&lt;pubDate&gt;Thu, 21 May 2020 10:43:55 GMT&lt;/pubDate&gt;
&lt;managingEditor&gt;editor@example.com&lt;/managingEditor&gt;
&lt;webMaster&gt;webmaster@example.com&lt;/webMaster&gt;
&lt;generator&gt;Rivendell 3.3.0int1&lt;/generator&gt;
&lt;image&gt;
&lt;url&gt;http://feeds.example.com/rivendel/img000022_000038.png&lt;/url&gt;
&lt;title&gt;Rivendell Radio Automation&lt;/title&gt;
&lt;link&gt;http://feeds.example.com/rivendel&lt;/link&gt;
&lt;width&gt;2048&lt;/width&gt;
&lt;height&gt;2048&lt;/height&gt;
&lt;description&gt;The Rivendell Icon&lt;/description&gt;
&lt;/image&gt;
&lt;atom:link href=&quot;http://feeds.example.com/rivendel/RIVENDEL.rss&quot; rel=&quot;self&quot; type=&quot;application/rss+xml&quot; /&gt;
&lt;itunes:author&gt;author@example.com&lt;/itunes:author&gt;
&lt;itunes:type&gt;episodic&lt;/itunes:type&gt;
&lt;itunes:owner&gt;
&lt;itunes:name&gt;John Q. Author&lt;/itunes:name&gt;
&lt;itunes:email&gt;fredg@paravelsystems.com&lt;/itunes:email&gt;
&lt;/itunes:owner&gt;
&lt;itunes:image href=&quot;http://feeds.example.com/rivendel/img000022_000038.png&quot; /&gt;
&lt;itunes:category text=&quot;Technology&quot; /&gt;
&lt;itunes:explicit&gt;false&lt;/itunes:explicit&gt;
&lt;item rivendell:id=&quot;4321&quot; rivendell:class=&quot;active-rounded-block&quot;&gt;
&lt;superfeed:channelTitle&gt;RDAirPlay&lt;/superfeed:channelTitle&gt;
&lt;superfeed:channelDescription&gt;All about RDAirPlay in Rivendell&lt;/superfeed:channelDescription&gt;
&lt;title&gt;Thurber Jewelers&lt;/title&gt;
&lt;itunes:title&gt;Thurber Jewelers&lt;/itunes:title&gt;
&lt;link&gt;http://feeds.example.com/airplay&lt;/link&gt;
&lt;guid isPermaLink=&quot;false&quot;&gt;http://feeds.example.com/airplay/000019_000026.mp3_000019_000026&lt;/guid&gt;
&lt;description&gt;All about RDAirPlay in Rivendell&lt;/description&gt;
&lt;itunes:summary&gt;All about RDAirPlay in Rivendell&lt;/itunes:summary&gt;
&lt;author&gt;someone@example.com (John Q. Author)&lt;/author&gt;
&lt;itunes:author&gt;someone@example.com (John Q. Author)&lt;/itunes:author&gt;
&lt;comments&gt;http://feeds.example.com/airplay&lt;/comments&gt;
&lt;source url=&quot;http://feeds.example.com/airplay/RIVENDEL&quot;&gt;Rivendell Radio Automation&lt;/source&gt;
&lt;enclosure url=&quot;http://feeds.example.com/airplay/000019_000026.mp3&quot; length=&quot;170496&quot; type=&quot;audio/mpeg&quot; /&gt;
&lt;category&gt;Technology&lt;/category&gt;
&lt;pubDate&gt;Thu, 21 May 2020 20:31:26 GMT&lt;/pubDate&gt;
&lt;itunes:duration&gt;14&lt;/itunes:duration&gt;
&lt;itunes:image href=&quot;http://feeds.example.com/airplay/img000019_000024.png&quot; /&gt;
&lt;itunes:explicit&gt;false&lt;/itunes:explicit&gt;
&lt;/item&gt;
&lt;item rivendell:id=&quot;4322&quot; rivendell:class=&quot;active-rounded-block&quot;&gt;
&lt;superfeed:channelTitle&gt;RDCartSlots&lt;/superfeed:channelTitle&gt;
&lt;superfeed:channelDescription&gt;All channel all about RDCartSlots!&lt;/superfeed:channelDescription&gt;
&lt;title&gt;Liberty Tax&lt;/title&gt;
&lt;itunes:title&gt;Liberty Tax&lt;/itunes:title&gt;
&lt;link&gt;http://feeds.example.com&lt;/link&gt;
&lt;guid isPermaLink=&quot;false&quot;&gt;http://feeds.example.com/cartslts/000025_000025.mp3_000025_000025&lt;/guid&gt;
&lt;description&gt;The Liberty tax advisors.&lt;/description&gt;
&lt;itunes:summary&gt;The Liberty tax advisors.&lt;/itunes:summary&gt;
&lt;author&gt;someone@example.com (John Q. Author)&lt;/author&gt;
&lt;itunes:author&gt;someone@example.com (John Q. Author)&lt;/itunes:author&gt;
&lt;comments&gt;http://feeds.example.com/cartslts&lt;/comments&gt;
&lt;source url=&quot;http://feeds.example.com/cartslts/RIVENDEL&quot;&gt;Rivendell Radio Automation&lt;/source&gt;
&lt;enclosure url=&quot;http://feeds.example.com/cartslts/000025_000025.mp3&quot; length=&quot;369216&quot; type=&quot;audio/mpeg&quot; /&gt;
&lt;category&gt;Technology&lt;/category&gt;
&lt;pubDate&gt;Thu, 21 May 2020 19:17:26 GMT&lt;/pubDate&gt;
&lt;itunes:duration&gt;15&lt;/itunes:duration&gt;
&lt;itunes:image href=&quot;http://feeds.example.com/cartslts/img000025_000037.png&quot; /&gt;
&lt;itunes:explicit&gt;false&lt;/itunes:explicit&gt;
&lt;/item&gt;
&lt;item&gt;
&lt;superfeed:channelTitle&gt;RDLibrary&lt;/superfeed:channelTitle&gt;
&lt;superfeed:channelDescription&gt;A channel all about RDLibrary&lt;/superfeed:channelDescription&gt;
&lt;title&gt;The Peanut Shoppe&lt;/title&gt;
&lt;itunes:title&gt;The Peanut Shoppe&lt;/itunes:title&gt;
&lt;link&gt;http://feeds.example.com/library&lt;/link&gt;
&lt;guid isPermaLink=&quot;false&quot;&gt;http://feeds.example.com/library/000024_000024.mp3_000024_000024&lt;/guid&gt;
&lt;description&gt;A trip to a peanut and candy shop in downtown Wadsworth OH.&lt;/description&gt;
&lt;itunes:summary&gt;A trip to a peanut and candy shop in downtown Wadsworth OH.&lt;/itunes:summary&gt;
&lt;author&gt;someone@example.com (John Q. Author)&lt;/author&gt;
&lt;itunes:author&gt;someone@example.com (John Q. Author)&lt;/itunes:author&gt;
&lt;comments&gt;http://feeds.example.com/library&lt;/comments&gt;
&lt;source url=&quot;http://feeds.example.com/library/RIVENDEL&quot;&gt;Rivendell Radio Automation&lt;/source&gt;
&lt;enclosure url=&quot;http://feeds.example.com/library/000024_000024.mp3&quot; length=&quot;196992&quot; type=&quot;audio/mpeg&quot; /&gt;
&lt;category&gt;Technology&lt;/category&gt;
&lt;pubDate&gt;Thu, 21 May 2020 19:14:53 GMT&lt;/pubDate&gt;
&lt;itunes:duration&gt;16&lt;/itunes:duration&gt;
&lt;itunes:image href=&quot;http://feeds.example.com/library/img000024_000036.png&quot; /&gt;
&lt;itunes:explicit&gt;false&lt;/itunes:explicit&gt;
&lt;/item&gt;
&lt;/channel&gt;
&lt;/rss&gt;
</literallayout>
</sect1>
</article>

View File

@ -136,7 +136,6 @@ dist_librd_la_SOURCES = dbversion.h\
rdexport_settings_dialog.cpp rdexport_settings_dialog.h\ rdexport_settings_dialog.cpp rdexport_settings_dialog.h\
rdfeed.cpp rdfeed.h\ rdfeed.cpp rdfeed.h\
rdfeedlistmodel.cpp rdfeedlistmodel.h\ rdfeedlistmodel.cpp rdfeedlistmodel.h\
rdfeedlistview.cpp rdfeedlistview.h\
rdfontengine.cpp rdfontengine.h\ rdfontengine.cpp rdfontengine.h\
rdformpost.cpp rdformpost.h\ rdformpost.cpp rdformpost.h\
rdflacdecode.cpp rdflacdecode.h\ rdflacdecode.cpp rdflacdecode.h\
@ -348,7 +347,6 @@ nodist_librd_la_SOURCES = moc_rdadd_cart.cpp\
moc_rdexport_settings_dialog.cpp\ moc_rdexport_settings_dialog.cpp\
moc_rdfeed.cpp\ moc_rdfeed.cpp\
moc_rdfeedlistmodel.cpp\ moc_rdfeedlistmodel.cpp\
moc_rdfeedlistview.cpp\
moc_rdframe.cpp\ moc_rdframe.cpp\
moc_rdget_ath.cpp\ moc_rdget_ath.cpp\
moc_rdgetpasswd.cpp\ moc_rdgetpasswd.cpp\

View File

@ -44,6 +44,7 @@
#include "rdwavefile.h" #include "rdwavefile.h"
#include "rdwebresult.h" #include "rdwebresult.h"
#include "rdxport_interface.h" #include "rdxport_interface.h"
#include "rdxsltengine.h"
int __RDFeed_Debug_Callback(CURL *handle,curl_infotype type,char *data, int __RDFeed_Debug_Callback(CURL *handle,curl_infotype type,char *data,
size_t size,void *userptr) size_t size,void *userptr)
@ -69,6 +70,8 @@ size_t __RDFeed_Download_Callback(char *ptr,size_t size,size_t nmemb,
} }
RDFeed::RDFeed(const QString &keyname,RDConfig *config,QObject *parent) RDFeed::RDFeed(const QString &keyname,RDConfig *config,QObject *parent)
: QObject(parent) : QObject(parent)
{ {
@ -956,90 +959,6 @@ QString RDFeed::imageUrl(int img_id) const
} }
bool RDFeed::downloadXml(QByteArray *xml,QString *err_msg)
{
long response_code;
CURL *curl=NULL;
CURLcode curl_err;
char curl_errorbuffer[CURL_ERROR_SIZE];
struct curl_httppost *first=NULL;
struct curl_httppost *last=NULL;
//
// Generate POST Data
//
curl_formadd(&first,&last,CURLFORM_PTRNAME,"COMMAND",
CURLFORM_COPYCONTENTS,
QString::asprintf("%u",RDXPORT_COMMAND_DOWNLOAD_RSS).toUtf8().
constData(),
CURLFORM_END);
curl_formadd(&first,&last,CURLFORM_PTRNAME,"LOGIN_NAME",
CURLFORM_COPYCONTENTS,rda->user()->name().toUtf8().constData(),
CURLFORM_END);
curl_formadd(&first,&last,CURLFORM_PTRNAME,"PASSWORD",
CURLFORM_COPYCONTENTS,
rda->user()->password().toUtf8().constData(),CURLFORM_END);
curl_formadd(&first,&last,CURLFORM_PTRNAME,"ID",
CURLFORM_COPYCONTENTS,
QString::asprintf("%u",feed_id).toUtf8().constData(),
CURLFORM_END);
//
// Set up the transfer
//
if((curl=curl_easy_init())==NULL) {
curl_formfree(first);
return false;
}
QStringList *err_msgs=SetupCurlLogging(curl);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,__RDFeed_Download_Callback);
feed_xml.clear();
curl_easy_setopt(curl,CURLOPT_WRITEDATA,xml);
curl_easy_setopt(curl,CURLOPT_HTTPPOST,first);
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,curl_errorbuffer);
curl_easy_setopt(curl,CURLOPT_USERAGENT,
rda->config()->userAgent().toUtf8().constData());
curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT);
curl_easy_setopt(curl,CURLOPT_NOPROGRESS,1);
curl_easy_setopt(curl,CURLOPT_URL,
rda->station()->webServiceUrl(rda->config()).toUtf8().constData());
rda->syslog(LOG_DEBUG,"using web service URL: %s",
rda->station()->webServiceUrl(rda->config()).toUtf8().constData());
//
// Send it
//
if((curl_err=curl_easy_perform(curl))!=CURLE_OK) {
*err_msg=QString::fromUtf8(curl_errorbuffer);
curl_easy_cleanup(curl);
curl_formfree(first);
ProcessCurlLogging("RDFeed::postPodcast()",err_msgs);
return false;
}
//
// Clean up
//
curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code);
curl_easy_cleanup(curl);
curl_formfree(first);
//
// Process the results
//
if((response_code<200)||(response_code>299)) {
*err_msg=tr("remote server returned unexpected response code")+
QString::asprintf(" %ld",response_code);
ProcessCurlLogging("RDFeed::postPodcast()",err_msgs);
return false;
}
delete err_msgs;
return true;
}
bool RDFeed::postXml(QString *err_msg) bool RDFeed::postXml(QString *err_msg)
{ {
long response_code; long response_code;
@ -1714,7 +1633,8 @@ unsigned RDFeed::postLog(const QString &logname,const QTime &start_time,
} }
QString RDFeed::rssXml(QString *err_msg,const QDateTime &now,bool *ok) QString RDFeed::rssXml(QString *err_msg,const QDateTime &now,bool *ok,
QList<unsigned> *active_cast_ids)
{ {
QString ret; QString ret;
@ -1791,7 +1711,8 @@ QString RDFeed::rssXml(QString *err_msg,const QDateTime &now,bool *ok)
// //
// Render Channel XML // Render Channel XML
// //
ret+=" <channel>\n"; ret+=QString::asprintf(" <channel rivendell:id=\"%u\">\n",
chan_q->value(18).toUInt());
ret+=ResolveChannelWildcards(channel_template,chan_q,now)+"\r\n"; ret+=ResolveChannelWildcards(channel_template,chan_q,now)+"\r\n";
// //
@ -1852,7 +1773,15 @@ QString RDFeed::rssXml(QString *err_msg,const QDateTime &now,bool *ok)
} }
item_q=new RDSqlQuery(sql); item_q=new RDSqlQuery(sql);
while(item_q->next()) { while(item_q->next()) {
ret+=" <item>\r\n"; if((active_cast_ids==NULL)||
(active_cast_ids->contains(item_q->value(14).toUInt()))) {
ret+=QString::
asprintf(" <item rivendell:id=\"%u\" rivendell:style=\"active-rounded-block\">\r\n",item_q->value(14).toUInt());
}
else {
ret+=QString::
asprintf(" <item rivendell:id=\"%u\" rivendell:style=\"missing-rounded-block\">\r\n",item_q->value(14).toUInt());
}
ret+=ResolveItemWildcards(item_template,item_q,chan_q); ret+=ResolveItemWildcards(item_template,item_q,chan_q);
ret+="\r\n"; ret+="\r\n";
ret+=" </item>\r\n"; ret+=" </item>\r\n";
@ -1871,6 +1800,256 @@ QString RDFeed::rssXml(QString *err_msg,const QDateTime &now,bool *ok)
} }
bool RDFeed::rssFrontXml(QByteArray *xml,QString *err_msg) const
{
long response_code;
CURL *curl=NULL;
CURLcode curl_err;
char curl_errorbuffer[CURL_ERROR_SIZE];
struct curl_httppost *first=NULL;
struct curl_httppost *last=NULL;
//
// Generate POST Data
//
curl_formadd(&first,&last,CURLFORM_PTRNAME,"COMMAND",
CURLFORM_COPYCONTENTS,
QString::asprintf("%u",RDXPORT_COMMAND_DOWNLOAD_RSS).toUtf8().
constData(),
CURLFORM_END);
curl_formadd(&first,&last,CURLFORM_PTRNAME,"LOGIN_NAME",
CURLFORM_COPYCONTENTS,rda->user()->name().toUtf8().constData(),
CURLFORM_END);
curl_formadd(&first,&last,CURLFORM_PTRNAME,"PASSWORD",
CURLFORM_COPYCONTENTS,
rda->user()->password().toUtf8().constData(),CURLFORM_END);
curl_formadd(&first,&last,CURLFORM_PTRNAME,"ID",
CURLFORM_COPYCONTENTS,
QString::asprintf("%u",feed_id).toUtf8().constData(),
CURLFORM_END);
//
// Set up the transfer
//
if((curl=curl_easy_init())==NULL) {
curl_formfree(first);
return false;
}
QStringList *err_msgs=SetupCurlLogging(curl);
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,__RDFeed_Download_Callback);
xml->clear();
curl_easy_setopt(curl,CURLOPT_WRITEDATA,xml);
curl_easy_setopt(curl,CURLOPT_HTTPPOST,first);
curl_easy_setopt(curl,CURLOPT_ERRORBUFFER,curl_errorbuffer);
curl_easy_setopt(curl,CURLOPT_USERAGENT,
rda->config()->userAgent().toUtf8().constData());
curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT);
curl_easy_setopt(curl,CURLOPT_NOPROGRESS,1);
curl_easy_setopt(curl,CURLOPT_URL,
rda->station()->webServiceUrl(rda->config()).toUtf8().constData());
rda->syslog(LOG_DEBUG,"using web service URL: %s",
rda->station()->webServiceUrl(rda->config()).toUtf8().constData());
//
// Send it
//
if((curl_err=curl_easy_perform(curl))!=CURLE_OK) {
*err_msg=QString::fromUtf8(curl_errorbuffer);
curl_easy_cleanup(curl);
curl_formfree(first);
ProcessCurlLogging("RDFeed::postPodcast()",err_msgs);
return false;
}
//
// Clean up
//
curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code);
curl_easy_cleanup(curl);
curl_formfree(first);
//
// Process the results
//
if((response_code<200)||(response_code>299)) {
*err_msg=tr("remote server returned unexpected response code")+
QString::asprintf(" %ld",response_code);
ProcessCurlLogging("RDFeed::postPodcast()",err_msgs);
return false;
}
delete err_msgs;
return true;
}
bool RDFeed::rssBackXml(QByteArray *xml,QString *err_msg) const
{
CURL *curl=NULL;
CURLcode curl_err;
long response_code;
bool ret=false;
if((curl=curl_easy_init())==NULL) {
*err_msg=tr("Unable to initialize CURL");
ret=false;
}
else {
QByteArray src_xml;
curl_easy_setopt(curl,CURLOPT_WRITEFUNCTION,__RDFeed_Download_Callback);
curl_easy_setopt(curl,CURLOPT_WRITEDATA,xml);
curl_easy_setopt(curl,CURLOPT_USERAGENT,
rda->config()->userAgent().toUtf8().constData());
curl_easy_setopt(curl,CURLOPT_TIMEOUT,RD_CURL_TIMEOUT);
curl_easy_setopt(curl,CURLOPT_NOPROGRESS,1);
curl_easy_setopt(curl,CURLOPT_URL,
RDFeed::publicUrl(baseUrl(""),feed_keyname).
toUtf8().constData());
curl_err=curl_easy_perform(curl);
if((ret=(curl_err==CURLE_OK))) {
curl_easy_getinfo(curl,CURLINFO_RESPONSE_CODE,&response_code);
if((ret=(response_code>=200)||(response_code<300))) {
ret=true;
*err_msg=QObject::tr("Server returned result code")+
QString::asprintf(" %lu ",response_code)+*xml;
}
}
else {
*err_msg=QObject::tr("Curl error")+" ["+curl_easy_strerror(curl_err)+"].";
ret=false;
}
}
curl_easy_cleanup(curl);
return ret;
}
void RDFeed::activeCasts(QList<unsigned> *cast_ids)
{
cast_ids->clear();
QString sql=QString("select ")+
"`ID` "+ // 00
"from `PODCASTS` where "+
QString::asprintf("`FEED_ID`=%u && ",feed_id)+
QString::asprintf("`STATUS`=%u ",RDPodcast::StatusActive)+
"order by `ORIGIN_DATETIME` desc";
RDSqlQuery *q=new RDSqlQuery(sql);
while(q->next()) {
cast_ids->push_back(q->value(0).toUInt());
}
delete q;
}
bool RDFeed::frontActiveCasts(QList<unsigned> *cast_ids,QString *err_msg)
{
QByteArray xml;
bool ret=false;
QString text;
bool ok=false;
cast_ids->clear();
if(rssFrontXml(&xml,err_msg)) {
RDXsltEngine *xslt=
new RDXsltEngine("/usr/share/rivendell/rss-item-enclosures.xsl",this);
if(xslt->transform(&text,xml,err_msg)) {
QStringList f0=text.split("|",QString::SkipEmptyParts);
for(int i=0;i<f0.size();i++) {
QStringList f1=f0.at(i).split("/",QString::SkipEmptyParts);
QStringList f2=f1.last().split(".",QString::KeepEmptyParts);
if(f2.size()==2) {
QStringList f3=f2.first().split("_",QString::KeepEmptyParts);
if(f3.size()==2) {
cast_ids->push_back(f3.last().toUInt(&ok));
if(ok) {
ret=ok;
// OK, keep going
}
else {
// Integer conversion failed
*err_msg=QObject::tr("Internal error 1");
ret=false;
break;
}
}
else {
// f3: Split on '_' failed
*err_msg=QObject::tr("Internal error 2");
ret=false;
break;
}
}
else {
// f2: Split on '.' failed
*err_msg=QObject::tr("Internal error 3");
ret=false;
break;
}
}
}
delete xslt;
}
return ret;
}
bool RDFeed::backActiveCasts(QList<unsigned> *cast_ids,QString *err_msg)
{
QByteArray xml;
bool ret=false;
QString text;
bool ok=false;
cast_ids->clear();
if(rssBackXml(&xml,err_msg)) {
RDXsltEngine *xslt=
new RDXsltEngine("/usr/share/rivendell/rss-item-enclosures.xsl",
this);
if(xslt->transform(&text,xml,err_msg)) {
QStringList f0=text.split("|",QString::SkipEmptyParts);
for(int i=0;i<f0.size();i++) {
QStringList f1=f0.at(i).split("/",QString::SkipEmptyParts);
QStringList f2=f1.last().split(".",QString::KeepEmptyParts);
if(f2.size()==2) {
QStringList f3=f2.first().split("_",QString::KeepEmptyParts);
if(f3.size()==2) {
cast_ids->push_back(f3.last().toUInt(&ok));
if(ok) {
ret=ok;
// OK, keep going
}
else {
// Integer conversion failed
*err_msg=QObject::tr("Internal error 1");
ret=false;
break;
}
}
else {
// f3: Split on '_' failed
*err_msg=QObject::tr("Internal error 2");
ret=false;
break;
}
}
else {
// f2: Split on '.' failed
*err_msg=QObject::tr("Internal error 3");
ret=false;
break;
}
}
}
delete xslt;
}
return ret;
}
unsigned RDFeed::create(const QString &keyname,bool enable_users, unsigned RDFeed::create(const QString &keyname,bool enable_users,
QString *err_msg) QString *err_msg)
{ {

View File

@ -136,7 +136,6 @@ class RDFeed : public QObject
bool postPodcast(unsigned cast_id,QString *err_msg); bool postPodcast(unsigned cast_id,QString *err_msg);
QString audioUrl(unsigned cast_id); QString audioUrl(unsigned cast_id);
QString imageUrl(int img_id) const; QString imageUrl(int img_id) const;
bool downloadXml(QByteArray *xml,QString *err_msg); // WebAPI Call
bool postXml(QString *err_msg); // WebAPI Call bool postXml(QString *err_msg); // WebAPI Call
bool postXmlConditional(const QString &caption,QWidget *widget); bool postXmlConditional(const QString &caption,QWidget *widget);
bool removeRss(); // WebAPI Call bool removeRss(); // WebAPI Call
@ -148,31 +147,19 @@ class RDFeed : public QObject
unsigned postLog(const QString &logname,const QTime &start_time, unsigned postLog(const QString &logname,const QTime &start_time,
bool stop_at_stop,int start_line,int end_line, bool stop_at_stop,int start_line,int end_line,
QString *err_msg); QString *err_msg);
QString rssXml(QString *err_msg,const QDateTime &now,bool *ok=NULL); QString rssXml(QString *err_msg,const QDateTime &now,bool *ok,
QList<unsigned> *active_cast_ids=NULL);
bool rssFrontXml(QByteArray *xml,QString *err_msg) const; // WebAPI Call
bool rssBackXml(QByteArray *xml,QString *err_msg) const;// Public HTTP(S) Call
void activeCasts(QList<unsigned> *cast_ids);
bool frontActiveCasts(QList<unsigned> *cast_ids,QString *err_msg);
bool backActiveCasts(QList<unsigned> *cast_ids,QString *err_msg);
static unsigned create(const QString &keyname,bool enable_users, static unsigned create(const QString &keyname,bool enable_users,
QString *err_msg); QString *err_msg);
static QString imageFilename(int feed_id,int img_id,const QString &ext); static QString imageFilename(int feed_id,int img_id,const QString &ext);
static QString publicUrl(const QString &base_url,const QString &keyname); static QString publicUrl(const QString &base_url,const QString &keyname);
static QString itunesCategoryXml(const QString &category, static QString itunesCategoryXml(const QString &category,
const QString &sub_category,int padding=0); const QString &sub_category,int padding=0);
/*
static bool generateReport(const QString &feed_url,
const QString &stylesheet_pathname,
const QString &report_filename,
RDTempDirectory *tempdir,QString *err_msg);
*/
/*
static bool generateReport(const QByteArray &src_xml,
const QString &stylesheet_pathname,
const QString &report_filename,
RDTempDirectory *tempdir,QString *err_msg);
*/
/*
static bool generateReport(QString *output,
const QString &src_xml,
const QString &stylesheet_pathname,
QString *err_msg);
*/
signals: signals:
void postProgressChanged(int step); void postProgressChanged(int step);

View File

@ -1,131 +0,0 @@
// rdfeedlistview.cpp
//
// RDTableView widget for RSS feeds
//
// (C) Copyright 2021 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <QDragEnterEvent>
#include <QHeaderView>
#include <QMessageBox>
#include "rdfeed.h"
#include "rdfeedlistmodel.h"
#include "rdfeedlistview.h"
#include "rdtextfile.h"
RDFeedListView::RDFeedListView(QWidget *parent)
:RDTableView(parent)
{
d_mouse_row=-1;
//
// Mouse menu
//
d_mouse_menu=new QMenu(this);
d_front_report_action=d_mouse_menu->
addAction(tr("Generate Front Report"),this,SLOT(generateFrontReportData()));
d_front_report_action->setCheckable(false);
d_back_report_action=d_mouse_menu->
addAction(tr("Generate Back Report"),this,SLOT(generateBackReportData()));
d_back_report_action->setCheckable(false);
connect(d_mouse_menu,SIGNAL(aboutToShow()),
this,SLOT(aboutToShowMenuData()));
//
// XSLT Engine (for feed reports)
//
d_xslt_engine=
new RDXsltEngine("/usr/share/rivendell/rdcastmanager-report.xsl",this);
}
RDFeedListView::~RDFeedListView()
{
delete d_xslt_engine;
}
void RDFeedListView::aboutToShowMenuData()
{
RDFeedListModel *mod=(RDFeedListModel *)model();
if((d_mouse_row<0)||(d_mouse_row>=mod->rowCount())) {
d_front_report_action->setEnabled(false);
d_back_report_action->setEnabled(false);
}
else {
d_front_report_action->setEnabled(true);
d_back_report_action->setEnabled(true);
}
}
void RDFeedListView::generateFrontReportData()
{
QString err_msg;
RDFeedListModel *m=(RDFeedListModel *)model();
QString keyname=m->data(m->index(d_mouse_row,0)).toString();
RDFeed *feed=new RDFeed(keyname,rda->config(),this);
QByteArray xml;
if(feed->downloadXml(&xml,&err_msg)) {
QString output_filename="report.html";
if(d_xslt_engine->transformXml(&output_filename,xml,&err_msg)) {
RDWebBrowser("file://"+output_filename);
}
else {
QMessageBox::warning(this,"RDAdmin - "+tr("Error"),err_msg);
}
}
else {
QMessageBox::warning(this,"RDAdmin - "+tr("Error"),err_msg);
}
}
void RDFeedListView::generateBackReportData()
{
QString err_msg;
RDFeedListModel *m=(RDFeedListModel *)model();
QString url=m->data(m->index(d_mouse_row,6)).toString();
QString output_filename="report.html";
if(d_xslt_engine->transformUrl(&output_filename,url,&err_msg)) {
RDWebBrowser("file://"+output_filename);
}
else {
QMessageBox::warning(this,"RDAdmin - "+tr("Error"),err_msg);
return;
}
}
void RDFeedListView::mousePressEvent(QMouseEvent *e)
{
if(e->button()==Qt::RightButton) {
d_mouse_row=indexAt(e->pos()).row();
if((d_mouse_row>=0)&&(d_mouse_row<model()->rowCount())) {
d_mouse_menu->popup(e->globalPos());
}
else {
d_mouse_row=-1;
}
}
QTableView::mousePressEvent(e);
}

View File

@ -2,7 +2,7 @@
// //
// RSS schema definitions for Rivendell // RSS schema definitions for Rivendell
// //
// (C) Copyright 2020-2022 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2020-2023 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -57,13 +57,13 @@ RDRssSchemas::RDRssSchemas()
c_header_templates.push_back(""); c_header_templates.push_back("");
// Rss202Schema // Rss202Schema
c_header_templates.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\">"); c_header_templates.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:rivendell=\"http://www.rivendellaudio.org/dtds/rivendell-0.1.dtd\">");
// AppleSchema // AppleSchema
c_header_templates.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:superfeed=\"http://www.rivendellaudio.org/dtds/superfeed-0.1.dtd\" xmlns:direct=\"http://www.rivendellaudio.org/dtds/direct-0.1.dtd\">"); c_header_templates.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:superfeed=\"http://www.rivendellaudio.org/dtds/superfeed-0.1.dtd\" xmlns:direct=\"http://www.rivendellaudio.org/dtds/direct-0.1.dtd\" xmlns:rivendell=\"http://www.rivendellaudio.org/dtds/rivendell-0.1.dtd\">");
// AppleSuperfeedSchema // AppleSuperfeedSchema
c_header_templates.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:superfeed=\"http://www.rivendellaudio.org/dtds/superfeed-0.1.dtd\" xmlns:direct=\"http://www.rivendellaudio.org/dtds/direct-0.1.dtd\">"); c_header_templates.push_back("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<rss version=\"2.0\" xmlns:itunes=\"http://www.itunes.com/dtds/podcast-1.0.dtd\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\" xmlns:atom=\"http://www.w3.org/2005/Atom\" xmlns:superfeed=\"http://www.rivendellaudio.org/dtds/superfeed-0.1.dtd\" xmlns:direct=\"http://www.rivendellaudio.org/dtds/direct-0.1.dtd\" xmlns:rivendell=\"http://www.rivendellaudio.org/dtds/rivendell-0.1.dtd\">");
// //
// Channel Templates // Channel Templates

View File

@ -2,7 +2,7 @@
## ##
## Automake.am for rivendell/rdadmin ## Automake.am for rivendell/rdadmin
## ##
## (C) Copyright 2002-2021 Fred Gleason <fredg@paravelsystems.com> ## (C) Copyright 2002-2023 Fred Gleason <fredg@paravelsystems.com>
## ##
## This program is free software; you can redistribute it and/or modify ## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License version 2 as ## it under the terms of the GNU General Public License version 2 as
@ -93,6 +93,7 @@ dist_rdadmin_SOURCES = add_feed.cpp add_feed.h\
edit_user_perms.cpp edit_user_perms.h\ edit_user_perms.cpp edit_user_perms.h\
edit_user_service_perms.cpp edit_user_service_perms.h\ edit_user_service_perms.cpp edit_user_service_perms.h\
edit_vguest_resource.cpp edit_vguest_resource.h\ edit_vguest_resource.cpp edit_vguest_resource.h\
feedlistview.cpp feedlistview.h\
globals.h\ globals.h\
help_audios.cpp help_audios.h\ help_audios.cpp help_audios.h\
importfields.cpp importfields.h\ importfields.cpp importfields.h\
@ -176,6 +177,7 @@ nodist_rdadmin_SOURCES = global_credits.cpp\
moc_edit_user_perms.cpp\ moc_edit_user_perms.cpp\
moc_edit_user_service_perms.cpp\ moc_edit_user_service_perms.cpp\
moc_edit_vguest_resource.cpp\ moc_edit_vguest_resource.cpp\
moc_feedlistview.cpp\
moc_help_audios.cpp\ moc_help_audios.cpp\
moc_importfields.cpp\ moc_importfields.cpp\
moc_info_dialog.cpp\ moc_info_dialog.cpp\

148
rdadmin/feedlistview.cpp Normal file
View File

@ -0,0 +1,148 @@
// feedlistview.cpp
//
// RDTableView widget for RSS feeds
//
// (C) Copyright 2021-2023 Fred Gleason <fredg@paravelsystems.com>
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as
// published by the Free Software Foundation.
//
// 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., 675 Mass Ave, Cambridge, MA 02139, USA.
//
#include <QDragEnterEvent>
#include <QHeaderView>
#include <QMessageBox>
#include "rdfeedlistmodel.h"
#include "rdreport.h"
#include "feedlistview.h"
#include "rdtextfile.h"
FeedListView::FeedListView(QWidget *parent)
:RDTableView(parent)
{
d_mouse_row=-1;
//
// Mouse menu
//
d_mouse_menu=new QMenu(this);
d_front_item_report_action=d_mouse_menu->
addAction(tr("Generate Item Report [Front]"),this,SLOT(generateFrontItemReportData()));
d_front_item_report_action->setCheckable(false);
d_back_item_report_action=d_mouse_menu->
addAction(tr("Generate Item Report [Back]"),this,SLOT(generateBackItemReportData()));
d_back_item_report_action->setCheckable(false);
connect(d_mouse_menu,SIGNAL(aboutToShow()),
this,SLOT(aboutToShowMenuData()));
}
FeedListView::~FeedListView()
{
for(int i=0;i<d_xslt_engines.size();i++) {
delete d_xslt_engines.at(i);
}
}
void FeedListView::aboutToShowMenuData()
{
RDFeedListModel *mod=(RDFeedListModel *)model();
if((d_mouse_row<0)||(d_mouse_row>=mod->rowCount())) {
d_front_item_report_action->setEnabled(false);
d_back_item_report_action->setEnabled(false);
}
else {
d_front_item_report_action->setEnabled(true);
d_back_item_report_action->setEnabled(true);
}
}
void FeedListView::generateFrontItemReportData()
{
QDateTime now=QDateTime::currentDateTime();
bool ok=false;
QList<unsigned> front_ids;
QString err_msg;
QString output_filename="report.html";
RDFeedListModel *m=(RDFeedListModel *)model();
QString keyname=m->data(m->index(d_mouse_row,0)).toString();
RDFeed *feed=new RDFeed(keyname,rda->config(),this);
if(feed->frontActiveCasts(&front_ids,&err_msg)) {
QString xml=feed->rssXml(&err_msg,now,&ok,&front_ids);
d_xslt_engines.
push_back(new RDXsltEngine("/usr/share/rivendell/rss-front-item-report.xsl",this));
if(d_xslt_engines.back()->transformXml(&output_filename,xml,&err_msg)) {
RDWebBrowser("file://"+output_filename);
}
else {
QMessageBox::warning(this,"RDAdmin - "+tr("Error"),err_msg);
}
}
else {
QMessageBox::warning(this,"RDAdmin - "+tr("Error"),
tr("Error accessing from XML data.")+"\n"+
"["+err_msg+"]");
}
}
void FeedListView::generateBackItemReportData()
{
QDateTime now=QDateTime::currentDateTime();
bool ok=false;
QList<unsigned> back_ids;
QString err_msg;
QString output_filename="report.html";
RDFeedListModel *m=(RDFeedListModel *)model();
QString keyname=m->data(m->index(d_mouse_row,0)).toString();
RDFeed *feed=new RDFeed(keyname,rda->config(),this);
if(feed->backActiveCasts(&back_ids,&err_msg)) {
QString xml=feed->rssXml(&err_msg,now,&ok,&back_ids);
d_xslt_engines.
push_back(new RDXsltEngine("/usr/share/rivendell/rss-back-item-report.xsl",this));
if(d_xslt_engines.back()->transformXml(&output_filename,xml,&err_msg)) {
RDWebBrowser("file://"+output_filename);
}
else {
QMessageBox::warning(this,"RDAdmin - "+tr("Error"),err_msg);
}
}
else {
QMessageBox::warning(this,"RDAdmin - "+tr("Error"),
tr("Error accessing from XML data.")+"\n"+
"["+err_msg+"]");
}
}
void FeedListView::mousePressEvent(QMouseEvent *e)
{
if(e->button()==Qt::RightButton) {
d_mouse_row=indexAt(e->pos()).row();
if((d_mouse_row>=0)&&(d_mouse_row<model()->rowCount())) {
d_mouse_menu->popup(e->globalPos());
}
else {
d_mouse_row=-1;
}
}
QTableView::mousePressEvent(e);
}

View File

@ -1,4 +1,4 @@
// rdfeedlistview.h // feedlistview.h
// //
// RDTableView widget for RSS feeds // RDTableView widget for RSS feeds
// //
@ -18,28 +18,29 @@
// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
// //
#ifndef RDFEEDLISTVIEW_H #ifndef FEEDLISTVIEW_H
#define RDFEEDLISTVIEW_H #define FEEDLISTVIEW_H
#include <QAction> #include <QAction>
#include <QList> #include <QList>
#include <QMenu> #include <QMenu>
#include <rdfeed.h>
#include <rdtableview.h> #include <rdtableview.h>
#include <rdtempdirectory.h> #include <rdtempdirectory.h>
#include "rdxsltengine.h" #include <rdxsltengine.h>
class RDFeedListView : public RDTableView class FeedListView : public RDTableView
{ {
Q_OBJECT Q_OBJECT
public: public:
RDFeedListView(QWidget *parent=0); FeedListView(QWidget *parent=0);
~RDFeedListView(); ~FeedListView();
private slots: private slots:
void aboutToShowMenuData(); void aboutToShowMenuData();
void generateFrontReportData(); void generateFrontItemReportData();
void generateBackReportData(); void generateBackItemReportData();
protected: protected:
void mousePressEvent(QMouseEvent *e); void mousePressEvent(QMouseEvent *e);
@ -47,10 +48,10 @@ class RDFeedListView : public RDTableView
private: private:
int d_mouse_row; int d_mouse_row;
QMenu *d_mouse_menu; QMenu *d_mouse_menu;
QAction *d_front_report_action; QAction *d_front_item_report_action;
QAction *d_back_report_action; QAction *d_back_item_report_action;
RDXsltEngine *d_xslt_engine; QList<RDXsltEngine *> d_xslt_engines;
}; };
#endif // RDFEEDLISTVIEW_H #endif // FEEDLISTVIEW_H

View File

@ -2,7 +2,7 @@
// //
// List Rivendell Feeds // List Rivendell Feeds
// //
// (C) Copyright 2002-2022 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2002-2023 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -98,7 +98,7 @@ ListFeeds::ListFeeds(QWidget *parent)
// //
// Feed List // Feed List
// //
list_feeds_view=new RDFeedListView(this); list_feeds_view=new FeedListView(this);
list_feeds_model=new RDFeedListModel(true,false,this); list_feeds_model=new RDFeedListModel(true,false,this);
list_feeds_model->setFont(font()); list_feeds_model->setFont(font());
list_feeds_model->setPalette(palette()); list_feeds_model->setPalette(palette());

View File

@ -2,7 +2,7 @@
// //
// List Rivendell RSS Feeds // List Rivendell RSS Feeds
// //
// (C) Copyright 2002-2021 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2002-2023 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -25,9 +25,10 @@
#include <rddialog.h> #include <rddialog.h>
#include <rdfeedlistmodel.h> #include <rdfeedlistmodel.h>
#include <rdfeedlistview.h>
#include <rdtableview.h> #include <rdtableview.h>
#include <feedlistview.h>
class ListFeeds : public RDDialog class ListFeeds : public RDDialog
{ {
Q_OBJECT Q_OBJECT
@ -52,7 +53,7 @@ class ListFeeds : public RDDialog
private: private:
QLabel *list_box_label; QLabel *list_box_label;
RDFeedListView *list_feeds_view; FeedListView *list_feeds_view;
RDFeedListModel *list_feeds_model; RDFeedListModel *list_feeds_model;
QPushButton *list_add_button; QPushButton *list_add_button;
QPushButton *list_edit_button; QPushButton *list_edit_button;

View File

@ -2,7 +2,9 @@
# #
# The QMake project file for RDAdmin. # The QMake project file for RDAdmin.
# #
# (C) Copyright 2003-2021 Fred Gleason <fredg@paravelsystems.com> # (C) Copyright 2003-2023 Fred Gleason <fredg@paravelsystems.com>
#
# NB - This data is used only by Qt's i18n tools!
# #
# This program is free software; you can redistribute it and/or modify # This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 2 as # it under the terms of the GNU General Public License version 2 as
@ -59,6 +61,7 @@ x11 {
SOURCES += edit_user.cpp SOURCES += edit_user.cpp
SOURCES += edit_user_perms.cpp SOURCES += edit_user_perms.cpp
SOURCES += edit_vguest_resource.cpp SOURCES += edit_vguest_resource.cpp
SOURCES += feedlistview.cpp
SOURCES += info_dialog.cpp SOURCES += info_dialog.cpp
SOURCES += license.cpp SOURCES += license.cpp
SOURCES += list_dropboxes.cpp SOURCES += list_dropboxes.cpp
@ -129,6 +132,7 @@ x11 {
HEADERS += edit_user.h HEADERS += edit_user.h
HEADERS += edit_user_perms.h HEADERS += edit_user_perms.h
HEADERS += edit_vguest_resource.h HEADERS += edit_vguest_resource.h
HEADERS += feedlistview.h
HEADERS += info_dialog.h HEADERS += info_dialog.h
HEADERS += license.h HEADERS += license.h
HEADERS += list_dropboxes.h HEADERS += list_dropboxes.h

View File

@ -93,7 +93,7 @@ MainWidget::MainWidget(RDConfig *c,QWidget *parent)
// XSLT Engine (for feed reports) // XSLT Engine (for feed reports)
// //
cast_xslt_engine= cast_xslt_engine=
new RDXsltEngine("/usr/share/rivendell/rdcastmanager-report.xsl",this); new RDXsltEngine("/usr/share/rivendell/rss-back-item-report.xsl",this);
// //
// Feed List // Feed List

View File

@ -2,7 +2,7 @@
// //
// Rivendell web service portal -- Podcast services // Rivendell web service portal -- Podcast services
// //
// (C) Copyright 2010-2022 Fred Gleason <fredg@paravelsystems.com> // (C) Copyright 2010-2023 Fred Gleason <fredg@paravelsystems.com>
// //
// This program is free software; you can redistribute it and/or modify // This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License version 2 as // it under the terms of the GNU General Public License version 2 as
@ -369,11 +369,12 @@ bool Xport::PostRssElemental(RDFeed *feed,const QDateTime &now,QString *err_msg)
CURLcode curl_err; CURLcode curl_err;
char errstr[CURL_ERROR_SIZE]; char errstr[CURL_ERROR_SIZE];
bool ret=false; bool ret=false;
bool ok=false;
if((curl=curl_easy_init())==NULL) { if((curl=curl_easy_init())==NULL) {
XmlExit("unable to get CURL handle",500,"podcasts.cpp",LINE_NUMBER); XmlExit("unable to get CURL handle",500,"podcasts.cpp",LINE_NUMBER);
} }
xport_curl_data=feed->rssXml(err_msg,now).toUtf8(); xport_curl_data=feed->rssXml(err_msg,now,&ok).toUtf8();
xport_curl_data_ptr=0; xport_curl_data_ptr=0;
// //

View File

@ -2,7 +2,7 @@
## ##
## Makefile.am for rivendell/web/stylesheets ## Makefile.am for rivendell/web/stylesheets
## ##
## (C) Copyright 2022 Fred Gleason <fredg@paravelsystems.com> ## (C) Copyright 2022-2023 Fred Gleason <fredg@paravelsystems.com>
## ##
## This program is free software; you can redistribute it and/or modify ## This program is free software; you can redistribute it and/or modify
## it under the terms of the GNU General Public License version 2 as ## it under the terms of the GNU General Public License version 2 as
@ -21,12 +21,18 @@
install-exec-am: install-exec-am:
mkdir -p $(DESTDIR)/usr/share/rivendell mkdir -p $(DESTDIR)/usr/share/rivendell
cp rdcastmanager-report.xsl $(DESTDIR)/usr/share/rivendell/ cp rss-item-enclosures.xsl $(DESTDIR)/usr/share/rivendell/
cp rss-front-item-report.xsl $(DESTDIR)/usr/share/rivendell/
cp rss-back-item-report.xsl $(DESTDIR)/usr/share/rivendell/
uninstall-local: uninstall-local:
rm -f $(DESTDIR)/usr/share/rivendell/rdcastmanager-report.xsl rm -f $(DESTDIR)/usr/share/rivendell/rss-item-enclosures.xsl
rm -f $(DESTDIR)/usr/share/rivendell/rss-front-item-report.xsl
rm -f $(DESTDIR)/usr/share/rivendell/rss-back-item-report.xsl
EXTRA_DIST = rdcastmanager-report.xsl EXTRA_DIST = rss-front-item-report.xsl\
rss-back-item-report.xsl\
rss-item-enclosures.xsl
CLEANFILES = *~ CLEANFILES = *~
MAINTAINERCLEANFILES = *~\ MAINTAINERCLEANFILES = *~\

View File

@ -1,7 +1,7 @@
<!-- rdcastmanager-report.xsl <!-- rdadmin-back-item-report.xsl
Stylesheet for generating the Online Feed Report in rdcastmanager(1). Stylesheet for generating the Back Item Report in rdadmin(1)
Copyright (C) 2002-2022 Fred Gleason <fredg@paravelsystems.com> Copyright (C) 2002-2023 Fred Gleason <fredg@paravelsystems.com>
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as it under the terms of version 2 of the GNU General Public License as
@ -18,12 +18,14 @@
Boston, MA 02111-1307 USA Boston, MA 02111-1307 USA
--> -->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd"> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:rivendell="http://www.rivendellaudio.org/dtds/rivendell-0.1.dtd">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/> <xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/"> <xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml"> <html xmlns="http://www.w3.org/1999/xhtml">
<head> <head>
<title><xsl:value-of select="/rss/channel/title"/> RSS Feed</title> <title>
<xsl:value-of select="/rss/channel/title"/> Rivendell Back Item Report
</title>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="IE=edge,chrome=1" /> <meta http-equiv="x-ua-compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no" /> <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no" />
@ -31,7 +33,7 @@
body { body {
background-color: darkgray; background-color: darkgray;
} }
.rounded-block { .active-rounded-block {
background-color: white; background-color: white;
width: 800px; width: 800px;
border-style: solid; border-style: solid;
@ -39,6 +41,14 @@
border-radius: 10px; border-radius: 10px;
margin-bottom: 5px; margin-bottom: 5px;
} }
.missing-rounded-block {
background-color: red;
width: 800px;
border-style: solid;
border-width: 2px;
border-radius: 10px;
margin-bottom: 5px;
}
.image { .image {
vertical-align: text-top; vertical-align: text-top;
margin-left: 5px; margin-left: 5px;
@ -70,17 +80,17 @@
</head> </head>
<body> <body>
<header> <header>
<table class="rounded-block"> <table class="active-rounded-block">
<tr> <tr>
<td width="1024" colspan="2"> <td width="1024" colspan="2">
<h1 class="center-aligned">Rivendell Podcast Report</h1> <h1 class="center-aligned">Rivendell Back Item Report</h1>
</td> </td>
</tr> </tr>
</table> </table>
</header> </header>
<main> <main>
<!-- Channel Info --> <!-- Channel Info -->
<table class="rounded-block"> <table class="active-rounded-block">
<tr> <tr>
<td class="image" width="96"> <td class="image" width="96">
<img class="image" width="96" height="96"> <img class="image" width="96" height="96">
@ -117,7 +127,10 @@
<!-- Item Info --> <!-- Item Info -->
<xsl:for-each select="/rss/channel/item"> <xsl:for-each select="/rss/channel/item">
<table class="rounded-block"> <table>
<xsl:attribute name="class">
<xsl:value-of select="@rivendell:style"/>
</xsl:attribute>
<tr> <tr>
<td><h3> <td><h3>
<a class="left-aligned" target="_blank"> <a class="left-aligned" target="_blank">

View File

@ -0,0 +1,163 @@
<!-- rdadmin-front-item-report.xsl
Stylesheet for generating the Front Item Report in rdadmin(1)
Copyright (C) 2002-2023 Fred Gleason <fredg@paravelsystems.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation;
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., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd" xmlns:rivendell="http://www.rivendellaudio.org/dtds/rivendell-0.1.dtd">
<xsl:output method="html" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>
<xsl:value-of select="/rss/channel/title"/> Rivendell Front Item Report
</title>
<meta charset="UTF-8" />
<meta http-equiv="x-ua-compatible" content="IE=edge,chrome=1" />
<meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1,shrink-to-fit=no" />
<style type="text/css">
body {
background-color: darkgray;
}
.active-rounded-block {
background-color: white;
width: 800px;
border-style: solid;
border-width: 2px;
border-radius: 10px;
margin-bottom: 5px;
}
.missing-rounded-block {
background-color: red;
width: 800px;
border-style: solid;
border-width: 2px;
border-radius: 10px;
margin-bottom: 5px;
}
.image {
vertical-align: text-top;
margin-left: 5px;
margin-right: 5px;
}
.center-aligned {
font-family: Verdana,san serif;
text-align: center;
margin-top: 5px;
margin-bottom: 5px;
margin-left: 5px;
margin-right: 5px;
}
.left-aligned {
font-family: Helvetica,serif;
text-align: left;
margin-top: 5px;
margin-left: 5px;
margin-right: 5px;
}
.datetime {
font-family: Helvetica,serif;
text-align: right;
margin-top: 5px;
margin-left: 5px;
margin-right: 5px;
}
</style>
</head>
<body>
<header>
<table class="active-rounded-block">
<tr>
<td width="1024" colspan="2">
<h1 class="center-aligned">Rivendell Front Item Report</h1>
</td>
</tr>
</table>
</header>
<main>
<!-- Channel Info -->
<table class="active-rounded-block">
<tr>
<td class="image" width="96">
<img class="image" width="96" height="96">
<xsl:attribute name="src">
<xsl:value-of select="/rss/channel/image/url" />
</xsl:attribute>
</img>
</td>
<td>
<table>
<tr>
<td class="left-aligned">
<h2>
<a target="_blank">
<xsl:attribute name="href">
<xsl:value-of select="/rss/channel/link"/>
</xsl:attribute>
<xsl:attribute name="hreflang">
<xsl:value-of select="/rss/channel/language"/>
</xsl:attribute>
<xsl:value-of select="/rss/channel/title"/>
</a>
</h2>
</td>
</tr>
<tr>
<td class="left-aligned">
<xsl:value-of select="/rss/channel/description"/></td>
</tr>
</table>
</td>
</tr>
</table>
<!-- Item Info -->
<xsl:for-each select="/rss/channel/item">
<table>
<xsl:attribute name="class">
<xsl:value-of select="@rivendell:style"/>
</xsl:attribute>
<tr>
<td><h3>
<a class="left-aligned" target="_blank">
<xsl:attribute name="href">
<xsl:value-of select="enclosure/@url"/>
</xsl:attribute>
<xsl:attribute name="hreflang">
<xsl:value-of select="/rss/channel/language"/>
</xsl:attribute>
<xsl:value-of select="title"/>
</a>
</h3></td>
<td class="datetime"><h4>
<time class="datetime">
<xsl:value-of select="pubDate" />
</time>
</h4></td>
</tr>
<tr>
<td class="left-aligned" colspan="2">
<xsl:value-of select="description"/>
</td>
</tr>
</table>
</xsl:for-each>
</main>
</body>
</html>
</xsl:template>
</xsl:stylesheet>

View File

@ -0,0 +1,29 @@
<!-- rdcastmanager-item-enclosures.xsl
Stylesheet for generating a list of RSS feed item enclosures.
Copyright (C) 2002-2023 Fred Gleason <fredg@paravelsystems.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
published by the Free Software Foundation;
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., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
-->
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:itunes="http://www.itunes.com/dtds/podcast-1.0.dtd">
<xsl:output method="text" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:template match="/">
<xsl:for-each select="/rss/channel/item">
<xsl:value-of select="enclosure/@url"/>
<xsl:text>|</xsl:text>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>