From 672bd74a7c1a014252992074b816491b2797696f Mon Sep 17 00:00:00 2001 From: Fred Gleason Date: Fri, 25 Mar 2022 08:39:52 -0400 Subject: [PATCH] 2022-03-25 Fred Gleason * Added '--by-isci' and '--dump-isci-xref' options to rdimport(1). Signed-off-by: Fred Gleason --- ChangeLog | 2 + docs/manpages/rdimport.xml | 35 ++++++ utils/rdimport/rdimport.cpp | 241 ++++++++++++++++++++++++++++++++++-- utils/rdimport/rdimport.h | 16 ++- 4 files changed, 282 insertions(+), 12 deletions(-) diff --git a/ChangeLog b/ChangeLog index 84113e4d..f0a7b0d9 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22947,3 +22947,5 @@ * Fixed a bug in the 'rdxport' service that caused the 'ListLog' WebAPI call to return null values in the 'description', 'isrc', 'isci', 'recordingMbId' and 'releaseMbId' fields. +2022-03-25 Fred Gleason + * Added '--by-isci' and '--dump-isci-xref' options to rdimport(1). diff --git a/docs/manpages/rdimport.xml b/docs/manpages/rdimport.xml index 36fe54de..76cdd8c9 100644 --- a/docs/manpages/rdimport.xml +++ b/docs/manpages/rdimport.xml @@ -80,6 +80,29 @@ + + + [=service-name] + + + + Determine the target cart number by looking it up in the ISCI + cross-reference table, using the ISCI code provided by the + or + options. If + service-name is given, prepend the + Program Code for the specified service followed by an underscore + to the ISCI code when doing the cart number lookup in the ISCI + cross-reference table. Useful for importing sets of copy-split + audio. + + + This option is mutually exclusive with the + option. + + + + offset @@ -188,6 +211,18 @@ + + + + + + + Print a copy of the current ISCI cross-reference table and then + exit. Useless except for debugging. + + + + days diff --git a/utils/rdimport/rdimport.cpp b/utils/rdimport/rdimport.cpp index a1f2490a..cb02b9f8 100644 --- a/utils/rdimport/rdimport.cpp +++ b/utils/rdimport/rdimport.cpp @@ -2,7 +2,7 @@ // // A Batch Importer for Rivendell. // -// (C) Copyright 2002-2021 Fred Gleason +// (C) Copyright 2002-2022 Fred Gleason // // 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 @@ -41,6 +41,7 @@ #include #include #include +#include #include #include "rdimport.h" @@ -99,7 +100,10 @@ MainObject::MainObject(QObject *parent) import_send_mail=false; import_mail_per_file=false; import_journal=NULL; - + import_dump_isci_xref=false; + import_by_isci_program_code=""; + import_by_isci=false; + // // Open the Database // @@ -171,6 +175,42 @@ MainObject::MainObject(QObject *parent) import_delete_cuts=true; rda->cmdSwitch()->setProcessed(i,true); } + if(rda->cmdSwitch()->key(i)=="--dump-isci-xref") { + import_dump_isci_xref=true; + rda->cmdSwitch()->setProcessed(i,true); + } + if(rda->cmdSwitch()->key(i)=="--by-isci") { + import_by_isci=true; + if(!rda->cmdSwitch()->value(i).isEmpty()) { + RDSvc *svc=new RDSvc(rda->cmdSwitch()->value(i), + rda->station(),rda->config(),this); + if(!svc->exists()) { + Log(LOG_ERR,QString("rdimport: no such service\n")); + ErrorExit(RDApplication::ExitNoSvc); + } + import_by_isci_program_code=svc->programCode(); + delete svc; + } + rda->cmdSwitch()->setProcessed(i,true); + } + if(rda->cmdSwitch()->key(i)=="--dump-isci-xref") { + import_dump_isci_xref=true; + rda->cmdSwitch()->setProcessed(i,true); + } + if(rda->cmdSwitch()->key(i)=="--by-isci") { + import_by_isci=true; + if(!rda->cmdSwitch()->value(i).isEmpty()) { + RDSvc *svc=new RDSvc(rda->cmdSwitch()->value(i), + rda->station(),rda->config(),this); + if(!svc->exists()) { + Log(LOG_ERR,QString("rdimport: no such service\n")); + ErrorExit(RDApplication::ExitNoSvc); + } + import_by_isci_program_code=svc->programCode(); + delete svc; + } + rda->cmdSwitch()->setProcessed(i,true); + } if(rda->cmdSwitch()->key(i)=="--startdate-offset") { import_startdate_offset=rda->cmdSwitch()->value(i).toInt(&ok); if(!ok) { @@ -476,7 +516,11 @@ MainObject::MainObject(QObject *parent) Log(LOG_ERR,QString::asprintf("rdimport: --log-filename and --log-syslog are mutually exclusive\n")); ErrorExit(RDApplication::ExitInvalidOption); } - + if((import_cart_number>0)&&import_by_isci) { + Log(LOG_ERR,QString().sprintf("rdimport: --to-cart and --by-isci are mutually exclusive\n")); + ErrorExit(RDApplication::ExitInvalidOption); + } + import_cut_markers=new MarkerSet(); import_cut_markers->loadMarker(rda->cmdSwitch(),"cut"); import_talk_markers=new MarkerSet(); @@ -667,6 +711,18 @@ MainObject::MainObject(QObject *parent) else { Log(LOG_INFO,QString(" Delete cuts mode is OFF\n")); } + if(import_dump_isci_xref) { + Log(LOG_INFO,QString(" Dump ISCI Cross Reference File is ON\n")); + } + else { + Log(LOG_INFO,QString(" Dump ISCI Cross Reference File is OFF\n")); + } + if(import_by_isci) { + Log(LOG_INFO,QString(" Import by ISCI Code is ON\n")); + } + else { + Log(LOG_INFO,QString(" Import by ISCI Code is OFF\n")); + } if(import_drop_box) { Log(LOG_INFO,QString(" DropBox mode is ON\n")); } @@ -838,6 +894,36 @@ MainObject::MainObject(QObject *parent) } } + // + // ISCI Code Lookups + // + if(import_dump_isci_xref) { + QString err_msg; + if(LoadIsciXref(&err_msg,rda->system()->isciXreferencePath())) { + for(QMap::const_iterator it= + import_isci_xref.begin(); + it!=import_isci_xref.end();it++) { + printf("%32s : %06u | %s\n",it.key().toUtf8().constData(), + it.value()->cartNumber(), + it.value()->title().toUtf8().constData()); + } + exit(RDApplication::ExitOk); + } + else { + fprintf(stderr,"rdimport: isci Xref load failed [%s]\n", + err_msg.toUtf8().constData()); + exit(RDApplication::ExitImportFailed); + } + } + if(import_by_isci) { + QString err_msg; + if(!LoadIsciXref(&err_msg,rda->system()->isciXreferencePath())) { + fprintf(stderr,"rdimport: isci Xref load failed [%s]\n", + err_msg.toUtf8().constData()); + exit(RDApplication::ExitImportFailed); + } + } + // // Start the email journal // @@ -977,7 +1063,6 @@ void MainObject::ProcessFileEntry(const QString &entry) VerifyFile(QString::fromUtf8(globbuf.gl_pathv[i]),&import_cart_number); } else { - //ImportFile(QString::fromUtf8(globbuf.gl_pathv[i]),&import_cart_number); switch(ImportFile(QString::fromUtf8(globbuf.gl_pathv[i]),&import_cart_number)) { case MainObject::Success: break; @@ -1118,6 +1203,7 @@ MainObject::Result MainObject::ImportFile(const QString &filename, wavedata->setTitle(effective_group->generateTitle(filename)); } + /* // // Attempt to find a free cart // @@ -1136,15 +1222,93 @@ MainObject::Result MainObject::ImportFile(const QString &filename, if(!import_temp_fix_filename.isEmpty()) { QFile::remove(import_temp_fix_filename); import_temp_fix_filename=""; + */ + if(import_by_isci) { + QString isci=wavedata->isci().trimmed(); + if(isci.isEmpty()) { + isci=import_string_isci.trimmed(); + if(isci.isEmpty()) { + Log(LOG_WARNING,QString().sprintf(" File \"%s\" has no ISCI code, skipping...\n", + RDGetBasePart(filename).toUtf8().constData())); + wavefile->closeWave(); + import_failed_imports++; + import_journal->addFailure(effective_group->name(),filename, + tr("no isci code")); + delete wavefile; + delete wavedata; + delete effective_group; + return MainObject::FileBad; } + } + if(!import_by_isci_program_code.isEmpty()) { + isci=import_by_isci_program_code+"_"+isci; + } + RDWaveData *wd=import_isci_xref.value(isci,NULL); + if(wd==NULL) { + *cartnum=0; + } + else { + *cartnum=wd->cartNumber(); + } + if(*cartnum==0) { + Log(LOG_WARNING,QString().sprintf(" File \"%s\" has no ISCI xreference entry, skipping...\n", + RDGetBasePart(filename).toUtf8().constData())); + wavefile->closeWave(); + import_failed_imports++; import_journal->addFailure(effective_group->name(),filename, - tr("no free cart available in group")); + tr("no isci xref entry")); delete wavefile; delete wavedata; delete effective_group; - return MainObject::NoCart; + return MainObject::FileBad; + } + if(!effective_group->cartNumberValid(*cartnum)) { + Log(LOG_WARNING,QString().sprintf(" File \"%s\" cart number %06u is is not valid in group \"%s\", skipping...\n", + RDGetBasePart(filename).toUtf8().constData(), + *cartnum, + effective_group->name().toUtf8().constData())); + wavefile->closeWave(); + import_failed_imports++; + import_journal->addFailure(effective_group->name(),filename, + tr("forbidden cart number")); + delete wavefile; + delete wavedata; + delete effective_group; + return MainObject::FileBad; + } + if(import_string_title.isEmpty()) { + wavedata->setTitle(import_isci_xref.value(isci)->title()); + } + } + else { + // + // Attempt to find a free cart + // + if(*cartnum==0) { + *cartnum=effective_group->nextFreeCart(); + } + if(*cartnum==0) { + Log(LOG_ERR,QString().sprintf("rdimport: no free carts available in specified group\n")); + wavefile->closeWave(); + import_failed_imports++; + import_failed_imports++; + if(import_drop_box) { + if(!import_run) { + NormalExit(); + } + if(!import_temp_fix_filename.isEmpty()) { + QFile::remove(import_temp_fix_filename); + import_temp_fix_filename=""; + } + import_journal->addFailure(effective_group->name(),filename, + tr("no free cart available in group")); + delete wavefile; + delete wavedata; + delete effective_group; + return MainObject::NoCart; + } + ErrorExit(RDApplication::ExitImportFailed); } - ErrorExit(RDApplication::ExitImportFailed); } // @@ -2136,6 +2300,7 @@ bool MainObject::VerifyPattern(const QString &pattern) return false; } switch(pattern.at(++i).cell()) { + case 'c': case 'i': case 'm': case 'r': @@ -2214,6 +2379,68 @@ void MainObject::WriteTimestampCache(const QString &filename, } +bool MainObject::LoadIsciXref(QString *err_msg,const QString &filename) +{ + char line[1024]; + FILE *f=NULL; + bool ok=false; + + *err_msg=tr("OK"); + for(QMap::const_iterator it=import_isci_xref.begin(); + it!=import_isci_xref.end();it++) { + delete it.value(); + } + import_isci_xref.clear(); + + if((f=fopen(filename.toUtf8(),"r"))==NULL) { + *err_msg=strerror(errno); + return false; + } + + // + // Skip Header + // + fgets(line,1024,f); + fgets(line,1024,f); + + // + // Load Records + // + while(fgets(line,1024,f)!=NULL) { + RDStringList fields=fields.split(',',line,"\""); + if(fields.size()==9) { + for(int i=0;isetCartNumber(cartnum); + wd->setIsci(fields[4].trimmed()); + if(!fields[1].trimmed().isEmpty()) { + if(fields[7].isEmpty()) { + wd->setTitle(fields[1].trimmed()); + } + else { + wd->setTitle(fields[1].trimmed()+" - "+fields[7]); + } + } + import_isci_xref[fields[4].trimmed()]=wd; + } + } + } + else { + *err_msg=tr("invalid/corrupt data at line")+ + QString().sprintf("%d",3+fields.size()); + return false; + } + } + + return true; +} + + bool MainObject::SchedulerCodeExists(const QString &code) const { QString sql; diff --git a/utils/rdimport/rdimport.h b/utils/rdimport/rdimport.h index 3e77cd00..77c8a289 100644 --- a/utils/rdimport/rdimport.h +++ b/utils/rdimport/rdimport.h @@ -2,7 +2,7 @@ // // A Batch Importer for Rivendell. // -// (C) Copyright 2002-2020 Fred Gleason +// (C) Copyright 2002-2022 Fred Gleason // // 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 @@ -24,11 +24,11 @@ #include #include -#include -#include -#include -#include +#include +#include #include +#include +#include #include #include @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -75,6 +76,7 @@ class MainObject : public QObject void DeleteCuts(unsigned cartnum); QDateTime GetCachedTimestamp(const QString &filename); void WriteTimestampCache(const QString &filename,const QDateTime &dt); + bool LoadIsciXref(QString *err_msg,const QString &filename); bool SchedulerCodeExists(const QString &code) const; void ReadXmlFile(const QString &basename,RDWaveData *wavedata) const; void Log(int prio,const QString &msg) const; @@ -160,6 +162,10 @@ class MainObject : public QObject MarkerSet *import_fadedown_marker; MarkerSet *import_fadeup_marker; Journal *import_journal; + QMap import_isci_xref; + bool import_dump_isci_xref; + bool import_by_isci; + QString import_by_isci_program_code; };