mirror of
https://github.com/ElvishArtisan/rivendell.git
synced 2025-08-16 08:34:12 +02:00
2020-09-21 Fred Gleason <fredg@paravelsystems.com>
* Added a 'PODCASTS.SHA1_HASH' field to the database. * Incremented the database version to 335. * Added 'RDPodcast::sha1Hash()' and 'RDPodcast::setSha1Hash()' methods. * Implemented audio relinking for podcast media files. Signed-off-by: Fred Gleason <fredg@paravelsystems.com>
This commit is contained in:
parent
6516c20ff6
commit
6d3a60d174
@ -20285,3 +20285,9 @@
|
|||||||
* Added a 'SavePodcast' method to the Web API.
|
* Added a 'SavePodcast' method to the Web API.
|
||||||
* Added a 'GetPodcast' method to the Web API.
|
* Added a 'GetPodcast' method to the Web API.
|
||||||
* Added a 'DeletePodcast' method to the Web API.
|
* Added a 'DeletePodcast' method to the Web API.
|
||||||
|
2020-09-21 Fred Gleason <fredg@paravelsystems.com>
|
||||||
|
* Added a 'PODCASTS.SHA1_HASH' field to the database.
|
||||||
|
* Incremented the database version to 335.
|
||||||
|
* Added 'RDPodcast::sha1Hash()' and 'RDPodcast::setSha1Hash()'
|
||||||
|
methods.
|
||||||
|
* Implemented audio relinking for podcast media files.
|
||||||
|
@ -20,6 +20,7 @@ ITEM_IMAGE_ID int(11) From FEED_IMAGES.ID
|
|||||||
AUDIO_FILENAME varchar(191)
|
AUDIO_FILENAME varchar(191)
|
||||||
AUDIO_LENGTH int(10) unsigned
|
AUDIO_LENGTH int(10) unsigned
|
||||||
AUDIO_TIME int(10) unsigned
|
AUDIO_TIME int(10) unsigned
|
||||||
|
SHA1_HASH varchar(40)
|
||||||
ORIGIN_LOGIN_NAME varchar(191) From USERS.LOGIN_NAME
|
ORIGIN_LOGIN_NAME varchar(191) From USERS.LOGIN_NAME
|
||||||
ORIGIN_STATION varchar(64) From STATIONS.NAME
|
ORIGIN_STATION varchar(64) From STATIONS.NAME
|
||||||
ORIGIN_DATETIME datetime
|
ORIGIN_DATETIME datetime
|
||||||
|
@ -24,7 +24,7 @@
|
|||||||
/*
|
/*
|
||||||
* Current Database Version
|
* Current Database Version
|
||||||
*/
|
*/
|
||||||
#define RD_VERSION_DATABASE 334
|
#define RD_VERSION_DATABASE 335
|
||||||
|
|
||||||
|
|
||||||
#endif // DBVERSION_H
|
#endif // DBVERSION_H
|
||||||
|
@ -46,6 +46,7 @@
|
|||||||
#include "rdtempdirectory.h"
|
#include "rdtempdirectory.h"
|
||||||
#include "rdupload.h"
|
#include "rdupload.h"
|
||||||
#include "rdwavefile.h"
|
#include "rdwavefile.h"
|
||||||
|
#include "rdxport_interface.h"
|
||||||
|
|
||||||
size_t __RDFeed_Readfunction_Callback(char *buffer,size_t size,size_t nitems,
|
size_t __RDFeed_Readfunction_Callback(char *buffer,size_t size,size_t nitems,
|
||||||
void *userdata)
|
void *userdata)
|
||||||
@ -1093,6 +1094,11 @@ unsigned RDFeed::postCut(const QString &cutname,Error *err)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
emit postProgressChanged(3);
|
emit postProgressChanged(3);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save to Audio Store
|
||||||
|
//
|
||||||
|
SavePodcast(cast_id,tmpfile);
|
||||||
unlink(tmpfile);
|
unlink(tmpfile);
|
||||||
delete upload;
|
delete upload;
|
||||||
|
|
||||||
@ -1225,6 +1231,10 @@ unsigned RDFeed::postFile(const QString &srcfile,Error *err)
|
|||||||
}
|
}
|
||||||
delete upload;
|
delete upload;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save to Audio Store
|
||||||
|
//
|
||||||
|
SavePodcast(cast_id,tmpfile);
|
||||||
unlink(QString(tmpfile)+".wav");
|
unlink(QString(tmpfile)+".wav");
|
||||||
unlink(tmpfile);
|
unlink(tmpfile);
|
||||||
|
|
||||||
@ -1349,6 +1359,10 @@ unsigned RDFeed::postLog(const QString &logname,const QTime &start_time,
|
|||||||
|
|
||||||
emit postProgressChanged(2+log_event->size());
|
emit postProgressChanged(2+log_event->size());
|
||||||
|
|
||||||
|
//
|
||||||
|
// Save to Audio Store
|
||||||
|
//
|
||||||
|
SavePodcast(cast_id,tmpfile);
|
||||||
unlink(tmpfile);
|
unlink(tmpfile);
|
||||||
|
|
||||||
//
|
//
|
||||||
@ -1673,6 +1687,80 @@ void RDFeed::renderLineStartedData(int lineno,int total_lines)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RDFeed::SavePodcast(unsigned cast_id,const QString &src_filename) const
|
||||||
|
{
|
||||||
|
long response_code;
|
||||||
|
CURL *curl=NULL;
|
||||||
|
CURLcode curl_err;
|
||||||
|
struct curl_httppost *first=NULL;
|
||||||
|
struct curl_httppost *last=NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generate POST Data
|
||||||
|
//
|
||||||
|
// We have to use multipart here because we have a file to send.
|
||||||
|
//
|
||||||
|
curl_formadd(&first,&last,CURLFORM_PTRNAME,"COMMAND",
|
||||||
|
CURLFORM_COPYCONTENTS,
|
||||||
|
(const char *)QString().sprintf("%u",RDXPORT_COMMAND_SAVE_PODCAST),
|
||||||
|
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,
|
||||||
|
(const char *)QString().sprintf("%u",cast_id),
|
||||||
|
CURLFORM_END);
|
||||||
|
curl_formadd(&first,&last,CURLFORM_PTRNAME,"FILENAME",
|
||||||
|
CURLFORM_FILE,src_filename.toUtf8().constData(),
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set up the transfer
|
||||||
|
//
|
||||||
|
if((curl=curl_easy_init())==NULL) {
|
||||||
|
curl_formfree(first);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
curl_easy_setopt(curl,CURLOPT_WRITEDATA,stdout);
|
||||||
|
curl_easy_setopt(curl,CURLOPT_HTTPPOST,first);
|
||||||
|
curl_easy_setopt(curl,CURLOPT_USERAGENT,
|
||||||
|
(const char *)rda->config()->userAgent());
|
||||||
|
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());
|
||||||
|
|
||||||
|
//
|
||||||
|
// Send it
|
||||||
|
//
|
||||||
|
if((curl_err=curl_easy_perform(curl))!=CURLE_OK) {
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
curl_formfree(first);
|
||||||
|
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)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned RDFeed::CreateCast(QString *filename,int bytes,int msecs) const
|
unsigned RDFeed::CreateCast(QString *filename,int bytes,int msecs) const
|
||||||
{
|
{
|
||||||
QString sql;
|
QString sql;
|
||||||
|
@ -160,6 +160,7 @@ class RDFeed : public QObject
|
|||||||
void renderLineStartedData(int lineno,int total_lines);
|
void renderLineStartedData(int lineno,int total_lines);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool SavePodcast(unsigned cast_id,const QString &src_filename) const;
|
||||||
unsigned CreateCast(QString *filename,int bytes,int msecs) const;
|
unsigned CreateCast(QString *filename,int bytes,int msecs) const;
|
||||||
QString ResolveChannelWildcards(const QString &tmplt,RDSqlQuery *chan_q,
|
QString ResolveChannelWildcards(const QString &tmplt,RDSqlQuery *chan_q,
|
||||||
const QDateTime &build_datetime);
|
const QDateTime &build_datetime);
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
#include "rdescape_string.h"
|
#include "rdescape_string.h"
|
||||||
#include "rdpodcast.h"
|
#include "rdpodcast.h"
|
||||||
#include "rdurl.h"
|
#include "rdurl.h"
|
||||||
|
#include "rdxport_interface.h"
|
||||||
|
|
||||||
//
|
//
|
||||||
// CURL Callbacks
|
// CURL Callbacks
|
||||||
@ -317,6 +318,18 @@ int RDPodcast::audioTime() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
QString RDPodcast::sha1Hash() const
|
||||||
|
{
|
||||||
|
return RDGetSqlValue("PODCASTS","ID",podcast_id,"SHA1_HASH").toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RDPodcast::setSha1Hash(const QString &str) const
|
||||||
|
{
|
||||||
|
SetRow("SHA1_HASH",str);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RDPodcast::setAudioTime(int msecs) const
|
void RDPodcast::setAudioTime(int msecs) const
|
||||||
{
|
{
|
||||||
SetRow("AUDIO_TIME",msecs);
|
SetRow("AUDIO_TIME",msecs);
|
||||||
@ -367,6 +380,11 @@ bool RDPodcast::removeAudio(RDFeed *feed,QString *err_text,bool log_debug) const
|
|||||||
*err_text=RDDelete::errorText(conv_err);
|
*err_text=RDDelete::errorText(conv_err);
|
||||||
delete conv;
|
delete conv;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Delete from Audio Store
|
||||||
|
//
|
||||||
|
DeletePodcast(id());
|
||||||
|
|
||||||
return conv_err==RDDelete::ErrorOk;
|
return conv_err==RDDelete::ErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -385,29 +403,101 @@ QString RDPodcast::guid(const QString &full_url,unsigned feed_id,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool RDPodcast::DeletePodcast(unsigned cast_id) const
|
||||||
|
{
|
||||||
|
long response_code;
|
||||||
|
CURL *curl=NULL;
|
||||||
|
CURLcode curl_err;
|
||||||
|
struct curl_httppost *first=NULL;
|
||||||
|
struct curl_httppost *last=NULL;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Generate POST Data
|
||||||
|
//
|
||||||
|
curl_formadd(&first,&last,CURLFORM_PTRNAME,"COMMAND",
|
||||||
|
CURLFORM_COPYCONTENTS,
|
||||||
|
(const char *)QString().sprintf("%u",RDXPORT_COMMAND_DELETE_PODCAST),
|
||||||
|
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,
|
||||||
|
(const char *)QString().sprintf("%u",cast_id),
|
||||||
|
CURLFORM_END);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set up the transfer
|
||||||
|
//
|
||||||
|
if((curl=curl_easy_init())==NULL) {
|
||||||
|
curl_formfree(first);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
curl_easy_setopt(curl,CURLOPT_WRITEDATA,stdout);
|
||||||
|
curl_easy_setopt(curl,CURLOPT_HTTPPOST,first);
|
||||||
|
curl_easy_setopt(curl,CURLOPT_USERAGENT,
|
||||||
|
(const char *)rda->config()->userAgent());
|
||||||
|
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());
|
||||||
|
|
||||||
|
//
|
||||||
|
// Send it
|
||||||
|
//
|
||||||
|
if((curl_err=curl_easy_perform(curl))!=CURLE_OK) {
|
||||||
|
curl_easy_cleanup(curl);
|
||||||
|
curl_formfree(first);
|
||||||
|
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)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void RDPodcast::SetRow(const QString ¶m,int value) const
|
void RDPodcast::SetRow(const QString ¶m,int value) const
|
||||||
{
|
{
|
||||||
RDSqlQuery *q;
|
|
||||||
QString sql;
|
QString sql;
|
||||||
|
|
||||||
sql=QString("update PODCASTS set ")+
|
sql=QString("update PODCASTS set ")+
|
||||||
param+QString().sprintf("=%d where ",value)+
|
param+QString().sprintf("=%d where ",value)+
|
||||||
QString().sprintf("ID=%u",podcast_id);
|
QString().sprintf("ID=%u",podcast_id);
|
||||||
q=new RDSqlQuery(sql);
|
RDSqlQuery::apply(sql);
|
||||||
delete q;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void RDPodcast::SetRow(const QString ¶m,const QString &value) const
|
void RDPodcast::SetRow(const QString ¶m,const QString &value) const
|
||||||
{
|
{
|
||||||
RDSqlQuery *q;
|
|
||||||
QString sql;
|
QString sql;
|
||||||
|
|
||||||
sql=QString("update PODCASTS set ")+
|
if(value.isNull()) {
|
||||||
param+"=\""+RDEscapeString(value)+"\" where "+
|
sql=QString("update PODCASTS set ")+
|
||||||
QString().sprintf("ID=%u",podcast_id);
|
param+"=NULL where "+
|
||||||
q=new RDSqlQuery(sql);
|
QString().sprintf("ID=%u",podcast_id);
|
||||||
delete q;
|
}
|
||||||
|
else {
|
||||||
|
sql=QString("update PODCASTS set ")+
|
||||||
|
param+"=\""+RDEscapeString(value)+"\" where "+
|
||||||
|
QString().sprintf("ID=%u",podcast_id);
|
||||||
|
}
|
||||||
|
RDSqlQuery::apply(sql);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -68,6 +68,8 @@ class RDPodcast
|
|||||||
void setAudioLength(int len) const;
|
void setAudioLength(int len) const;
|
||||||
int audioTime() const;
|
int audioTime() const;
|
||||||
void setAudioTime(int msecs) const;
|
void setAudioTime(int msecs) const;
|
||||||
|
QString sha1Hash() const;
|
||||||
|
void setSha1Hash(const QString &str=QString()) const;
|
||||||
QDateTime expirationDateTime() const;
|
QDateTime expirationDateTime() const;
|
||||||
void setExpirationDateTime(const QDateTime &dt) const;
|
void setExpirationDateTime(const QDateTime &dt) const;
|
||||||
RDPodcast::Status status() const;
|
RDPodcast::Status status() const;
|
||||||
@ -79,6 +81,7 @@ class RDPodcast
|
|||||||
unsigned feed_id,unsigned cast_id);
|
unsigned feed_id,unsigned cast_id);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool DeletePodcast(unsigned cast_id) const;
|
||||||
void SetRow(const QString ¶m,int value) const;
|
void SetRow(const QString ¶m,int value) const;
|
||||||
void SetRow(const QString ¶m,const QString &value) const;
|
void SetRow(const QString ¶m,const QString &value) const;
|
||||||
void SetRow(const QString ¶m,const QDateTime &datetime,const QString &value) const;
|
void SetRow(const QString ¶m,const QDateTime &datetime,const QString &value) const;
|
||||||
|
@ -389,60 +389,42 @@ void MainObject::RelinkAudio(const QString &srcdir) const
|
|||||||
QString hash=RDSha1Hash(filename);
|
QString hash=RDSha1Hash(filename);
|
||||||
QString firstdest;
|
QString firstdest;
|
||||||
bool delete_source=true;
|
bool delete_source=true;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check against audio cuts
|
||||||
|
//
|
||||||
sql=QString("select CUTS.CUT_NAME,CART.TITLE from ")+
|
sql=QString("select CUTS.CUT_NAME,CART.TITLE from ")+
|
||||||
"CUTS left join CART "+
|
"CUTS left join CART "+
|
||||||
"on CUTS.CART_NUMBER=CART.NUMBER where "+
|
"on CUTS.CART_NUMBER=CART.NUMBER where "+
|
||||||
"CUTS.SHA1_HASH=\""+RDEscapeString(hash)+"\"";
|
"CUTS.SHA1_HASH=\""+RDEscapeString(hash)+"\"";
|
||||||
q=new RDSqlQuery(sql);
|
q=new RDSqlQuery(sql);
|
||||||
while(q->next()) {
|
while(q->next()) {
|
||||||
printf(" Recovering %06u/%03d [%s]...",
|
RelinkCut(filename,q->value(0).toString(),q->value(1).toString(),
|
||||||
RDCut::cartNumber(q->value(0).toString()),
|
&firstdest,&delete_source);
|
||||||
RDCut::cutNumber(q->value(0).toString()),
|
|
||||||
(const char *)q->value(1).toString());
|
|
||||||
fflush(stdout);
|
|
||||||
if(db_relink_audio_move) {
|
|
||||||
unlink(RDCut::pathName(q->value(0).toString()));
|
|
||||||
if(link(filename,RDCut::pathName(q->value(0).toString()))<0) {
|
|
||||||
if(errno==EXDEV) {
|
|
||||||
if(firstdest.isEmpty()) {
|
|
||||||
if(CopyFile(RDCut::pathName(q->value(0).toString()),filename)) {
|
|
||||||
firstdest=RDCut::pathName(q->value(0).toString());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr,"unable to copy file \"%s\"\n",
|
|
||||||
(const char *)filename);
|
|
||||||
delete_source=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unlink(RDCut::pathName(q->value(0).toString()));
|
|
||||||
link(firstdest,RDCut::pathName(q->value(0).toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr,"unable to move file \"%s\" [%s]\n",
|
|
||||||
(const char *)filename,strerror(errno));
|
|
||||||
delete_source=false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
if(firstdest.isEmpty()) {
|
|
||||||
if(CopyFile(RDCut::pathName(q->value(0).toString()),filename)) {
|
|
||||||
firstdest=RDCut::pathName(q->value(0).toString());
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
fprintf(stderr,"unable to copy file \"%s\"\n",
|
|
||||||
(const char *)filename);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
unlink(RDCut::pathName(q->value(0).toString()));
|
|
||||||
link(firstdest,RDCut::pathName(q->value(0).toString()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
printf(" done.\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Check against RSS posts
|
||||||
|
//
|
||||||
|
sql=QString("select ")+
|
||||||
|
"FEEDS.KEY_NAME,"+ // 00
|
||||||
|
"PODCASTS.ID,"+ // 01
|
||||||
|
"PODCASTS.ITEM_TITLE,"+ // 02
|
||||||
|
"PODCASTS.AUDIO_FILENAME "+ // 03
|
||||||
|
"from PODCASTS left join FEEDS "+
|
||||||
|
"on FEEDS.ID=PODCASTS.FEED_ID where "+
|
||||||
|
"PODCASTS.SHA1_HASH=\""+RDEscapeString(hash)+"\"";
|
||||||
|
q=new RDSqlQuery(sql);
|
||||||
|
while(q->next()) {
|
||||||
|
RelinkCast(filename,q->value(0).toString(),q->value(1).toUInt(),
|
||||||
|
q->value(2).toString(),q->value(3).toString(),
|
||||||
|
&firstdest,&delete_source);
|
||||||
|
}
|
||||||
|
delete q;
|
||||||
|
|
||||||
|
//
|
||||||
|
// (Perhaps) delete the source file
|
||||||
|
//
|
||||||
if(db_relink_audio_move&&delete_source) {
|
if(db_relink_audio_move&&delete_source) {
|
||||||
unlink(filename);
|
unlink(filename);
|
||||||
}
|
}
|
||||||
@ -450,6 +432,125 @@ void MainObject::RelinkAudio(const QString &srcdir) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainObject::RelinkCut(const QString &src_filename,const QString &cutname,
|
||||||
|
const QString &title,
|
||||||
|
QString *firstdest,bool *delete_src) const
|
||||||
|
{
|
||||||
|
printf(" Recovering %06u/%03d [%s]...",
|
||||||
|
RDCut::cartNumber(cutname),RDCut::cutNumber(cutname),
|
||||||
|
title.toUtf8().constData());
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
if(db_relink_audio_move) {
|
||||||
|
unlink(RDCut::pathName(cutname));
|
||||||
|
if(link(src_filename,RDCut::pathName(cutname))<0) {
|
||||||
|
if(errno==EXDEV) { // We're crossing filesystems, so do a copy
|
||||||
|
if(firstdest->isEmpty()) {
|
||||||
|
if(CopyToAudioStore(RDCut::pathName(cutname),src_filename)) {
|
||||||
|
*firstdest=RDCut::pathName(cutname);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr,"unable to copy file \"%s\"\n",
|
||||||
|
(const char *)src_filename);
|
||||||
|
*delete_src=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unlink(RDCut::pathName(cutname));
|
||||||
|
link(*firstdest,RDCut::pathName(cutname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr,"unable to move file \"%s\" [%s]\n",
|
||||||
|
(const char *)src_filename,strerror(errno));
|
||||||
|
*delete_src=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chown(RDCut::pathName(cutname),db_config->uid(),db_config->gid());
|
||||||
|
chmod(RDCut::pathName(cutname),S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(firstdest->isEmpty()) {
|
||||||
|
if(CopyToAudioStore(RDCut::pathName(cutname),src_filename)) {
|
||||||
|
*firstdest=RDCut::pathName(cutname);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr,"unable to copy file \"%s\"\n",
|
||||||
|
(const char *)src_filename);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unlink(RDCut::pathName(cutname));
|
||||||
|
link(*firstdest,RDCut::pathName(cutname));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf(" done.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void MainObject::RelinkCast(const QString &src_filename,const QString &keyname,
|
||||||
|
unsigned cast_id,const QString &title,
|
||||||
|
const QString &audio_filename,
|
||||||
|
QString *firstdest,bool *delete_src) const
|
||||||
|
{
|
||||||
|
QString destpath=QString(RD_AUDIO_ROOT)+"/"+audio_filename;
|
||||||
|
|
||||||
|
printf(" Recovering RSS item %s:%u [%s]...",
|
||||||
|
keyname.toUtf8().constData(),cast_id,title.toUtf8().constData());
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
if(db_relink_audio_move) {
|
||||||
|
unlink(destpath);
|
||||||
|
if(link(src_filename,destpath)<0) {
|
||||||
|
if(errno==EXDEV) { // We're crossing filesystems, so do a copy
|
||||||
|
if(firstdest->isEmpty()) {
|
||||||
|
if(CopyToAudioStore(destpath,src_filename)) {
|
||||||
|
*firstdest=destpath;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr,"unable to copy file \"%s\"\n",
|
||||||
|
(const char *)src_filename);
|
||||||
|
*delete_src=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unlink(destpath);
|
||||||
|
link(*firstdest,destpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr,"unable to move file \"%s\" [%s]\n",
|
||||||
|
(const char *)src_filename,strerror(errno));
|
||||||
|
*delete_src=false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
chown(destpath,db_config->uid(),db_config->gid());
|
||||||
|
chmod(destpath,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if(firstdest->isEmpty()) {
|
||||||
|
unlink(destpath);
|
||||||
|
if(CopyToAudioStore(destpath,src_filename)) {
|
||||||
|
*firstdest=destpath;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr,"unable to copy file \"%s\" [%s]\n",
|
||||||
|
(const char *)src_filename,strerror(errno));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
unlink(destpath);
|
||||||
|
link(*firstdest,destpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf(" done.\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MainObject::CheckOrphanedTracks() const
|
void MainObject::CheckOrphanedTracks() const
|
||||||
{
|
{
|
||||||
QString sql="select NUMBER,TITLE,OWNER from CART where OWNER!=\"\"";
|
QString sql="select NUMBER,TITLE,OWNER from CART where OWNER!=\"\"";
|
||||||
@ -865,7 +966,8 @@ bool MainObject::UserResponse() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool MainObject::CopyFile(const QString &destfile,const QString &srcfile) const
|
bool MainObject::CopyToAudioStore(const QString &destfile,
|
||||||
|
const QString &srcfile) const
|
||||||
{
|
{
|
||||||
int src_fd=-1;
|
int src_fd=-1;
|
||||||
struct stat src_stat;
|
struct stat src_stat;
|
||||||
@ -896,10 +998,10 @@ bool MainObject::CopyFile(const QString &destfile,const QString &srcfile) const
|
|||||||
write(dest_fd,data,n);
|
write(dest_fd,data,n);
|
||||||
}
|
}
|
||||||
free(data);
|
free(data);
|
||||||
fchown(dest_fd,150,150); // FIXME: do name lookup!
|
fchown(dest_fd,db_config->uid(),db_config->gid());
|
||||||
|
fchmod(dest_fd,S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP);
|
||||||
close(dest_fd);
|
close(dest_fd);
|
||||||
close(src_fd);
|
close(src_fd);
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -50,6 +50,13 @@ class MainObject : public QObject
|
|||||||
const QString &new_filename,const QString &new_str,
|
const QString &new_filename,const QString &new_str,
|
||||||
QString *err_msg);
|
QString *err_msg);
|
||||||
void RelinkAudio(const QString &srcdir) const;
|
void RelinkAudio(const QString &srcdir) const;
|
||||||
|
void RelinkCut(const QString &src_filename,const QString &cutname,
|
||||||
|
const QString &title,
|
||||||
|
QString *firstdest,bool *delete_src) const;
|
||||||
|
void RelinkCast(const QString &src_filename,const QString &keyname,
|
||||||
|
unsigned cast_id,const QString &title,
|
||||||
|
const QString &audio_filename,
|
||||||
|
QString *firstdest,bool *delete_src) const;
|
||||||
void CheckOrphanedTracks() const;
|
void CheckOrphanedTracks() const;
|
||||||
void CheckCutCounts() const;
|
void CheckCutCounts() const;
|
||||||
void CheckPendingCarts() const;
|
void CheckPendingCarts() const;
|
||||||
@ -62,7 +69,7 @@ class MainObject : public QObject
|
|||||||
void RehashCut(const QString &cutnum) const;
|
void RehashCut(const QString &cutnum) const;
|
||||||
void SetCutLength(const QString &cutname,int len) const;
|
void SetCutLength(const QString &cutname,int len) const;
|
||||||
void RemoveCart(unsigned cartnum);
|
void RemoveCart(unsigned cartnum);
|
||||||
bool CopyFile(const QString &destfile,const QString &srcfile) const;
|
bool CopyToAudioStore(const QString &destfile,const QString &srcfile) const;
|
||||||
bool UserResponse() const;
|
bool UserResponse() const;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -40,6 +40,16 @@ bool MainObject::RevertSchema(int cur_schema,int set_schema,QString *err_msg)
|
|||||||
// NEW SCHEMA REVERSIONS GO HERE...
|
// NEW SCHEMA REVERSIONS GO HERE...
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Revert 335
|
||||||
|
//
|
||||||
|
if((cur_schema==335)&&(set_schema<cur_schema)) {
|
||||||
|
DropIndex("PODCASTS","SHA1_HASH_IDX");
|
||||||
|
DropColumn("PODCASTS","SHA1_HASH");
|
||||||
|
|
||||||
|
WriteSchemaVersion(--cur_schema);
|
||||||
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Revert 334
|
// Revert 334
|
||||||
//
|
//
|
||||||
|
@ -161,7 +161,7 @@ void MainObject::InitializeSchemaMap() {
|
|||||||
global_version_map["3.2"]=311;
|
global_version_map["3.2"]=311;
|
||||||
global_version_map["3.3"]=314;
|
global_version_map["3.3"]=314;
|
||||||
global_version_map["3.4"]=317;
|
global_version_map["3.4"]=317;
|
||||||
global_version_map["4.0"]=334;
|
global_version_map["4.0"]=335;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -10243,6 +10243,20 @@ bool MainObject::UpdateSchema(int cur_schema,int set_schema,QString *err_msg)
|
|||||||
WriteSchemaVersion(++cur_schema);
|
WriteSchemaVersion(++cur_schema);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if((cur_schema<335)&&(set_schema>cur_schema)) {
|
||||||
|
sql=QString("alter table PODCASTS add column ")+
|
||||||
|
"SHA1_HASH varchar(40) after AUDIO_TIME";
|
||||||
|
if(!RDSqlQuery::apply(sql,err_msg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
sql=QString("alter table PODCASTS add index SHA1_HASH_IDX(SHA1_HASH)");
|
||||||
|
if(!RDSqlQuery::apply(sql,err_msg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
WriteSchemaVersion(++cur_schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -29,6 +29,7 @@
|
|||||||
#include <rdescape_string.h>
|
#include <rdescape_string.h>
|
||||||
#include <rdformpost.h>
|
#include <rdformpost.h>
|
||||||
#include <rdgroup.h>
|
#include <rdgroup.h>
|
||||||
|
#include <rdhash.h>
|
||||||
#include <rdpodcast.h>
|
#include <rdpodcast.h>
|
||||||
#include <rduser.h>
|
#include <rduser.h>
|
||||||
#include <rdweb.h>
|
#include <rdweb.h>
|
||||||
@ -83,6 +84,7 @@ void Xport::SavePodcast()
|
|||||||
delete cast;
|
delete cast;
|
||||||
XmlExit(err_msg.toUtf8(),500,"podcasts.cpp",LINE_NUMBER);
|
XmlExit(err_msg.toUtf8(),500,"podcasts.cpp",LINE_NUMBER);
|
||||||
}
|
}
|
||||||
|
cast->setSha1Hash(RDSha1Hash(destpath));
|
||||||
|
|
||||||
printf("Content-type: text/html; charset: UTF-8\n");
|
printf("Content-type: text/html; charset: UTF-8\n");
|
||||||
printf("Status: 200\n\n");
|
printf("Status: 200\n\n");
|
||||||
@ -191,6 +193,7 @@ void Xport::DeletePodcast()
|
|||||||
XmlExit(err_msg.toUtf8(),500,"podcasts.cpp",LINE_NUMBER);
|
XmlExit(err_msg.toUtf8(),500,"podcasts.cpp",LINE_NUMBER);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
cast->setSha1Hash();
|
||||||
|
|
||||||
printf("Content-type: text/html; charset: UTF-8\n");
|
printf("Content-type: text/html; charset: UTF-8\n");
|
||||||
printf("Status: 200\n\n");
|
printf("Status: 200\n\n");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user