diff --git a/.gitignore b/.gitignore index d1863bbc..af9fd0ed 100644 --- a/.gitignore +++ b/.gitignore @@ -21,6 +21,7 @@ *.rpm *.so *.spec +*.src? *.tar.gz *.tar.xz *.whl diff --git a/CODINGSTYLE b/CODINGSTYLE index 38f54e25..b65e688e 100644 --- a/CODINGSTYLE +++ b/CODINGSTYLE @@ -371,14 +371,14 @@ a GUI context. They should *not* be used in other contexts, including CONTRIBUTING CHANGES: -The master code repository for Rivendell resides at GitHub, and can be +The primary code repository for Rivendell resides at GitHub, and can be found at: https://github.com/ElvishArtisan/rivendell Changes should be submitted in the form of a pull request [PR] against -the 'master' branch. Information about drafting and submitting PRs can -be found at: +the default branch ('v4' as of this writing). Information about drafting and +submitting PRs can be found at: https://help.github.com/en/articles/about-pull-requests diff --git a/ChangeLog b/ChangeLog index bbcba59a..3cf8b75f 100644 --- a/ChangeLog +++ b/ChangeLog @@ -24596,10 +24596,91 @@ 2023-12-27 Fred Gleason * Fixed a regression in rdcatchd(8) that caused recordings to MPEG Layer II to fail. -2024-01-13 Fred Gleason +2024-01-12 Fred Gleason + * Documented the meaning of the 'RDLogLine::StartTimeType' enum + in 'lib/rdlog_line.h'. + * Changed the default value of the 'RDLogLine::Imported' start time + from '00:00:00' to NULL. + * Fixed a regression in rdairplay(1) that caused the 'Sch. Time' + column to be removed from the Full Log lists. +2024-01-12 Fred Gleason + * Changed the recommended base branch for PRs from 'master' to 'v4' + in the 'CONTRIBUTING CHANGES' section of 'CODINGSTYLE'. +2024-01-12 Fred Gleason + * Updated the screenshot of the Full Log widget in the 'Running Logs + with RDAirPlay' chapter of the Operations Guide. +2024-01-12 Fred Gleason + * Updated the build system to DEB packages to support environments + with no HPI support. +2024-01-16 Fred Gleason + * Incremented the package version to 4.1.2int0. +2024-01-24 Fred Gleason + * Incremented the package version to 4.1.3. +2024-02-05 Fred Gleason + * Added a 'REPLICATORS.PROGRAM_CODE' field to the database. + * Incremented the database version to 372. + * Added 'RDReplicator::programCode()' and + 'RDReplicator::setProgramCode()' methods. + * Added a 'Program Code' control to the 'Rivendell Replicators' + dialog in rdadmin(1). + * Renamed the 'Citadel X-Digital Portal' replicator to + 'X-Digital National ISCI Model'. + * Added a 'X-Digital Cue Model' replicator. +2024-02-06 Fred Gleason + * Fixed a regression in 'rdrepld/Makefile.am' that broke the + 'make rpm' target. +2024-02-06 Fred Gleason + * Incremented the package version to 4.1.3int0. +2024-02-06 Fred Gleason + * Changed the 'AUDIO_CARDS.NAME' database field from 'varchar(64)' + to 'text'. + * Incremented the database version to 373. +2024-02-06 Fred Gleason + * Fixed a regression in rdairplay(1) that could cause the space bar + to fail to start the next main log event. +2024-02-06 Fred Gleason + * Fixed a regression in rdlogmanager(1) that caused clock titles + to fail to be centered in the pie wedge display in the + 'Edit Clock' dialog. +2024-02-07 Fred Gleason + * Added the option to provision users from an existing RSS feed + to the 'Add RSS Feed' dialog in rdadmin(1). +2024-02-08 Fred Gleason + * Added 'RDTimeEdit::Mode' enumeration. + * Added 'RDTimeEdit::mode()', 'RDTimeEdit::setMode()', + 'RDTimeEdit::length()' and 'RDTimeEdit::setLength()' methods. + * Fixed a regression in rdlibrary(1) that caused the 'Forced Length' + control in the 'Edit Cart' dialog to be misformatted when the + system was configured to use 12 hour time format. +2024-02-08 Fred Gleason + * Implemented the 'Load Message" ['LM'] RML. +2024-02-09 Fred Gleason + * Added a 'RDEventFilter' class. + * Fixed bugs in rdairplay(1) that caused scroll bars to appear when + loading web content into the message widget. +2024-02-14 Fred Gleason + * Fixed a regression in rdlogmanager(1) that could throw SQL + 'column out of range' errors when importing traffic logs. + * Fixed a bug in rdlogmanager(1) that threw SQL errors when processing + log GUIDs containing apostrophes. +2024-02-14 Fred Gleason + * Added a 'RDAIRPLAY.MESSAGE_WIDGET_URL' field to the database. + * Incremented the database version to 374. + * Added 'RDAirPlayConf::messageWidgetUrl()' and + 'RDAirPlayConf::setMessageWidgetUrl()' methods. + * Modified rdairplay(1) to make the Message Widget retain the loaded + URL across instances. + * Modified rdairplay(1) to make the Message Widget continually poll + and update loaded URLs using the 'file:' schema. +2024-02-14 Fred Gleason + * Incremented the package version to v4.1.3int1. +2024-03-08 Fred Gleason + * Added a check to the audio importation system to validate metadata + cue point positions relative to the actual audio duration. +2024-04-02 Fred Gleason * Added an extended event PAD output at TCP port 34290. -2024-02-18 Fred Gleason +2024-04-02 Fred Gleason * Fixed a regression in rdairplay(1) that caused invalid PAD JSON to be emitted when processing a Chain event. -2024-02-18 Fred Gleason +2024-04-02 Fred Gleason * Added an 'eventType' field to the PAD JSON schema. diff --git a/INSTALL b/INSTALL index 593f5be3..4882a683 100644 --- a/INSTALL +++ b/INSTALL @@ -275,26 +275,26 @@ DISTRO-SPECIFIC NOTES --------------------- 1) RedHat Enterprise Linux 7 -Required build packages: git gcc-c++ automake autoconf libtool qt5-qtbase-devel qt5-qtbase-mysql qt5-linguist libcurl-devel cdparanoia-devel hpklinux-devel alsa-lib-devel jack-audio-connection-kit-devel libsamplerate-devel libsndfile-devel id3lib-devel libvorbis-devel flac-devel pam-devel soundtouch-devel twolame-devel libmad-devel lame-devel rpm-build createrepo fop docbook5-style-xsl libxslt kernel-devel rpm-sign man-pages openssl-devel taglib-devel libmusicbrainz5-devel libdiscid-devel libcoverart libcoverart-devel ImageMagick-c++-devel +Required build packages: git gcc-c++ automake autoconf libtool qt5-qtbase-devel qt5-qtbase-mysql qt5-linguist qt5-qtwebkit-devel libcurl-devel cdparanoia-devel hpklinux-devel alsa-lib-devel jack-audio-connection-kit-devel libsamplerate-devel libsndfile-devel id3lib-devel libvorbis-devel flac-devel pam-devel soundtouch-devel twolame-devel libmad-devel lame-devel rpm-build createrepo fop docbook5-style-xsl libxslt kernel-devel rpm-sign man-pages openssl-devel taglib-devel libmusicbrainz5-devel libdiscid-devel libcoverart libcoverart-devel ImageMagick-c++-devel Configure script invocation: ./configure --prefix=/usr --libdir=/usr/lib64 --libexecdir=/var/www/rd-bin --sysconfdir=/etc/httpd/conf.d 2) RedHat Enterprise Linux 8 -Required build packages: git gcc-c++ automake autoconf libtool qt5-qtbase-devel qt5-linguist qt5-qtbase-mysql libcurl-devel cdparanoia-devel alsa-lib-devel libsamplerate-devel libsndfile-devel libvorbis-devel flac-devel pam-devel soundtouch-devel twolame-devel libmad-devel lame-devel rpm-build createrepo libxslt kernel-devel rpm-sign man-pages openssl-devel taglib-devel libmusicbrainz5-devel id3lib-devel libdiscid-devel libcoverart libcoverart-devel jack-audio-connection-kit-devel docbook5-style-xsl ImageMagick-c++-devel fop-static hpklinux-devel +Required build packages: git gcc-c++ automake autoconf libtool qt5-qtbase-devel qt5-linguist qt5-qtbase-mysql qt5-qtwebkit-devel libcurl-devel cdparanoia-devel alsa-lib-devel libsamplerate-devel libsndfile-devel libvorbis-devel flac-devel pam-devel soundtouch-devel twolame-devel libmad-devel lame-devel rpm-build createrepo libxslt kernel-devel rpm-sign man-pages openssl-devel taglib-devel libmusicbrainz5-devel id3lib-devel libdiscid-devel libcoverart libcoverart-devel jack-audio-connection-kit-devel docbook5-style-xsl ImageMagick-c++-devel fop-static hpklinux-devel Configure script invocation: ./configure --prefix=/usr --libdir=/usr/lib64 --libexecdir=/var/www/rd-bin --sysconfdir=/etc/httpd/conf.d 3) RedHat Enterprise Linux 9 -Required build packages: git gcc-c++ automake autoconf libtool qt5-qtbase-devel qt5-linguist qt5-qtbase-mysql libcurl-devel cdparanoia-devel alsa-lib-devel libsamplerate-devel libsndfile-devel libvorbis-devel flac-devel pam-devel soundtouch-devel twolame-devel libmad-devel lame-devel rpm-build createrepo libxslt kernel-devel rpm-sign man-pages openssl-devel taglib-devel libmusicbrainz5-devel id3lib-devel libdiscid-devel libcoverart libcoverart-devel pipewire-jack-audio-connection-kit-devel docbook5-style-xsl ImageMagick-c++-devel fop-static hpklinux-devel +Required build packages: git gcc-c++ automake autoconf libtool qt5-qtbase-devel qt5-linguist qt5-qtbase-mysql qt5-qtwebkit-devel libcurl-devel cdparanoia-devel alsa-lib-devel libsamplerate-devel libsndfile-devel libvorbis-devel flac-devel pam-devel soundtouch-devel twolame-devel libmad-devel lame-devel rpm-build createrepo libxslt kernel-devel rpm-sign man-pages openssl-devel taglib-devel libmusicbrainz5-devel id3lib-devel libdiscid-devel libcoverart libcoverart-devel pipewire-jack-audio-connection-kit-devel docbook5-style-xsl ImageMagick-c++-devel fop-static hpklinux-devel Configure script invocation: ./configure --prefix=/usr --libdir=/usr/lib64 --libexecdir=/var/www/rd-bin --sysconfdir=/etc/httpd/conf.d 4) Ubuntu 20.04 LTS -Required build packages: apache2 libexpat1-dev libexpat1 libid3-dev libcurl4-gnutls-dev libcoverart-dev libdiscid-dev libmusicbrainz5-dev libcdparanoia-dev libsndfile1-dev libpam0g-dev libvorbis-dev python3 python3-pycurl python3-pymysql python3-serial python3-requests libsamplerate0-dev qtbase5-dev libqt5sql5-mysql libsoundtouch-dev libsystemd-dev libjack-jackd2-dev libasound2-dev libflac-dev libflac++-dev libmp3lame-dev libmad0-dev libtwolame-dev docbook5-xml libxml2-utils docbook-xsl-ns xsltproc fop make g++ libltdl-dev autoconf automake libssl-dev libtag1-dev qttools5-dev-tools debhelper openssh-server autoconf-archive gnupg pbuilder ubuntu-dev-tools apt-file +Required build packages: apache2 libexpat1-dev libexpat1 libid3-dev libcurl4-gnutls-dev libcoverart-dev libdiscid-dev libmusicbrainz5-dev libcdparanoia-dev libsndfile1-dev libpam0g-dev libvorbis-dev python3 python3-pycurl python3-pymysql python3-serial python3-requests libsamplerate0-dev qtbase5-dev libqt5sql5-mysql libqt5webkit5-dev libsoundtouch-dev libsystemd-dev libjack-jackd2-dev libasound2-dev libflac-dev libflac++-dev libmp3lame-dev libmad0-dev libtwolame-dev docbook5-xml libxml2-utils docbook-xsl-ns xsltproc fop make g++ libltdl-dev autoconf automake libssl-dev libtag1-dev qttools5-dev-tools debhelper openssh-server autoconf-archive gnupg pbuilder ubuntu-dev-tools apt-file Configure script invocation: ./configure --prefix=/usr --libdir=/usr/lib --libexecdir=/var/www/rd-bin --sysconfdir=/etc/apache2/conf-enabled --enable-rdxport-debug MUSICBRAINZ_LIBS="-ldiscid -lmusicbrainz5cc -lcoverartcc" @@ -310,7 +310,7 @@ be done by means of the following commands: 5) Ubuntu 22.04 LTS -Required build packages: apache2 libexpat1-dev libexpat1 libid3-dev libcurl4-gnutls-dev libcoverart-dev libdiscid-dev libmusicbrainz5-dev libcdparanoia-dev libsndfile1-dev libpam0g-dev libvorbis-dev python3 python3-pycurl python3-pymysql python3-serial python3-requests libsamplerate0-dev qtbase5-dev libqt5sql5-mysql libsoundtouch-dev libsystemd-dev libjack-jackd2-dev libasound2-dev libflac-dev libflac++-dev libmp3lame-dev libmad0-dev libtwolame-dev docbook5-xml libxml2-utils docbook-xsl-ns xsltproc fop make g++ libltdl-dev autoconf automake libssl-dev libtag1-dev qttools5-dev-tools debhelper openssh-server autoconf-archive gnupg pbuilder ubuntu-dev-tools apt-file hpklinux-dev libmagick++-dev +Required build packages: apache2 libexpat1-dev libexpat1 libid3-dev libcurl4-gnutls-dev libcoverart-dev libdiscid-dev libmusicbrainz5-dev libcdparanoia-dev libsndfile1-dev libpam0g-dev libvorbis-dev python3 python3-pycurl python3-pymysql python3-serial python3-requests libsamplerate0-dev qtbase5-dev libqt5sql5-mysql libqt5webkit5-dev libsoundtouch-dev libsystemd-dev libjack-jackd2-dev libasound2-dev libflac-dev libflac++-dev libmp3lame-dev libmad0-dev libtwolame-dev docbook5-xml libxml2-utils docbook-xsl-ns xsltproc fop make g++ libltdl-dev autoconf automake libssl-dev libtag1-dev qttools5-dev-tools debhelper openssh-server autoconf-archive gnupg pbuilder ubuntu-dev-tools apt-file hpklinux-dev libmagick++-dev Configure script invocation: ./configure --prefix=/usr --libdir=/usr/lib --libexecdir=/var/www/rd-bin --sysconfdir=/etc/apache2/conf-enabled --enable-rdxport-debug MUSICBRAINZ_LIBS="-ldiscid -lmusicbrainz5cc -lcoverartcc" diff --git a/NEWS b/NEWS index 398e33fe..f2122f58 100644 --- a/NEWS +++ b/NEWS @@ -1,5 +1,45 @@ The NEWS file for the Rivendell package. +------------------------------------------------------------------------------- +v4.1.3int1 -- 14 February 2024 + +Changes: + Podcasting System. Added the ability to provision users for a new + RSS feed on the basis of the membership of an existing feed. + + RDAirPlay. Added a 'Load Message' ['LM'] RML for loading the contents + of a web page into the Message Widget. + + Replication. Added a 'X-Digital Cue Model' replicator. + + Bug fixes. See the ChangeLog. + +Database Update: + This version of Rivendell uses database schema version 374, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, do 'sudo rddbmgr'. + + Be sure to run 'rddbmgr --modify' (as root) immediately after upgrading + to allow any necessary changes to the database schema to be applied. +------------------------------------------------------------------------------- +v4.1.3 -- 24 January 2024 + +Changes: + Library Search. Optimized search library syntax to better handle cart + numbers and phrase vs. individual word search scenarios. See the + 'Library Text Searches' appendix in the Operations Guide for details. + + Tweaked rdairplay(1) layout to work with 1280x1024 resolution displays. + + Bugfixes. See the ChangeLog for details + +Database Update: + This version of Rivendell uses database schema version 371, and will + automatically upgrade any earlier versions. To see the current schema + version prior to upgrade, do 'sudo rddbmgr'. + + Be sure to run 'rddbmgr --modify' (as root) immediately after upgrading + to allow any necessary changes to the database schema to be applied. ------------------------------------------------------------------------------- v4.1.2 -- 21 November 2023 diff --git a/autogen.sh b/autogen.sh index 26c362fe..a026c8e6 100755 --- a/autogen.sh +++ b/autogen.sh @@ -24,7 +24,12 @@ # Generate Debian packaging metadata # DATESTAMP=`date +%a,\ %d\ %b\ %Y\ %T\ %z` +if test -f /usr/include/asihpi/hpi.h ; then + HPKLINUX_DEP="\,hpklinux-dev" +fi sed s/@VERSION@/`cat versions/PACKAGE_VERSION`/ < debian/control.src > debian/control +sed s/@HPKLINUX_DEP@/$HPKLINUX_DEP/ debian/control.src2 +sed s/@VERSION@/`cat versions/PACKAGE_VERSION`/ < debian/control.src2 > debian/control sed s/@VERSION@/`cat versions/PACKAGE_VERSION`/ < debian/changelog.src | sed "s/@DATESTAMP@/$DATESTAMP/" > debian/changelog sed s/@PYTHONAPI_VERSION@/`cat versions/PYTHONAPI_VERSION`/ < debian/rules.src > debian/rules diff --git a/configure.ac b/configure.ac index e0cddade..5baf1ee5 100644 --- a/configure.ac +++ b/configure.ac @@ -93,7 +93,7 @@ AC_ARG_ENABLE(i18n-updates,[ --enable-i18n-updates enable I18N metadata updat # # Check for Qt5 (Mandatory) # -PKG_CHECK_MODULES(QT5,Qt5Core Qt5Widgets Qt5Gui Qt5Network Qt5Sql Qt5Xml,,[AC_MSG_ERROR([*** Qt5 not found ***])]) +PKG_CHECK_MODULES(QT5,Qt5Core Qt5Widgets Qt5Gui Qt5Network Qt5Sql Qt5Xml Qt5WebKitWidgets,,[AC_MSG_ERROR([*** Qt5 not found ***])]) PKG_CHECK_MODULES(QT5_CLI,Qt5Core Qt5Network Qt5Sql Qt5Xml,,[AC_MSG_ERROR([*** Qt5 not found ***])]) AC_CHECK_PROG(MOC_NAME,moc-qt5,[moc-qt5],[moc]) AC_SUBST(QT_MOC,$MOC_NAME) diff --git a/debian/Makefile.am b/debian/Makefile.am index 22262c0a..7fa26ad9 100644 --- a/debian/Makefile.am +++ b/debian/Makefile.am @@ -2,7 +2,7 @@ ## ## Automake.am for rivendell debian/ ## -## (C) Copyright 2021 Fred Gleason +## (C) Copyright 2021-2023 Fred Gleason ## ## This program is free software; you can redistribute it and/or modify ## it under the terms of the GNU General Public License as @@ -35,4 +35,5 @@ EXTRA_DIST = changelog\ MAINTAINERCLEANFILES = changelog\ control\ + control.src2\ rules diff --git a/debian/control.src b/debian/control.src index 9bdb090a..d135e349 100644 --- a/debian/control.src +++ b/debian/control.src @@ -2,7 +2,7 @@ Source: rivendell Section: audio Priority: optional Maintainer: Fred Gleason -Build-Depends: debhelper-compat (= 12), autotools-dev, hpklinux-dev +Build-Depends: debhelper-compat (= 12), autotools-dev @HPKLINUX_DEP@ Standards-Version: 4.4.1 Package: rivendell diff --git a/docs/opsguide/rdairplay.full_log_widget.png b/docs/opsguide/rdairplay.full_log_widget.png index f07c1500..1e36be98 100644 Binary files a/docs/opsguide/rdairplay.full_log_widget.png and b/docs/opsguide/rdairplay.full_log_widget.png differ diff --git a/docs/opsguide/rdairplay.xml b/docs/opsguide/rdairplay.xml index 014e3faa..92f1ac9a 100644 --- a/docs/opsguide/rdairplay.xml +++ b/docs/opsguide/rdairplay.xml @@ -308,7 +308,7 @@ - + diff --git a/docs/opsguide/rml.xml b/docs/opsguide/rml.xml index 97ef75d8..7d3a1f47 100644 --- a/docs/opsguide/rml.xml +++ b/docs/opsguide/rml.xml @@ -1227,6 +1227,33 @@ + + Load Message [LM] + + + + Module + rdairplay1 + + + Mnemonic + LM + + + + + Load a webpage into RDAirPlay's Message Area. + + + LM + url! + + + Display the web page specified by url in the + message widget. + + + Load Panel [PE] diff --git a/docs/tables/audio_cards.txt b/docs/tables/audio_cards.txt index 26ab92d4..e1c7f111 100644 --- a/docs/tables/audio_cards.txt +++ b/docs/tables/audio_cards.txt @@ -9,7 +9,7 @@ ID int(10) unsigned Primary key, auto increment STATION_NAME varchar(64) CARD_NUMBER int(11) signed DRIVER int(11) signed -NAME varchar(64) +NAME text INPUTS int(11) signed OUTPUTS int(11) signed CLOCK_SOURCE int(11) signed 0 = Internal, 1 = AES/EBU, diff --git a/docs/tables/rd_airplay.txt b/docs/tables/rd_airplay.txt index f0762c63..b30d4f9f 100644 --- a/docs/tables/rd_airplay.txt +++ b/docs/tables/rd_airplay.txt @@ -35,3 +35,4 @@ TITLE_TEMPLATE varchar(64) ARTIST_TEMPLATE varchar(64) OUTCUE_TEMPLATE varchar(64) DESCRIPTION_TEMPLATE varchar(64) +MESSAGE_WIDGET_URL text diff --git a/docs/tables/replicators.txt b/docs/tables/replicators.txt index cd22f9b7..6f31bae9 100644 --- a/docs/tables/replicators.txt +++ b/docs/tables/replicators.txt @@ -9,6 +9,7 @@ NAME varchar(32) not null, primary key DESCRIPTION varchar(64) TYPE_ID int(10) unsigned not null STATION_NAME varchar(64) from STATIONS.NAME +PROGRAM_CODE varchar(191) FORMAT int(10) unsigned CHANNELS int(10) unsigned SAMPRATE int(10) unsigned diff --git a/lib/Makefile.am b/lib/Makefile.am index 6f383659..638b37ec 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -132,6 +132,7 @@ dist_librd_la_SOURCES = dbversion.h\ rdevent.cpp rdevent.h\ rdevent_line.cpp rdevent_line.h\ rdevent_player.cpp rdevent_player.h\ + rdeventfilter.cpp rdeventfilter.h\ rdeventimportlist.cpp rdeventimportlist.h\ rdexport_settings_dialog.cpp rdexport_settings_dialog.h\ rdfeed.cpp rdfeed.h\ @@ -344,6 +345,7 @@ nodist_librd_la_SOURCES = moc_rdadd_cart.cpp\ moc_rdemptycart.cpp\ moc_rdendpointlistmodel.cpp\ moc_rdevent_player.cpp\ + moc_rdeventfilter.cpp\ moc_rdexport_settings_dialog.cpp\ moc_rdfeed.cpp\ moc_rdfeedlistmodel.cpp\ diff --git a/lib/dbversion.h b/lib/dbversion.h index fff661dd..fed7da8d 100644 --- a/lib/dbversion.h +++ b/lib/dbversion.h @@ -2,7 +2,7 @@ // // The Current Database Schema Version for Rivendell // -// (C) Copyright 2002-2023 Fred Gleason +// (C) Copyright 2002-2024 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,7 +24,7 @@ /* * Current Database Version */ -#define RD_VERSION_DATABASE 371 +#define RD_VERSION_DATABASE 374 #endif // DBVERSION_H diff --git a/lib/librd.pro b/lib/librd.pro index 0a51f834..158a2bfb 100644 --- a/lib/librd.pro +++ b/lib/librd.pro @@ -102,6 +102,7 @@ SOURCES += rdescape_string.cpp SOURCES += rdevent.cpp SOURCES += rdevent_line.cpp SOURCES += rdeventimportlist.cpp +SOURCES += rdeventfilter.cpp SOURCES += rdexport_settings_dialog.cpp SOURCES += rdfeedlistmodel.cpp SOURCES += rdfontengine.cpp @@ -292,6 +293,7 @@ HEADERS += rdendpointlistmodel.h HEADERS += rdescape_string.h HEADERS += rdevent.h HEADERS += rdevent_line.h +HEADERS += rdeventfilter.h HEADERS += rdeventimportlist.h HEADERS += rdexport_settings_dialog.h HEADERS += rdfeedlistmodel.h diff --git a/lib/rdairplay_conf.cpp b/lib/rdairplay_conf.cpp index 281f0be9..656e8419 100644 --- a/lib/rdairplay_conf.cpp +++ b/lib/rdairplay_conf.cpp @@ -749,6 +749,24 @@ void RDAirPlayConf::setAuditionPreroll(int msecs) const } +QString RDAirPlayConf::messageWidgetUrl() const +{ + return RDGetSqlValue(air_tablename,"ID",air_id,"MESSAGE_WIDGET_URL"). + toString(); +} + + +void RDAirPlayConf::setMessageWidgetUrl(const QString url) +{ + if(url.trimmed().isEmpty()) { + SetRowNull("MESSAGE_WIDGET_URL"); + } + else { + SetRow("MESSAGE_WIDGET_URL",url); + } +} + + RDAirPlayConf::StartMode RDAirPlayConf::startMode(int lognum) const { RDAirPlayConf::StartMode ret=RDAirPlayConf::StartEmpty; @@ -1162,50 +1180,53 @@ void RDAirPlayConf::SetLogMode(const QString ¶m,int mach, RDAirPlayConf::OpMode mode) const { QString sql; - RDSqlQuery *q; sql=QString("update `LOG_MODES` set `")+param+QString::asprintf("`=%d ",mode)+ "where (`STATION_NAME`='"+RDEscapeString(air_station)+"')&&"+ QString::asprintf("(`MACHINE`=%d)",mach); - q=new RDSqlQuery(sql); - delete q; + RDSqlQuery::apply(sql); } void RDAirPlayConf::SetRow(const QString ¶m,int value) const { - RDSqlQuery *q; QString sql; sql=QString("update `")+air_tablename+"` set `"+ param+QString::asprintf("`=%d where ",value)+ "`STATION`='"+RDEscapeString(air_station)+"'"; - q=new RDSqlQuery(sql); - delete q; + RDSqlQuery::apply(sql); } void RDAirPlayConf::SetRow(const QString ¶m,unsigned value) const { - RDSqlQuery *q; QString sql; sql=QString("update `")+air_tablename+"` set `"+ param+QString::asprintf("`=%u where ",value)+ "`STATION`='"+RDEscapeString(air_station)+"'"; - q=new RDSqlQuery(sql); - delete q; + RDSqlQuery::apply(sql); } void RDAirPlayConf::SetRow(const QString ¶m,const QString &value) const { - RDSqlQuery *q; QString sql; sql=QString("update `")+air_tablename+"` set `"+ param+"`='"+RDEscapeString(value)+"' where "+ "`STATION`='"+RDEscapeString(air_station)+"'"; - q=new RDSqlQuery(sql); - delete q; + RDSqlQuery::apply(sql); } + + + void RDAirPlayConf::SetRowNull(const QString ¶m) const + { + QString sql; + + sql=QString("update `")+air_tablename+"` set `"+ + param+"`=NULL where "+ + "`STATION`='"+RDEscapeString(air_station)+"'"; + RDSqlQuery::apply(sql); + } diff --git a/lib/rdairplay_conf.h b/lib/rdairplay_conf.h index 8305f5f0..3c0ac3c3 100644 --- a/lib/rdairplay_conf.h +++ b/lib/rdairplay_conf.h @@ -143,6 +143,8 @@ class RDAirPlayConf void setShowCounters(bool state) const; int auditionPreroll() const; void setAuditionPreroll(int msecs) const; + QString messageWidgetUrl() const; + void setMessageWidgetUrl(const QString url); RDAirPlayConf::StartMode startMode(int lognum) const; void setStartMode(int lognum,RDAirPlayConf::StartMode mode) const; bool autoRestart(int lognum) const; @@ -176,6 +178,7 @@ class RDAirPlayConf void SetRow(const QString ¶m,int value) const; void SetRow(const QString ¶m,unsigned value) const; void SetRow(const QString ¶m,const QString &value) const; + void SetRowNull(const QString ¶m) const; QString air_station; unsigned air_id; QString air_tablename; diff --git a/lib/rdeventfilter.cpp b/lib/rdeventfilter.cpp new file mode 100644 index 00000000..1e1110b1 --- /dev/null +++ b/lib/rdeventfilter.cpp @@ -0,0 +1,59 @@ +// rdeventfilter.cpp +// +// Filter one or more window system events +// +// (C) Copyright 2024 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 +// 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 + +#include + +#include "rdeventfilter.h" + +RDEventFilter::RDEventFilter(QObject *parent) +{ +} + + +QList RDEventFilter::filterList() const +{ + return d_filter_types; +} + + +void RDEventFilter::addFilter(QEvent::Type type) +{ + if(!d_filter_types.contains(type)) { + d_filter_types.push_back(type); + } +} + + +void RDEventFilter::removeFilter(QEvent::Type type) +{ + d_filter_types.removeAll(type); +} + + +bool RDEventFilter::eventFilter(QObject *obj,QEvent *e) +{ + if(d_filter_types.contains(e->type())) { + // Block it + return true; + } + return QObject::eventFilter(obj,e); +} diff --git a/lib/rdeventfilter.h b/lib/rdeventfilter.h new file mode 100644 index 00000000..558bff89 --- /dev/null +++ b/lib/rdeventfilter.h @@ -0,0 +1,40 @@ +// rdeventfilter.h +// +// Filter one or more window system events +// +// (C) Copyright 2024 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 +// 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. +// + +#ifndef RDEVENTFILTER_H +#define RDEVENTFILTER_H + +#include +#include + +class RDEventFilter : public QObject +{ + public: + RDEventFilter(QObject *parent); + QList filterList() const; + void addFilter(QEvent::Type type); + void removeFilter(QEvent::Type type); + + protected: + bool eventFilter(QObject *obj,QEvent *e) override; + QList d_filter_types; +}; + +#endif // RDEVENTFILTER_H diff --git a/lib/rdlog_line.cpp b/lib/rdlog_line.cpp index f5783cbf..89f2de80 100644 --- a/lib/rdlog_line.cpp +++ b/lib/rdlog_line.cpp @@ -118,7 +118,7 @@ void RDLogLine::clear() log_pass=0; log_source=RDLogLine::Manual; log_cart_number=0; - log_start_time[RDLogLine::Imported]=QTime(0,0,0); + log_start_time[RDLogLine::Imported]=QTime(); log_start_time[RDLogLine::Logged]=QTime(0,0,0); log_start_time[RDLogLine::Predicted]=QTime(); log_start_time[RDLogLine::Actual]=QTime(0,0,0); diff --git a/lib/rdlog_line.h b/lib/rdlog_line.h index 87406fe8..3e5b0210 100644 --- a/lib/rdlog_line.h +++ b/lib/rdlog_line.h @@ -31,6 +31,23 @@ class RDLogLine { public: + // + // StartTimeType values: + // + // Imported - Value from an external scheduler --i.e. imported traffic + // or music log). + // + // Logged - Used by rdlogmanager(1) when processing log imports. + // + // Predicted - Generated by RDLogPlay on the basis of current log machine + // state. + // + // Actual - Time event was last started by RDLogPlay or RDCartSlot. + // (Includes restarts from a paused state). + // + // Initial - Time event was originally started by RDLogPlay (not reset when + // resuming from a paused state). + // enum StartTimeType {Imported=0,Logged=1,Predicted=2,Actual=3,Initial=4}; enum TimeType {Relative=0,Hard=1,NoTime=255}; enum TransType {Play=0,Segue=1,Stop=2,NoTrans=255}; diff --git a/lib/rdlogmodel.cpp b/lib/rdlogmodel.cpp index 00791050..c07ff909 100644 --- a/lib/rdlogmodel.cpp +++ b/lib/rdlogmodel.cpp @@ -1546,20 +1546,21 @@ QStringList RDLogModel::headerTexts() const { QStringList ret; - ret.push_back(tr("Start Time")); - ret.push_back(tr("Trans")); - ret.push_back(tr("Cart")); - ret.push_back(tr("Group")); - ret.push_back(tr("Length")); - ret.push_back(tr("Title")); - ret.push_back(tr("Artist")); - ret.push_back(tr("Client")); - ret.push_back(tr("Agency")); - ret.push_back(tr("Label")); - ret.push_back(tr("Source")); - ret.push_back(tr("Ext Data")); - ret.push_back(tr("Line ID")); - ret.push_back(tr("Count")); + ret.push_back(tr("Est. Time")); // 00 + ret.push_back(tr("Trans")); // 01 + ret.push_back(tr("Cart")); // 02 + ret.push_back(tr("Group")); // 03 + ret.push_back(tr("Length")); // 04 + ret.push_back(tr("Title")); // 05 + ret.push_back(tr("Artist")); // 06 + ret.push_back(tr("Sch. Time")); // 07 + ret.push_back(tr("Client")); // 08 + ret.push_back(tr("Agency")); // 09 + ret.push_back(tr("Label")); // 10 + ret.push_back(tr("Source")); // 11 + ret.push_back(tr("Ext Data")); // 12 + ret.push_back(tr("Line ID")); // 13 + ret.push_back(tr("Count")); // 14 return ret; } @@ -1572,13 +1573,14 @@ QList RDLogModel::columnAlignments() const int center=Qt::AlignCenter; int right=Qt::AlignRight|Qt::AlignVCenter; - ret.push_back(right); // Start Time + ret.push_back(right); // Estimated Time ret.push_back(center); // Trans ret.push_back(center); // Cart ret.push_back(center); // Group ret.push_back(right); // Length ret.push_back(left); // Title ret.push_back(left); // Artist + ret.push_back(right); // Scheduled Time ret.push_back(left); // Client ret.push_back(left); // Agency ret.push_back(left); // Label @@ -1624,19 +1626,22 @@ QString RDLogModel::cellText(int col,int line,RDLogLine *ll) const case 6: // Artist return ll->artist(); - case 7: // Client + case 7: // Scheduled Time + return rda->timeString(ll->startTime(RDLogLine::Imported)); + + case 8: // Client return ll->client(); - case 8: // Agency + case 9: // Agency return ll->agency(); - case 9: // Label + case 10: // Label return ll->markerLabel(); - case 10: // Source + case 11: // Source return RDLogLine::sourceText(ll->source()); - case 11: // Ext Data + case 12: // Ext Data switch(ll->type()) { case RDLogLine::MusicLink: case RDLogLine::TrafficLink: @@ -1654,10 +1659,10 @@ QString RDLogModel::cellText(int col,int line,RDLogLine *ll) const } break; - case 12: // Line ID + case 13: // Line ID return QString::asprintf("%d",ll->id()); - case 13: // Count + case 14: // Count return QString::asprintf("%d",line); } return QString(); diff --git a/lib/rdmacro.cpp b/lib/rdmacro.cpp index 34960a4b..d7082b72 100644 --- a/lib/rdmacro.cpp +++ b/lib/rdmacro.cpp @@ -80,6 +80,7 @@ void RDMacro::setCommand(const QString &str) case RDMacro::LB: case RDMacro::LC: case RDMacro::LL: + case RDMacro::LM: case RDMacro::LO: case RDMacro::MB: case RDMacro::MD: @@ -320,6 +321,7 @@ RDMacro RDMacro::fromString(const QString &str,RDMacro::Role role) case RDMacro::LB: case RDMacro::LC: case RDMacro::LL: + case RDMacro::LM: case RDMacro::LO: case RDMacro::MB: case RDMacro::MD: diff --git a/lib/rdmacro.h b/lib/rdmacro.h index fca7ee39..35f302b4 100644 --- a/lib/rdmacro.h +++ b/lib/rdmacro.h @@ -38,14 +38,14 @@ class RDMacro enum Command {AG=0x4147,AL=0x414C,BO=0x424F,CC=0x4343,CE=0x4345,CL=0x434C, CP=0x4350,DL=0x444C,DP=0x4450,DS=0x4453,DX=0x4458,EX=0x4558, FS=0x4653,GE=0x4745,GI=0x4749,GO=0x474F,JC=0x4A43,JD=0x4A44, - JZ=0x4A5A,LB=0x4C42,LC=0x4C43,LL=0x4C4C,LO=0x4C4F,MB=0x4D42, - MD=0x4D44,MN=0x4D4E,MT=0x4D54,NN=0x4E4E,PB=0x5042,PC=0x5043, - PD=0x5044,PE=0x5045,PL=0x504C,PM=0x504D,PN=0x504E,PP=0x5050, - PS=0x5053,PT=0x5054,PU=0x5055,PW=0x5057,PX=0x5058,RL=0x524C, - RN=0x524E,RS=0x5253,RR=0x5252,SA=0x5341,SC=0x5343,SD=0x5344, - SG=0x5347,SI=0x5349,SL=0x534C,SN=0x534e,SO=0x534F,SP=0x5350, - SR=0x5352,ST=0x5354,SX=0x5358,SY=0x5359,SZ=0x535A,TA=0x5441, - UO=0x554F}; + JZ=0x4A5A,LB=0x4C42,LC=0x4C43,LL=0x4C4C,LM=0x4C4D,LO=0x4C4F, + MB=0x4D42,MD=0x4D44,MN=0x4D4E,MT=0x4D54,NN=0x4E4E,PB=0x5042, + PC=0x5043,PD=0x5044,PE=0x5045,PL=0x504C,PM=0x504D,PN=0x504E, + PP=0x5050,PS=0x5053,PT=0x5054,PU=0x5055,PW=0x5057,PX=0x5058, + RL=0x524C,RN=0x524E,RS=0x5253,RR=0x5252,SA=0x5341,SC=0x5343, + SD=0x5344,SG=0x5347,SI=0x5349,SL=0x534C,SN=0x534e,SO=0x534F, + SP=0x5350,SR=0x5352,ST=0x5354,SX=0x5358,SY=0x5359,SZ=0x535A, + TA=0x5441,UO=0x554F}; enum Role {Invalid=0,Cmd=1,Reply=2}; RDMacro(); RDMacro::Role role() const; diff --git a/lib/rdreplicator.cpp b/lib/rdreplicator.cpp index 41ef3a94..e6af6c49 100644 --- a/lib/rdreplicator.cpp +++ b/lib/rdreplicator.cpp @@ -59,6 +59,18 @@ void RDReplicator::setStationName(const QString &str) } +QString RDReplicator::programCode() const +{ + return GetValue("PROGRAM_CODE").toString(); +} + + +void RDReplicator::setProgramCode(const QString &str) +{ + SetRow("PROGRAM_CODE",str); +} + + QString RDReplicator::description() const { return GetValue("DESCRIPTION").toString(); @@ -202,13 +214,17 @@ QString RDReplicator::typeString(RDReplicator::Type type) QString ret="Unknown type"; switch(type) { case RDReplicator::TypeCitadelXds: - ret="Citadel X-Digital Portal"; + ret="X-Digital National ISCI Model"; break; case RDReplicator::TypeWw1Ipump: ret="Westwood One Wegener Portal"; break; + case RDReplicator::TypeXdsCue: + ret="X-Digital Cue Model"; + break; + case RDReplicator::TypeLast: break; } diff --git a/lib/rdreplicator.h b/lib/rdreplicator.h index 23d80a3f..6554d527 100644 --- a/lib/rdreplicator.h +++ b/lib/rdreplicator.h @@ -28,13 +28,15 @@ class RDReplicator { public: - enum Type {TypeCitadelXds=0,TypeWw1Ipump=1,TypeLast=2}; + enum Type {TypeCitadelXds=0,TypeWw1Ipump=1,TypeXdsCue=2,TypeLast=3}; RDReplicator(const QString &name); QString name() const; RDReplicator::Type type() const; void setType(RDReplicator::Type type) const; QString stationName() const; void setStationName(const QString &str); + QString programCode() const; + void setProgramCode(const QString &str); QString description() const; void setDescription(const QString &str) const; RDSettings::Format format() const; diff --git a/lib/rdsvc.cpp b/lib/rdsvc.cpp index 08035175..6b57431b 100644 --- a/lib/rdsvc.cpp +++ b/lib/rdsvc.cpp @@ -590,11 +590,17 @@ bool RDSvc::import(ImportSource src,const QDate &date,const QString &break_str, int minutes_len_length=q->value(19).toInt(); int seconds_len_offset=q->value(20).toInt(); int seconds_len_length=q->value(21).toInt(); - int trans_type_offset=q->value(22).toInt(); - int trans_type_length=q->value(23).toInt(); - int time_type_offset=q->value(24).toInt(); - int time_type_length=q->value(25).toInt(); + int trans_type_offset=0; // Only used for music imports + int trans_type_length=0; + int time_type_offset=0; + int time_type_length=0; + if(src==RDSvc::Music) { + trans_type_offset=q->value(22).toInt(); + trans_type_length=q->value(23).toInt(); + time_type_offset=q->value(24).toInt(); + time_type_length=q->value(25).toInt(); + } delete q; // @@ -737,10 +743,10 @@ bool RDSvc::import(ImportSource src,const QDate &date,const QString &break_str, // if(start_time_ok&&cart_ok&&(cartnum>0)&&(cartnum<=RD_MAX_CART_NUMBER)) { sql+=QString::asprintf("`TYPE`=%u,",RDLogLine::Cart)+ - "`EXT_DATA`='"+data_buf.trimmed()+"',"+ - "`EXT_EVENT_ID`='"+eventid_buf.trimmed()+"',"+ - "`EXT_ANNC_TYPE`='"+annctype_buf.trimmed()+"',"+ - "`EXT_CART_NAME`='"+cartname.trimmed()+"',"+ + "`EXT_DATA`='"+RDEscapeString(data_buf.trimmed())+"',"+ + "`EXT_EVENT_ID`='"+RDEscapeString(eventid_buf.trimmed())+"',"+ + "`EXT_ANNC_TYPE`='"+RDEscapeString(annctype_buf.trimmed())+"',"+ + "`EXT_CART_NAME`='"+RDEscapeString(cartname.trimmed())+"',"+ QString::asprintf("`CART_NUMBER`=%u,",cartnum)+ "`TITLE`='"+RDEscapeString(title)+"'"; RDSqlQuery::apply(sql); diff --git a/lib/rdtimeedit.cpp b/lib/rdtimeedit.cpp index 7754f924..07e858c8 100644 --- a/lib/rdtimeedit.cpp +++ b/lib/rdtimeedit.cpp @@ -2,7 +2,7 @@ // // A QTimeEdit with tenth-second precision. // -// (C) Copyright 2003-2021 Fred Gleason +// (C) Copyright 2003-2024 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 @@ -27,6 +27,7 @@ RDTimeEdit::RDTimeEdit(QWidget *parent) : QTimeEdit(parent) { + d_mode=RDTimeEdit::TimeMode; d_show_hours=true; d_show_tenths=false; d_step_enabled=StepDownEnabled|StepUpEnabled; @@ -37,6 +38,19 @@ RDTimeEdit::RDTimeEdit(QWidget *parent) } +RDTimeEdit::Mode RDTimeEdit::mode() const +{ + return d_mode; +} + + +void RDTimeEdit::setMode(Mode mode) +{ + d_mode=mode; + SetFormat(); +} + + bool RDTimeEdit::showHours() const { return d_show_hours; @@ -73,6 +87,18 @@ bool RDTimeEdit::isReadOnly() const } +int RDTimeEdit::length() const +{ + return QTime(0,0,0).msecsTo(time()); +} + + +void RDTimeEdit::setLength(int msec) +{ + setTime(QTime(0,0,0).addMSecs(100*(msec/100))); +} + + void RDTimeEdit::setReadOnly(bool state) { if(d_read_only!=state) { @@ -206,48 +232,60 @@ QAbstractSpinBox::StepEnabled RDTimeEdit::stepEnabled() const void RDTimeEdit::SetFormat() { - if(rda->system()->showTwelveHourTime()) { - if(d_show_tenths) { - if(d_show_hours) { - setDisplayFormat(RD_TWELVE_HOUR_TENTHS_FORMAT); - d_width_variance=1; + if(d_mode==RDTimeEdit::TimeMode) { + if(rda->system()->showTwelveHourTime()) { + if(d_show_tenths) { + if(d_show_hours) { + setDisplayFormat(RD_TWELVE_HOUR_TENTHS_FORMAT); + d_width_variance=1; + } + else { + setDisplayFormat(RD_OFFSET_TENTHS_FORMAT); + d_width_variance=0; + } } else { - setDisplayFormat(RD_OFFSET_TENTHS_FORMAT); - d_width_variance=0; + if(d_show_hours) { + setDisplayFormat(RD_TWELVE_HOUR_FORMAT); + d_width_variance=0; + } + else { + setDisplayFormat(RD_OFFSET_FORMAT); + d_width_variance=0; + } } } else { - if(d_show_hours) { - setDisplayFormat(RD_TWELVE_HOUR_FORMAT); - d_width_variance=0; + if(d_show_tenths) { + if(d_show_hours) { + setDisplayFormat(RD_TWENTYFOUR_HOUR_TENTHS_FORMAT); + d_width_variance=0; + } + else { + setDisplayFormat(RD_OFFSET_TENTHS_FORMAT); + d_width_variance=0; + } } else { - setDisplayFormat(RD_OFFSET_FORMAT); - d_width_variance=0; + if(d_show_hours) { + setDisplayFormat(RD_TWENTYFOUR_HOUR_FORMAT); + d_width_variance=0; + } + else { + setDisplayFormat(RD_OFFSET_FORMAT); + d_width_variance=0; + } } } } - else { + if(d_mode==RDTimeEdit::LengthMode) { if(d_show_tenths) { - if(d_show_hours) { - setDisplayFormat(RD_TWENTYFOUR_HOUR_TENTHS_FORMAT); - d_width_variance=0; - } - else { - setDisplayFormat(RD_OFFSET_TENTHS_FORMAT); - d_width_variance=0; - } + setDisplayFormat(RD_OFFSET_TENTHS_FORMAT); + d_width_variance=0; } else { - if(d_show_hours) { - setDisplayFormat(RD_TWENTYFOUR_HOUR_FORMAT); - d_width_variance=0; - } - else { - setDisplayFormat(RD_OFFSET_FORMAT); - d_width_variance=0; - } + setDisplayFormat(RD_OFFSET_FORMAT); + d_width_variance=0; } } } diff --git a/lib/rdtimeedit.h b/lib/rdtimeedit.h index 88bc673c..98622579 100644 --- a/lib/rdtimeedit.h +++ b/lib/rdtimeedit.h @@ -2,7 +2,7 @@ // // A QTimeEdit with tenth-second precision. // -// (C) Copyright 2003-2021 Fred Gleason +// (C) Copyright 2003-2024 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 @@ -28,15 +28,20 @@ class RDTimeEdit : public QTimeEdit { Q_OBJECT public: + enum Mode {TimeMode=0,LengthMode=1}; RDTimeEdit(QWidget *parent=0); + Mode mode() const; + void setMode(Mode mode); bool showHours() const; void setShowHours(bool state); bool showTenths() const; void setShowTenths(bool state); bool isReadOnly() const; + int length() const; public slots: - void setReadOnly(bool state); + void setLength(int msec); + void setReadOnly(bool state); protected: QValidator::State validate(QString &input,int &pos) const; @@ -51,6 +56,7 @@ class RDTimeEdit : public QTimeEdit int d_width_variance; QAbstractSpinBox::StepEnabled d_step_enabled; bool d_read_only; + Mode d_mode; }; diff --git a/lib/rdtrackerwidget.cpp b/lib/rdtrackerwidget.cpp index 5525da72..a4c143c1 100644 --- a/lib/rdtrackerwidget.cpp +++ b/lib/rdtrackerwidget.cpp @@ -2,7 +2,7 @@ // // Rivendell Voice Tracker // -// (C) Copyright 2002-2022 Fred Gleason +// (C) Copyright 2002-2024 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 @@ -69,6 +69,7 @@ RDTrackerWidget::RDTrackerWidget(QString *import_path,QWidget *parent) d_menu_clicked_point=-1; d_shift_pressed=false; d_active=false; + d_focus_policy=Qt::WheelFocus; // // Create Palettes @@ -428,6 +429,25 @@ bool RDTrackerWidget::isActive() const } +void RDTrackerWidget::setFocusPolicy(Qt::FocusPolicy pol) +{ + d_focus_policy=pol; + d_play_button->setFocusPolicy(pol); + d_stop_button->setFocusPolicy(pol); + d_track1_button->setFocusPolicy(pol); + d_record_button->setFocusPolicy(pol); + d_track2_button->setFocusPolicy(pol); + d_finished_button->setFocusPolicy(pol); + d_post_button->setFocusPolicy(pol); + d_reset_button->setFocusPolicy(pol); + d_previous_button->setFocusPolicy(pol); + d_next_button->setFocusPolicy(pol); + d_insert_button->setFocusPolicy(pol); + d_delete_button->setFocusPolicy(pol); + d_log_view->setFocusPolicy(pol); +} + + bool RDTrackerWidget::load(const QString &logname) { QString username; @@ -3507,7 +3527,9 @@ void RDTrackerWidget::UpdateControls() d_track1_button->setPalette(d_record_palette); d_record_button->setEnabled(!d_group->name().isEmpty()); d_record_button->setText(tr("Record")); - d_record_button->setFocus(); + if(d_focus_policy!=Qt::NoFocus) { + d_record_button->setFocus(); + } } else { if((logline->transType()==RDLogLine::Segue)) { @@ -3515,7 +3537,9 @@ void RDTrackerWidget::UpdateControls() setEnabled(!d_group->name().isEmpty()); d_track1_button->setText(tr("Start")); d_track1_button->setPalette(d_start_palette); - d_track1_button->setFocus(); + if(d_focus_policy!=Qt::NoFocus) { + d_track1_button->setFocus(); + } d_record_button-> setEnabled(!d_group->name().isEmpty()); d_record_button->setText(tr("Import")); @@ -3528,7 +3552,9 @@ void RDTrackerWidget::UpdateControls() d_record_button-> setEnabled(!d_group->name().isEmpty()); d_record_button->setText(tr("Record")); - d_record_button->setFocus(); + if(d_focus_policy!=Qt::NoFocus) { + d_record_button->setFocus(); + } } } d_track2_button->setDisabled(true); @@ -3553,7 +3579,9 @@ void RDTrackerWidget::UpdateControls() d_track1_button->setPalette(d_start_palette); d_record_button->setEnabled(true); d_record_button->setText(tr("Record")); - d_record_button->setFocus(); + if(d_focus_policy!=Qt::NoFocus) { + d_record_button->setFocus(); + } d_track2_button->setDisabled(true); d_finished_button->setPalette(d_abort_palette); d_finished_button->setText(tr("Abort")); @@ -3578,7 +3606,9 @@ void RDTrackerWidget::UpdateControls() if(d_wave_name[2].isEmpty()) { d_finished_button->setPalette(d_done_palette); d_finished_button->setText(tr("Save")); - d_finished_button->setFocus(); + if(d_focus_policy!=Qt::NoFocus) { + d_finished_button->setFocus(); + } d_track2_button->setDisabled(true); } else { @@ -3598,7 +3628,9 @@ void RDTrackerWidget::UpdateControls() d_finished_button->setPalette(d_done_palette); d_track2_button->setDisabled(true); } - d_track2_button->setFocus(); + if(d_focus_policy!=Qt::NoFocus) { + d_track2_button->setFocus(); + } } d_finished_button->setEnabled(true); d_reset_button->setDisabled(true); @@ -3622,7 +3654,9 @@ void RDTrackerWidget::UpdateControls() d_finished_button->setPalette(d_done_palette); d_finished_button->setText(tr("Save")); d_finished_button->setEnabled(true); - d_finished_button->setFocus(); + if(d_focus_policy!=Qt::NoFocus) { + d_finished_button->setFocus(); + } d_reset_button->setDisabled(true); d_post_button->setDisabled(true); d_insert_button->setDisabled(true); @@ -3650,7 +3684,7 @@ void RDTrackerWidget::UpdateControls() d_stop_button->setEnabled(true); d_next_button->setEnabled(transport_idle); d_previous_button->setEnabled(transport_idle); - if(transport_idle) { + if(transport_idle&&(d_focus_policy!=Qt::NoFocus)) { d_next_button->setFocus(); } d_insert_button->setEnabled(transport_idle&&CanInsertTrack()); @@ -3674,7 +3708,7 @@ void RDTrackerWidget::UpdateControls() d_stop_button->setEnabled(true); d_next_button->setEnabled(transport_idle); d_previous_button->setEnabled(transport_idle); - if(transport_idle) { + if(transport_idle&&(d_focus_policy!=Qt::NoFocus)) { d_next_button->setFocus(); } d_insert_button->setEnabled(transport_idle&&CanInsertTrack()); diff --git a/lib/rdtrackerwidget.h b/lib/rdtrackerwidget.h index ac4ab4d1..54651439 100644 --- a/lib/rdtrackerwidget.h +++ b/lib/rdtrackerwidget.h @@ -2,7 +2,7 @@ // // Rivendell Voice Tracker // -// (C) Copyright 2002-2021 Fred Gleason +// (C) Copyright 2002-2024 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 @@ -70,6 +70,7 @@ class RDTrackerWidget : public RDWidget QSize sizeHint() const; QSizePolicy sizePolicy() const; bool isActive() const; + void setFocusPolicy(Qt::FocusPolicy pol); signals: void activeChanged(bool state); @@ -219,7 +220,6 @@ class RDTrackerWidget : public RDWidget QPushButton *d_next_button; QPushButton *d_insert_button; QPushButton *d_delete_button; - // QPushButton *d_close_button; RDEventPlayer *d_event_player; unsigned d_tracks; int d_time_remaining; @@ -273,7 +273,7 @@ class RDTrackerWidget : public RDWidget QLabel *d_tracks_remaining_label_label; QLabel *d_time_remaining_label_label; QLabel *d_time_label; - + Qt::FocusPolicy d_focus_policy; bool d_active; }; diff --git a/lib/rdwavefile.cpp b/lib/rdwavefile.cpp index b69464ca..2aa5aa4d 100644 --- a/lib/rdwavefile.cpp +++ b/lib/rdwavefile.cpp @@ -369,17 +369,21 @@ bool RDWaveFile::openWave(RDWaveData *data) wave_data->setMetadataFound(true); - if(tags->name) + if(tags->name) { wave_data->setTitle(tags->name); - if(tags->artist) + } + if(tags->artist) { wave_data->setArtist(tags->artist); - if(tags->composer) + } + if(tags->composer) { wave_data->setComposer(tags->composer); - if(tags->album) + } + if(tags->album) { wave_data->setAlbum(tags->album); + } dlmp4.MP4TagsFree(tags); - + wave_data->validateMarkers(ext_time_length); } dlmp4.MP4Close(f, 0); @@ -481,6 +485,10 @@ bool RDWaveFile::openWave(RDWaveData *data) } lseek(wave_file.handle(),data_start,SEEK_SET); + if(wave_data) { + wave_data->validateMarkers(ext_time_length); + } + return true; } diff --git a/rdadmin/add_feed.cpp b/rdadmin/add_feed.cpp index 823cff77..d3c44a70 100644 --- a/rdadmin/add_feed.cpp +++ b/rdadmin/add_feed.cpp @@ -2,7 +2,7 @@ // // Add a Rivendell RSS Feed // -// (C) Copyright 2002-2021 Fred Gleason +// (C) Copyright 2002-2024 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 @@ -29,17 +29,19 @@ #include "edit_feed.h" #include "globals.h" -AddFeed::AddFeed(unsigned *id,QString *keyname,QWidget *parent) +AddFeed::AddFeed(unsigned *id,QString *keyname,QStringList *usernames, + QWidget *parent) : RDDialog(parent) { feed_keyname=keyname; feed_id=id; + feed_usernames=usernames; // // Fix the Window Size // setMinimumSize(sizeHint()); - setMaximumSize(sizeHint()); + setMaximumHeight(sizeHint().height()); setWindowTitle("RDADmin - "+tr("Add RSS Feed")); @@ -62,13 +64,33 @@ AddFeed::AddFeed(unsigned *id,QString *keyname,QWidget *parent) feed_keyname_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); // - // Enable Users Checkbox + // Enable User Selector // - feed_users_box=new QCheckBox(this); - feed_users_box->setChecked(true); - feed_users_label= - new QLabel(tr("Enable Feed for All Users"),this); - feed_users_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + feed_usernames_groupbox=new QGroupBox(tr("Enable Users For Feed"),this); + + feed_usernames_group=new QButtonGroup(this); + connect(feed_usernames_group,SIGNAL(buttonToggled(QAbstractButton *,bool)), + this,SLOT(buttonToggledData(QAbstractButton *,bool))); + + feed_none_radio= + new QRadioButton(tr("No Users"),this); + feed_usernames_group->addButton(feed_none_radio); + + feed_all_radio= + new QRadioButton(tr("All Users"),this); + feed_usernames_group->addButton(feed_all_radio); + + feed_some_radio= + new QRadioButton(tr("Users from Feed")+":",this); + feed_usernames_group->addButton(feed_some_radio); + feed_keyname_box=new QComboBox(this); + feed_keyname_model=new RDFeedListModel(true,false,this); + feed_keyname_model->setPalette(palette()); + feed_keyname_model->setFont(font()); + feed_keyname_box->setModel(feed_keyname_model); + feed_some_radio->setDisabled(feed_keyname_model->rowCount()==0); + feed_none_radio->setChecked(true); + buttonToggledData(feed_usernames_group->checkedButton(),true); // // Ok Button @@ -98,7 +120,7 @@ AddFeed::~AddFeed() QSize AddFeed::sizeHint() const { - return QSize(290,123); + return QSize(310,205); } @@ -114,14 +136,43 @@ void AddFeed::keynameChangedData(const QString &str) } +void AddFeed::buttonToggledData(QAbstractButton *rbutton,bool checked) +{ + feed_keyname_box->setEnabled((rbutton==feed_some_radio)&&checked); +} + + void AddFeed::okData() { QString err_msg; + QString sql; + RDSqlQuery *q=NULL; - *feed_id=RDFeed::create(feed_keyname_edit->text(),feed_users_box->isChecked(), - &err_msg); + *feed_id=RDFeed::create(feed_keyname_edit->text(),false,&err_msg); if(*feed_id!=0) { *feed_keyname=feed_keyname_edit->text(); + if(feed_usernames_group->checkedButton()==feed_all_radio) { + sql=QString("select ")+ + "`LOGIN_NAME` "+ // 00 + "from `USERS` where "+ + "(`ADMIN_CONFIG_PRIV`='N')&&(ADMIN_RSS_PRIV='N')"; + q=new RDSqlQuery(sql); + while(q->next()) { + AuthorizeUser(*feed_keyname,q->value(0).toString()); + } + delete q; + } + if(feed_usernames_group->checkedButton()==feed_some_radio) { + sql=QString("select ")+ + "`USER_NAME` "+ // 00 + "from `FEED_PERMS` where "+ + "`KEY_NAME`='"+RDEscapeString(feed_keyname_box->currentText())+"'"; + q=new RDSqlQuery(sql); + while(q->next()) { + AuthorizeUser(*feed_keyname,q->value(0).toString()); + } + delete q; + } done(true); } else { @@ -139,11 +190,24 @@ void AddFeed::cancelData() void AddFeed::resizeEvent(QResizeEvent *e) { feed_keyname_label->setGeometry(10,11,120,19); - feed_keyname_edit->setGeometry(135,11,sizeHint().width()-140,19); - - feed_users_box->setGeometry(40,35,15,15); - feed_users_label->setGeometry(60,33,sizeHint().width()-60,19); + feed_keyname_edit->setGeometry(135,11,sizeHint().width()-145,19); + feed_usernames_groupbox->setGeometry(10,35,size().width()-20,97); + feed_none_radio->setGeometry(30,45,160,30); + feed_all_radio->setGeometry(30,70,160,30); + feed_some_radio->setGeometry(30,95,160,30); + feed_keyname_box->setGeometry(150,95,size().width()-170,30); + feed_ok_button->setGeometry(size().width()-180,size().height()-60,80,50); feed_cancel_button->setGeometry(size().width()-90,size().height()-60,80,50); } + + +void AddFeed::AuthorizeUser(const QString &keyname, + const QString &login_name) const +{ + QString sql=QString("insert into `FEED_PERMS` set ")+ + "`KEY_NAME`='"+RDEscapeString(keyname)+"',"+ + "`USER_NAME`='"+RDEscapeString(login_name)+"'"; + RDSqlQuery::apply(sql); +} diff --git a/rdadmin/add_feed.h b/rdadmin/add_feed.h index 01982546..62bf0685 100644 --- a/rdadmin/add_feed.h +++ b/rdadmin/add_feed.h @@ -2,7 +2,7 @@ // // Add a Rivendell Feed // -// (C) Copyright 2002-2020 Fred Gleason +// (C) Copyright 2002-2024 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 @@ -21,40 +21,53 @@ #ifndef ADD_FEED_H #define ADD_FEED_H -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include +#include +#include +#include #include +#include class AddFeed : public RDDialog { Q_OBJECT public: - AddFeed(unsigned *id,QString *keyname,QWidget *parent=0); + AddFeed(unsigned *id,QString *keyname,QStringList *usernames,QWidget *parent); ~AddFeed(); QSize sizeHint() const; QSizePolicy sizePolicy() const; private slots: void keynameChangedData(const QString &str); + void buttonToggledData(QAbstractButton *rbutton,bool checked); void okData(); void cancelData(); protected: void resizeEvent(QResizeEvent *e); - private: - QLabel *feed_keyname_label; - QLineEdit *feed_keyname_edit; - QCheckBox *feed_users_box; - QLabel *feed_users_label; - QPushButton *feed_ok_button; - QPushButton *feed_cancel_button; - QString *feed_keyname; - unsigned *feed_id; + private: + void AuthorizeUser(const QString &keyname,const QString &login_name) const; + QLabel *feed_keyname_label; + QLineEdit *feed_keyname_edit; + QGroupBox *feed_usernames_groupbox; + QButtonGroup *feed_usernames_group; + QRadioButton *feed_none_radio; + QRadioButton *feed_all_radio; + QRadioButton *feed_some_radio; + QComboBox *feed_keyname_box; + RDFeedListModel *feed_keyname_model; + QPushButton *feed_ok_button; + QPushButton *feed_cancel_button; + QString *feed_keyname; + unsigned *feed_id; + QStringList *feed_usernames; }; diff --git a/rdadmin/edit_replicator.cpp b/rdadmin/edit_replicator.cpp index d5251929..085f66bd 100644 --- a/rdadmin/edit_replicator.cpp +++ b/rdadmin/edit_replicator.cpp @@ -69,11 +69,22 @@ EditReplicator::EditReplicator(const QString &repl_name,QWidget *parent) repl_description_label->setGeometry(10,33,90,19); repl_description_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + // + // Replicator Program Code + // + repl_program_code_edit=new QLineEdit(this); + repl_program_code_edit->setGeometry(105,55,sizeHint().width()-115,19); + repl_program_code_edit->setMaxLength(191); + QLabel *repl_program_code_label=new QLabel(tr("Program Code")+":",this); + repl_program_code_label->setFont(labelFont()); + repl_program_code_label->setGeometry(0,55,100,19); + repl_program_code_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + // // Replicator Type // repl_type_box=new QComboBox(this); - repl_type_box->setGeometry(105,55,sizeHint().width()-115,19); + repl_type_box->setGeometry(105,77,sizeHint().width()-115,19); for(unsigned i=0;i<(int)RDReplicator::TypeLast;i++) { repl_type_box->insertItem(repl_type_box->count(), RDReplicator::typeString((RDReplicator::Type)i)); @@ -83,14 +94,14 @@ EditReplicator::EditReplicator(const QString &repl_name,QWidget *parent) } QLabel *repl_type_label=new QLabel(tr("Type:"),this); repl_type_label->setFont(labelFont()); - repl_type_label->setGeometry(10,55,90,19); + repl_type_label->setGeometry(10,77,90,19); repl_type_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); // // Host System // repl_station_box=new QComboBox(this); - repl_station_box->setGeometry(155,77,sizeHint().width()-165,19); + repl_station_box->setGeometry(155,99,sizeHint().width()-165,19); repl_station_model=new RDStationListModel(false,"",this); repl_station_model->setFont(defaultFont()); repl_station_model->setPalette(palette()); @@ -98,55 +109,55 @@ EditReplicator::EditReplicator(const QString &repl_name,QWidget *parent) repl_station_box->setCurrentText(repl_replicator->stationName()); QLabel *repl_station_label=new QLabel(tr("Host System:"),this); repl_station_label->setFont(labelFont()); - repl_station_label->setGeometry(10,77,140,19); + repl_station_label->setGeometry(10,99,140,19); repl_station_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); // // Upload Audio URL // repl_url_edit=new QLineEdit(this); - repl_url_edit->setGeometry(155,99,335,19); + repl_url_edit->setGeometry(155,121,335,19); repl_url_edit->setMaxLength(255); repl_url_label=new QLabel(tr("Audio Upload URL:"),this); repl_url_label->setFont(labelFont()); - repl_url_label->setGeometry(20,99,130,19); + repl_url_label->setGeometry(20,121,130,19); repl_url_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); // // Upload Username // repl_username_edit=new QLineEdit(this); - repl_username_edit->setGeometry(225,121,95,19); + repl_username_edit->setGeometry(225,143,95,19); repl_username_edit->setMaxLength(64); repl_username_label=new QLabel(tr("Username:"),this); repl_username_label->setFont(labelFont()); - repl_username_label->setGeometry(40,121,180,19); + repl_username_label->setGeometry(40,143,180,19); repl_username_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); // // Upload Password // repl_password_edit=new QLineEdit(this); - repl_password_edit->setGeometry(395,121,95,19); + repl_password_edit->setGeometry(395,143,95,19); repl_password_edit->setMaxLength(64); repl_password_edit->setEchoMode(QLineEdit::Password); repl_password_label=new QLabel(tr("Password:"),this); repl_password_label->setFont(labelFont()); - repl_password_label->setGeometry(320,121,70,19); + repl_password_label->setGeometry(320,143,70,19); repl_password_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); // // Audio Format // repl_format_edit=new QLineEdit(this); - repl_format_edit->setGeometry(155,143,285,20); + repl_format_edit->setGeometry(155,165,285,20); repl_format_edit->setReadOnly(true); repl_format_label=new QLabel(tr("Upload Format:"),this); repl_format_label->setFont(labelFont()); - repl_format_label->setGeometry(5,143,145,20); + repl_format_label->setGeometry(5,165,145,20); repl_format_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); repl_format_button=new QPushButton(this); - repl_format_button->setGeometry(450,142,40,24); + repl_format_button->setGeometry(450,164,40,24); repl_format_button->setFont(subButtonFont()); repl_format_button->setText(tr("Set")); connect(repl_format_button,SIGNAL(clicked()),this,SLOT(setFormatData())); @@ -155,11 +166,11 @@ EditReplicator::EditReplicator(const QString &repl_name,QWidget *parent) // Normalize Check Box // repl_normalize_box=new QCheckBox(this); - repl_normalize_box->setGeometry(155,167,15,15); + repl_normalize_box->setGeometry(155,189,15,15); repl_normalize_box->setChecked(true); repl_normalize_check_label=new QLabel(tr("Normalize"),this); repl_normalize_check_label->setFont(labelFont()); - repl_normalize_check_label->setGeometry(175,165,83,20); + repl_normalize_check_label->setGeometry(175,187,83,20); repl_normalize_check_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); connect(repl_normalize_box,SIGNAL(toggled(bool)), this,SLOT(normalizeCheckData(bool))); @@ -168,22 +179,22 @@ EditReplicator::EditReplicator(const QString &repl_name,QWidget *parent) // Normalize Level // repl_normalize_spin=new QSpinBox(this); - repl_normalize_spin->setGeometry(295,165,40,20); + repl_normalize_spin->setGeometry(295,187,40,20); repl_normalize_spin->setRange(-30,-1); repl_normalize_label=new QLabel(tr("Level:"),this); repl_normalize_label->setFont(labelFont()); - repl_normalize_label->setGeometry(245,165,45,20); + repl_normalize_label->setGeometry(245,187,45,20); repl_normalize_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); repl_normalize_unit_label=new QLabel(tr("dBFS"),this); repl_normalize_unit_label->setFont(labelFont()); - repl_normalize_unit_label->setGeometry(340,165,40,20); + repl_normalize_unit_label->setGeometry(340,187,40,20); repl_normalize_unit_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); // // Groups Selector // repl_groups_sel=new RDListSelector(this); - repl_groups_sel->setGeometry(60,192,380,130); + repl_groups_sel->setGeometry(60,214,380,130); repl_groups_sel->sourceSetLabel(tr("Available Groups")); repl_groups_sel->destSetLabel(tr("Active Groups")); @@ -212,6 +223,7 @@ EditReplicator::EditReplicator(const QString &repl_name,QWidget *parent) // repl_name_edit->setText(repl_replicator->name()); repl_description_edit->setText(repl_replicator->description()); + repl_program_code_edit->setText(repl_replicator->programCode()); repl_url_edit->setText(repl_replicator->url()); repl_username_edit->setText(repl_replicator->urlUsername()); repl_password_edit->setText(repl_replicator->urlPassword()); @@ -290,6 +302,7 @@ void EditReplicator::okData() RDSqlQuery *q; repl_replicator->setDescription(repl_description_edit->text()); + repl_replicator->setProgramCode(repl_program_code_edit->text()); repl_replicator->setType((RDReplicator::Type)repl_type_box->currentIndex()); repl_replicator->setStationName(repl_station_box->currentText()); repl_replicator->setUrl(repl_url_edit->text()); diff --git a/rdadmin/edit_replicator.h b/rdadmin/edit_replicator.h index 79d0ba89..9822e932 100644 --- a/rdadmin/edit_replicator.h +++ b/rdadmin/edit_replicator.h @@ -2,7 +2,7 @@ // // Edit a Rivendell Replicator // -// (C) Copyright 2002-2019 Fred Gleason +// (C) Copyright 2002-2024 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 @@ -21,12 +21,12 @@ #ifndef EDIT_REPLICATOR_H #define EDIT_REPLICATOR_H -#include -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include @@ -54,6 +54,7 @@ class EditReplicator : public RDDialog RDReplicator *repl_replicator; QLineEdit *repl_name_edit; QLineEdit *repl_description_edit; + QLineEdit *repl_program_code_edit; QComboBox *repl_type_box; QComboBox *repl_station_box; RDStationListModel *repl_station_model; diff --git a/rdadmin/list_feeds.cpp b/rdadmin/list_feeds.cpp index d8c613fe..a79107d5 100644 --- a/rdadmin/list_feeds.cpp +++ b/rdadmin/list_feeds.cpp @@ -2,7 +2,7 @@ // // List Rivendell Feeds // -// (C) Copyright 2002-2023 Fred Gleason +// (C) Copyright 2002-2024 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 @@ -144,9 +144,10 @@ void ListFeeds::addData() { QString feed; unsigned id; + QStringList usernames; QString sql; - AddFeed *ad=new AddFeed(&id,&feed,this); + AddFeed *ad=new AddFeed(&id,&feed,&usernames,this); if(ad->exec()) { EditFeed *d=new EditFeed(feed,this); if(d->exec()) { @@ -168,8 +169,6 @@ void ListFeeds::addData() sql=QString("delete from `FEEDS` where ")+ "`KEY_NAME`='"+RDEscapeString(feed)+"'"; RDSqlQuery::apply(sql); - - return; } delete d; } diff --git a/rdadmin/test_import.cpp b/rdadmin/test_import.cpp index 44ae3c70..233378c5 100644 --- a/rdadmin/test_import.cpp +++ b/rdadmin/test_import.cpp @@ -172,8 +172,8 @@ void TestImport::importData() QString sql=QString("delete from `IMPORTER_LINES` where ")+ "`STATION_NAME`='"+RDEscapeString(rda->station()->name())+"' && "+ QString::asprintf("`PROCESS_ID`=%u",getpid()); - printf("IMPORTER_LINES cleanup SQL: %s\n",sql.toUtf8().constData()); - // RDSqlQuery::apply(sql); + // printf("IMPORTER_LINES cleanup SQL: %s\n",sql.toUtf8().constData()); + RDSqlQuery::apply(sql); } diff --git a/rdairplay/Makefile.am b/rdairplay/Makefile.am index ebc76fa5..5c95c333 100644 --- a/rdairplay/Makefile.am +++ b/rdairplay/Makefile.am @@ -2,7 +2,7 @@ ## ## Automake.am for rivendell/rdairplay ## -## (C) 2002-2023 Fred Gleason +## (C) 2002-2024 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 @@ -48,6 +48,7 @@ dist_rdairplay_SOURCES = button_log.cpp button_log.h\ local_macros.cpp colors.h\ loglinebox.cpp loglinebox.h\ logtableview.cpp logtableview.h\ + messagewidget.cpp messagewidget.h\ mode_display.cpp mode_display.h\ pie_counter.cpp pie_counter.h\ post_counter.cpp post_counter.h\ @@ -68,6 +69,7 @@ nodist_rdairplay_SOURCES = moc_button_log.cpp\ moc_list_logs.cpp\ moc_loglinebox.cpp\ moc_logtableview.cpp\ + moc_messagewidget.cpp\ moc_mode_display.cpp\ moc_pie_counter.cpp\ moc_post_counter.cpp\ diff --git a/rdairplay/edit_event.cpp b/rdairplay/edit_event.cpp index 78f82381..b3c39e3c 100644 --- a/rdairplay/edit_event.cpp +++ b/rdairplay/edit_event.cpp @@ -191,6 +191,7 @@ int EditEvent::exec(int line) edit_grace_bgroup->button(2)->setChecked(true); graceClickedData(2); edit_grace_edit->setTime(QTime(0,0,0).addMSecs(edit_logline->graceTime())); + edit_grace_edit->setLength(edit_logline->graceTime()); break; } edit_transtype_box->setCurrentIndex((int)edit_logline->transType()); @@ -389,8 +390,7 @@ void EditEvent::okData() break; case 2: - edit_logline-> - setGraceTime(QTime(0,0,0).msecsTo(edit_grace_edit->time())); + edit_logline->setGraceTime(edit_grace_edit->length()); break; } } diff --git a/rdairplay/local_macros.cpp b/rdairplay/local_macros.cpp index d7ad8a92..8679734b 100644 --- a/rdairplay/local_macros.cpp +++ b/rdairplay/local_macros.cpp @@ -2,7 +2,7 @@ // // Local RML Macros for the Rivendell's RDAirPlay // -// (C) Copyright 2002-2022 Fred Gleason +// (C) Copyright 2002-2024 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 @@ -58,13 +58,7 @@ void MainWidget::RunLocalMacros(RDMacro *rml) str+=(rml->arg(i)+" "); } str+=rml->arg(rml->argQuantity()-1); - pal=air_top_strip->messageWidget()->palette(); - pal.setColor(QPalette::Active,QPalette::Foreground,QColor(Qt::black)); - pal.setColor(QPalette::Inactive,QPalette::Foreground, - QColor(Qt::black)); - air_top_strip->messageWidget()->setPalette(pal); - air_top_strip->messageWidget()->setFont(MessageFont(str)); - air_top_strip->messageWidget()->setText(str); + air_top_strip->messageWidget()->setText(str,QColor(Qt::black)); } if(rml->echoRequested()) { rml->acknowledge(true); @@ -85,12 +79,7 @@ void MainWidget::RunLocalMacros(RDMacro *rml) str+=(rml->arg(i)+" "); } str+=rml->arg(rml->argQuantity()-1); - pal=air_top_strip->messageWidget()->palette(); - pal.setColor(QPalette::Active,QPalette::Foreground,color); - pal.setColor(QPalette::Inactive,QPalette::Foreground,color); - air_top_strip->messageWidget()->setPalette(pal); - air_top_strip->messageWidget()->setFont(MessageFont(str)); - air_top_strip->messageWidget()->setText(str); + air_top_strip->messageWidget()->setText(str,color); } if(rml->echoRequested()) { rml->acknowledge(true); @@ -98,6 +87,22 @@ void MainWidget::RunLocalMacros(RDMacro *rml) } break; + case RDMacro::LM: // Load Message Widget + if(rml->argQuantity()==0) { + air_top_strip->messageWidget()->clear(); + } + else { + for(int i=0;i<(rml->argQuantity());i++) { + str+=(rml->arg(i)+" "); + } + ok=air_top_strip->messageWidget()->setUrl(str.trimmed()); + } + if(rml->echoRequested()) { + rml->acknowledge(ok); + rda->ripc()->sendRml(rml); + } + break; + case RDMacro::LL: // Load Log if((rml->argQuantity()<1)||(rml->argQuantity()>3)) { if(rml->echoRequested()) { @@ -960,17 +965,6 @@ void MainWidget::RunLocalMacros(RDMacro *rml) } -QFont MainWidget::MessageFont(QString str) -{ - for(int i=(AIR_MESSAGE_FONT_QUANTITY-1);i>=0;i--) { - if(air_message_metrics[i]->width(str) +// +// 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 +#include +#include + +#include +#include + +#include "colors.h" +#include "messagewidget.h" + +MessageWidget::MessageWidget(QWidget *parent) + : QWidget(parent) +{ + setStyleSheet("background-color: "+ + QColor(LOGLINEBOX_BACKGROUND_COLOR).name()); + + // + // Generate Fonts + // + for(unsigned i=0;isetWordWrap(true); + d_label->setAlignment(Qt::AlignCenter); + d_view=new QWebView(this); + connect(d_view,SIGNAL(loadFinished(bool)), + this,SLOT(webLoadFinishedData(bool))); + d_view->hide(); + RDEventFilter *filter=new RDEventFilter(this); + filter->addFilter(QEvent::Enter); + filter->addFilter(QEvent::Leave); + filter->addFilter(QEvent::KeyPress); + filter->addFilter(QEvent::KeyRelease); + filter->addFilter(QEvent::MouseButtonPress); + filter->addFilter(QEvent::MouseButtonRelease); + filter->addFilter(QEvent::MouseButtonDblClick); + filter->addFilter(QEvent::MouseMove); + filter->addFilter(QEvent::Wheel); + d_view->installEventFilter(filter); + + // + // Refresh Timer + // + d_refresh_timer=new QTimer(this); + d_refresh_timer->setSingleShot(true); + connect(d_refresh_timer,SIGNAL(timeout()),this,SLOT(refreshData())); + + // + // Load Current Page + // + QString url=rda->airplayConf()->messageWidgetUrl(); + if(!url.isEmpty()) { + setUrl(url); + } +} + + +void MessageWidget::setText(const QString &str,const QColor &col) +{ + QPalette pal=d_label->palette(); + + pal.setColor(QPalette::Active,QPalette::Foreground,col); + pal.setColor(QPalette::Inactive,QPalette::Foreground,col); + d_label->setPalette(pal); + d_label->setFont(MessageFont(str)); + d_label->setText(str); + d_label->show(); + d_view->hide(); + + d_refresh_timer->stop(); +} + + +bool MessageWidget::setUrl(const QString &str) +{ + QUrl url(str); + if(!url.isValid()) { + setText(tr("invalid URL")+": "+str.toUtf8().constData(),Qt::black); + d_refresh_timer->stop(); + return false; + } + if((url.scheme().toLower()!="http")&& + (url.scheme().toLower()!="https")&& + (url.scheme().toLower()!="file")) { + setText(tr("unsupported URL scheme")+": "+str.toUtf8().constData(), + Qt::black); + d_refresh_timer->stop(); + return false; + } + d_view->load(url); + d_view->show(); + d_label->hide(); + + d_url=str; + rda->airplayConf()->setMessageWidgetUrl(str); + if(url.scheme().toLower()=="file") { + d_refresh_timer->start(1000); + } + else { + d_refresh_timer->stop(); + } + + return true; +} + + +void MessageWidget::clear() +{ + d_label->clear(); + d_label->show(); + d_view->hide(); + d_refresh_timer->stop(); + + rda->airplayConf()->setMessageWidgetUrl(QString()); +} + + +void MessageWidget::webLoadFinishedData(bool state) +{ + d_view->page()->mainFrame()-> + setScrollBarPolicy(Qt::Horizontal,Qt::ScrollBarAlwaysOff); + d_view->page()->mainFrame()-> + setScrollBarPolicy(Qt::Vertical,Qt::ScrollBarAlwaysOff); +} + + +void MessageWidget::refreshData() +{ + d_view->load(d_url); + d_refresh_timer->start(1000); +} + + +void MessageWidget::resizeEvent(QResizeEvent *e) +{ + d_label->setGeometry(0,0,size().width(),size().height()); + d_view->setGeometry(0,0,size().width(),size().height()); +} + + +QFont MessageWidget::MessageFont(QString str) const +{ + for(int i=(MESSAGE_FONT_QUANTITY-1);i>=0;i--) { + if(d_message_metrics[i]->width(str) +// +// 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. +// + +#ifndef MESSAGEWIDGET_H +#define MESSAGEWIDGET_H + +#include +#include +#include + +#define MESSAGE_FONT_QUANTITY 8 +#define MESSAGE_WIDGET_WIDTH 410 + +class MessageWidget : public QWidget +{ + Q_OBJECT + public: + MessageWidget(QWidget *parent=0); + void setText(const QString &str,const QColor &col); + bool setUrl(const QString &url); + void clear(); + + private slots: + void webLoadFinishedData(bool state); + void refreshData(); + + protected: + void resizeEvent(QResizeEvent *e); + + private: + QFont MessageFont(QString str) const; + QLabel *d_label; + QWebView *d_view; + QTimer *d_refresh_timer; + QFont d_message_fonts[MESSAGE_FONT_QUANTITY]; + QFontMetrics *d_message_metrics[MESSAGE_FONT_QUANTITY]; + QString d_url; +}; + +#endif // MESSAGEWIDGET_H diff --git a/rdairplay/mode_display.cpp b/rdairplay/mode_display.cpp index 2bb63b8d..4a42c918 100644 --- a/rdairplay/mode_display.cpp +++ b/rdairplay/mode_display.cpp @@ -26,6 +26,8 @@ ModeDisplay::ModeDisplay(QWidget *parent) : RDPushButton(parent) { + setFocusPolicy(Qt::NoFocus); + for(int i=0;i +// (C) Copyright 2002-2024 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 @@ -134,15 +134,6 @@ MainWidget::MainWidget(RDConfig *config,QWidget *parent) // srandom(QTime::currentTime().msec()); - // - // Generate Fonts - // - for(unsigned i=0;i +// (C) Copyright 2002-2024 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 @@ -42,11 +42,9 @@ #define AIR_LOG_PORTS 2 #define AIR_PANEL_PORTS 1 #define AIR_TOTAL_PORTS 3 -#define AIR_MESSAGE_FONT_QUANTITY 8 #define AIR_CHANNEL_LOCKOUT_INTERVAL 1000 #define METER_INTERVAL 20 #define MASTER_TIMER_INTERVAL 100 -#define MESSAGE_WIDGET_WIDTH 410 #define RDAIRPLAY_USAGE "[OPTIONS]\n" class MainWidget : public RDMainWindow @@ -99,7 +97,6 @@ class MainWidget : public RDMainWindow void SetLiveAssistMode(int mach); void SetActionMode(StartButton::Mode mode); bool GetPanel(QString str,RDAirPlayConf::PanelType *type,int *panel); - QFont MessageFont(QString str); bool AssertChannelLock(int dir,int card,int port); bool AssertChannelLock(int dir,int achan); int AudioChannel(int card,int port) const; @@ -150,8 +147,6 @@ class MainWidget : public RDMainWindow RDAirPlayConf::ExitCode rdairplay_previous_exit_code; QDateTime air_startup_datetime; QPixmap *air_refresh_pixmap; - QFont air_message_fonts[AIR_MESSAGE_FONT_QUANTITY]; - QFontMetrics *air_message_metrics[AIR_MESSAGE_FONT_QUANTITY]; int air_audio_channels[RDAirPlayConf::LastChannel]; int air_start_gpi_matrices[RDAirPlayConf::LastChannel]; int air_start_gpi_lines[RDAirPlayConf::LastChannel]; diff --git a/rdairplay/soundpanel.cpp b/rdairplay/soundpanel.cpp index 5c227579..6b5b9fa6 100644 --- a/rdairplay/soundpanel.cpp +++ b/rdairplay/soundpanel.cpp @@ -27,6 +27,8 @@ SoundPanel::SoundPanel(RDEventPlayer *player,RDCartDialog *cart_dialog, bool dump_panel_updates,QWidget *parent) : RDWidget(parent) { + setFocusPolicy(Qt::NoFocus); + d_panel= new RDSoundPanel(rda->airplayConf()->panels(RDAirPlayConf::StationPanel), rda->airplayConf()->panels(RDAirPlayConf::UserPanel), diff --git a/rdairplay/stop_counter.cpp b/rdairplay/stop_counter.cpp index 8a2b9789..d1e779fe 100644 --- a/rdairplay/stop_counter.cpp +++ b/rdairplay/stop_counter.cpp @@ -28,6 +28,8 @@ StopCounter::StopCounter(QWidget *parent) : RDPushButton(parent) { + setFocusPolicy(Qt::NoFocus); + stop_running=false; stop_text=tr("Next Stop [none]"); diff --git a/rdairplay/topstrip.cpp b/rdairplay/topstrip.cpp index 3af1d577..528bed25 100644 --- a/rdairplay/topstrip.cpp +++ b/rdairplay/topstrip.cpp @@ -2,7 +2,7 @@ // // Top row of indicator widgets for rdairplay(1) // -// (C) Copyright 2021 Fred Gleason +// (C) Copyright 2021-2024 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 @@ -18,6 +18,8 @@ // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // +#include + #include #include @@ -45,18 +47,10 @@ TopStrip::TopStrip(QWidget *parent) // Audio Meters // d_meter_widget=new RDMeterStrip(this); - // - // Message Display + // Message Widget // - d_message_widget=new QLabel(this); - d_message_widget->setStyleSheet("background-color: "+ - QColor(LOGLINEBOX_BACKGROUND_COLOR).name()); - d_message_widget->setWordWrap(true); - d_message_widget->setLineWidth(1); - d_message_widget->setMidLineWidth(1); - d_message_widget->setFrameStyle(QFrame::Box|QFrame::Raised); - d_message_widget->setAlignment(Qt::AlignCenter); + d_message_widget=new MessageWidget(this); // // Logo @@ -114,7 +108,7 @@ RDMeterStrip *TopStrip::meterWidget() } -QLabel *TopStrip::messageWidget() const +MessageWidget *TopStrip::messageWidget() const { return d_message_widget; } @@ -131,6 +125,8 @@ void TopStrip::setOnairFlag(bool state) void TopStrip::resizeEvent(QResizeEvent *e) { + int w=size().width(); + d_wall_clock_widget->setGeometry(10,5, d_wall_clock_widget->sizeHint().width(), d_wall_clock_widget->sizeHint().height()); @@ -148,10 +144,10 @@ void TopStrip::resizeEvent(QResizeEvent *e) d_message_widget->setGeometry(10+d_meter_widget->geometry().x()+ d_meter_widget->geometry().width(), - 5, - size().width()-(30+d_meter_widget->geometry().x()+d_meter_widget->geometry().width()+RD_RDAIRPLAY_LOGO_WIDTH), - 125); - d_logo->setGeometry(size().width()-RD_RDAIRPLAY_LOGO_WIDTH-10, + 5, + w-(30+d_meter_widget->geometry().x()+d_meter_widget->geometry().width()+RD_RDAIRPLAY_LOGO_WIDTH), + 125); + d_logo->setGeometry(w-RD_RDAIRPLAY_LOGO_WIDTH-10, 5, RD_RDAIRPLAY_LOGO_WIDTH, RD_RDAIRPLAY_LOGO_HEIGHT); diff --git a/rdairplay/topstrip.h b/rdairplay/topstrip.h index 4e86d1f4..a39362eb 100644 --- a/rdairplay/topstrip.h +++ b/rdairplay/topstrip.h @@ -2,7 +2,7 @@ // // Top row of indicator widgets for rdairplay(1) // -// (C) Copyright 2021 Fred Gleason +// (C) Copyright 2021-2024 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 @@ -22,10 +22,12 @@ #define TOPSTRIP_H #include +#include #include #include +#include "messagewidget.h" #include "mode_display.h" #include "wall_clock.h" @@ -40,8 +42,7 @@ class TopStrip : public RDWidget WallClock *wallClockWidget() const; ModeDisplay *modeDisplayWidget() const; RDMeterStrip *meterWidget(); - QLabel *messageWidget() const; - + MessageWidget *messageWidget() const; public slots: void setOnairFlag(bool state); @@ -50,10 +51,11 @@ class TopStrip : public RDWidget void paintEvent(QPaintEvent *e); private: + // QFont MessageFont(QString str) const; WallClock *d_wall_clock_widget; ModeDisplay *d_mode_display_widget; RDMeterStrip *d_meter_widget; - QLabel *d_message_widget; + MessageWidget *d_message_widget; QLabel *d_logo; bool d_onair_flag; }; diff --git a/rdairplay/voicetracker.cpp b/rdairplay/voicetracker.cpp index 8c5d91b3..98851d93 100644 --- a/rdairplay/voicetracker.cpp +++ b/rdairplay/voicetracker.cpp @@ -27,12 +27,22 @@ VoiceTracker::VoiceTracker(QWidget *parent) : RDWidget(parent) { d_tracker_widget=new RDTrackerWidget(&d_import_path,this); + if(rda->airplayConf()->barAction()==RDAirPlayConf::StartNext) { + d_tracker_widget->setFocusPolicy(Qt::NoFocus); + } + else { + d_tracker_widget->setFocusPolicy(Qt::StrongFocus); + } d_load_button=new QPushButton(tr("Load\nLog"),this); d_load_button->setFont(bigButtonFont()); + d_load_button->setFocusPolicy(Qt::NoFocus); + connect(d_load_button,SIGNAL(clicked()),this,SLOT(loadData())); connect(d_tracker_widget,SIGNAL(activeChanged(bool)), d_load_button,SLOT(setDisabled(bool))); + + setFocusPolicy(Qt::NoFocus); } diff --git a/rdairplay/wall_clock.cpp b/rdairplay/wall_clock.cpp index 5c76ee06..e0b66d59 100644 --- a/rdairplay/wall_clock.cpp +++ b/rdairplay/wall_clock.cpp @@ -29,6 +29,8 @@ WallClock::WallClock(QWidget *parent) : RDPushButton(parent) { + setFocusPolicy(Qt::NoFocus); + previous_time=QTime::currentTime(); show_date=true; check_sync=true; diff --git a/rdlibrary/edit_cart.cpp b/rdlibrary/edit_cart.cpp index ea502ee2..41a614c7 100644 --- a/rdlibrary/edit_cart.cpp +++ b/rdlibrary/edit_cart.cpp @@ -2,7 +2,7 @@ // // Edit a Rivendell Cart // -// (C) Copyright 2002-2022 Fred Gleason +// (C) Copyright 2002-2024 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 @@ -181,8 +181,9 @@ EditCart::EditCart(const QList &cartnums,QString *path,bool new_cart, // Cart Forced Length // rdcart_controls.forced_length_edit=new RDTimeEdit(this); - rdcart_controls.forced_length_edit->setGeometry(530,36,85,21); rdcart_controls.forced_length_edit->setShowTenths(true); + rdcart_controls.forced_length_edit->setMode(RDTimeEdit::LengthMode); + rdcart_controls.forced_length_edit->setGeometry(530,36,85,21); rdcart_forced_length_ledit=new QLineEdit(this); rdcart_forced_length_ledit->setGeometry(535,36,80,21); rdcart_forced_length_ledit->hide(); @@ -581,8 +582,7 @@ EditCart::EditCart(const QList &cartnums,QString *path,bool new_cart, rdcart_average_length_edit-> setText(RDGetTimeLength(rdcart_cart->averageLength())); } - rdcart_controls.forced_length_edit-> - setTime(QTime(0,0,0).addMSecs(rdcart_cart->forcedLength())); + rdcart_controls.forced_length_edit->setLength(rdcart_cart->forcedLength()); rdcart_forced_length_ledit-> setText(rdcart_controls.forced_length_edit->time().toString("hh:mm:ss")); rdcart_controls.title_edit->setText(rdcart_cart->title()); @@ -792,13 +792,12 @@ void EditCart::okData() rdcart_cart->calculateAverageLength(&rdcart_length_deviation); rdcart_cart->setLengthDeviation(rdcart_length_deviation); rdcart_cart->updateLength(rdcart_controls.enforce_length_box->isChecked(), - QTime(0,0,0).msecsTo(rdcart_controls. - forced_length_edit->time())); + rdcart_controls.forced_length_edit->length()); rdcart_cart-> setAverageLength(RDSetTimeLength(rdcart_average_length_edit->text())); if(rdcart_controls.enforce_length_box->isChecked()) { rdcart_cart-> - setForcedLength(QTime(0,0,0).msecsTo(rdcart_controls.forced_length_edit->time())); + setForcedLength(rdcart_controls.forced_length_edit->length()); rdcart_cart->setEnforceLength(true); } else { @@ -825,8 +824,6 @@ void EditCart::okData() rdcart_cart->setConductor(rdcart_controls.conductor_edit->text()); rdcart_cart->setComposer(rdcart_controls.composer_edit->text()); rdcart_cart->setUserDefined(rdcart_controls.user_defined_edit->text()); - // rdcart_cart-> - // setUsageCode((RDCart::UsageCode)rdcart_usage_box->currentIndex()); rdcart_cart-> setUsageCode((RDCart::UsageCode)rdcart_usage_box-> itemData(rdcart_usage_box->currentIndex()).toInt()); @@ -910,8 +907,7 @@ void EditCart::cancelData() rdcart_cart->setForcedLength(len); } rdcart_cart->updateLength(rdcart_controls.enforce_length_box->isChecked(), - QTime(0,0,0).msecsTo(rdcart_controls. - forced_length_edit->time())); + rdcart_controls.forced_length_edit->length()); } done(false); } @@ -923,8 +919,7 @@ void EditCart::forcedLengthData(bool state) rdcart_controls.forced_length_edit->setEnabled(state); if(state) { rdcart_controls.forced_length_edit-> - setTime(QTime(0,0,0). - addMSecs(RDSetTimeLength(rdcart_average_length_edit->text()))); + setLength(RDSetTimeLength(rdcart_average_length_edit->text())); } } @@ -958,8 +953,8 @@ void EditCart::closeEvent(QCloseEvent *e) bool EditCart::ValidateLengths() { - return rdcart_cart->validateLengths(QTime(0,0,0). - msecsTo(rdcart_controls.forced_length_edit->time())); + return rdcart_cart-> + validateLengths(rdcart_controls.forced_length_edit->length()); } diff --git a/rdlogedit/edit_log.cpp b/rdlogedit/edit_log.cpp index cc4abe10..4b05a920 100644 --- a/rdlogedit/edit_log.cpp +++ b/rdlogedit/edit_log.cpp @@ -239,6 +239,7 @@ EditLog::EditLog(QString *filter,QString *group,QString *schedcode, edit_log_model->setFont(defaultFont()); edit_log_model->setPalette(palette()); edit_log_view->setModel(edit_log_model); + edit_log_view->hideColumn(7); // Scheduled Time is redundant connect(edit_log_model, SIGNAL(dataChanged(const QModelIndex &,const QModelIndex &)), this,SLOT(dataChangedData(const QModelIndex &,const QModelIndex &))); diff --git a/rdlogmanager/edit_clock.cpp b/rdlogmanager/edit_clock.cpp index 004923fe..be899c1f 100644 --- a/rdlogmanager/edit_clock.cpp +++ b/rdlogmanager/edit_clock.cpp @@ -602,7 +602,7 @@ void EditClock::UpdateClock(int line) // // Title // - p->drawText((edit_clock_label->size().width()- + p->drawText((CLOCK_EDGE- edit_title_metrics->width(edit_clocks_model->clockName()))/2, 50,edit_clocks_model->clockName()); diff --git a/rdrepld/Makefile.am b/rdrepld/Makefile.am index b62353ff..3b2db0fa 100644 --- a/rdrepld/Makefile.am +++ b/rdrepld/Makefile.am @@ -1,6 +1,6 @@ ## Makefile.am ## -## (C) Copyright 2010-2023 Fred Gleason +## (C) Copyright 2010-2024 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 @@ -30,8 +30,11 @@ dist_rdrepld_SOURCES = rdrepld.cpp rdrepld.h \ replconfig.cpp replconfig.h\ replfactory.cpp replfactory.h\ citadelxds.cpp citadelxds.h\ - ww1ipump.cpp ww1ipump.h + ww1ipump.cpp ww1ipump.h\ + xdscue.cpp xdscue.h + nodist_rdrepld_SOURCES = moc_rdrepld.cpp + rdrepld_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @QT5_LIBS@ @MUSICBRAINZ_LIBS@ @IMAGEMAGICK_LIBS@ CLEANFILES = *~ moc_* diff --git a/rdrepld/rdrepld.cpp b/rdrepld/rdrepld.cpp index 58fffc5b..42baf89f 100644 --- a/rdrepld/rdrepld.cpp +++ b/rdrepld/rdrepld.cpp @@ -2,7 +2,7 @@ // // The Rivendell Replicator Daemon // -// (C) Copyright 2010-2023 Fred Gleason +// (C) Copyright 2010-2024 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 @@ -37,6 +37,7 @@ #include "citadelxds.h" #include "rdrepld.h" #include "ww1ipump.h" +#include "xdscue.h" void SigHandler(int signum) { @@ -216,7 +217,8 @@ void MainObject::LoadReplicators() "`URL_USERNAME`,"+ // 08 "`URL_PASSWORD`,"+ // 09 "`ENABLE_METADATA`,"+ // 10 - "`NORMALIZATION_LEVEL` "+ // 11 + "`NORMALIZATION_LEVEL`,"+ // 11 + "`PROGRAM_CODE` "+ // 12 "from `REPLICATORS` where "+ "`STATION_NAME`='"+RDEscapeString(rda->config()->stationName())+"'"; q=new RDSqlQuery(sql); @@ -235,6 +237,7 @@ void MainObject::LoadReplicators() setUrlPassword(QByteArray::fromBase64(q->value(9).toString().toUtf8())); config->setEnableMetadata(RDBool(q->value(10).toString())); config->setNormalizeLevel(q->value(11).toInt()); + config->setProgramCode(q->value(12).toString()); switch(config->type()) { case RDReplicator::TypeCitadelXds: repl_replicators.push_back(new CitadelXds(config)); @@ -244,6 +247,10 @@ void MainObject::LoadReplicators() repl_replicators.push_back(new Ww1Ipump(config)); break; + case RDReplicator::TypeXdsCue: + repl_replicators.push_back(new XdsCue(config)); + break; + case RDReplicator::TypeLast: break; } diff --git a/rdrepld/replconfig.cpp b/rdrepld/replconfig.cpp index 432a7c95..c8a706d2 100644 --- a/rdrepld/replconfig.cpp +++ b/rdrepld/replconfig.cpp @@ -64,6 +64,18 @@ void ReplConfig::setStationName(const QString &str) } +QString ReplConfig::programCode() const +{ + return repl_program_code; +} + + +void ReplConfig::setProgramCode(const QString &str) +{ + repl_program_code=str; +} + + QString ReplConfig::description() const { return repl_description; @@ -200,6 +212,7 @@ void ReplConfig::clear() { repl_name=""; repl_station_name=""; + repl_program_code=""; repl_description=""; repl_format=RDSettings::Pcm16; repl_channels=2; diff --git a/rdrepld/replconfig.h b/rdrepld/replconfig.h index 09c904f4..95d9b424 100644 --- a/rdrepld/replconfig.h +++ b/rdrepld/replconfig.h @@ -36,6 +36,8 @@ class ReplConfig void setName(const QString &str); QString stationName() const; void setStationName(const QString &str); + QString programCode() const; + void setProgramCode(const QString &str); QString description() const; void setDescription(const QString &str); RDSettings::Format format() const; @@ -64,6 +66,7 @@ class ReplConfig QString repl_name; RDReplicator::Type repl_type; QString repl_station_name; + QString repl_program_code; QString repl_description; RDSettings::Format repl_format; unsigned repl_channels; diff --git a/rdrepld/xdscue.cpp b/rdrepld/xdscue.cpp new file mode 100644 index 00000000..c0a702e5 --- /dev/null +++ b/rdrepld/xdscue.cpp @@ -0,0 +1,458 @@ +// xdscue.cpp +// +// Replicator implementation for X-Digital Cue Model Copy-splitting +// +// (C) Copyright 2010-2024 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 +// 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 +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xdscue.h" + +#define RD_MAX_CART_NUMBER 999999 + +XdsCue::XdsCue(ReplConfig *repl_config) + : ReplFactory(repl_config) +{ + QString sql; + RDSqlQuery *q; + + sql="select `LAST_ISCI_XREFERENCE` from `VERSION`"; + q=new RDSqlQuery(sql); + if(q->first()) { + xds_isci_datetime=q->value(0).toDateTime(); + } + delete q; +} + + +void XdsCue::startProcess() +{ + CheckIsciXreference(); + CheckCarts(); +} + + +bool XdsCue::processCart(const unsigned cartnum) +{ + QString sql; + RDSqlQuery *q; + bool ret=false; + + sql=QString("select ")+ + "`FILENAME` "+ // 00 + "from `ISCI_XREFERENCE` where "+ + QString::asprintf("(`CART_NUMBER`=%u)&&",cartnum)+ + "(`LATEST_DATE`>=now())&&"+ + "(`FILENAME` like '"+RDEscapeString(config()->programCode()+"_")+"%')"; + q=new RDSqlQuery(sql); + if(q->first()) { + ret=PostCut(RDCut::cutName(cartnum,1),q->value(0).toString()); + } + delete q; + + return ret; +} + + +void XdsCue::CheckIsciXreference() +{ + QString sql; + + QFileInfo *fi=new QFileInfo(rda->system()->isciXreferencePath()); + if(fi->exists()) { + if(fi->lastModified()>xds_isci_datetime) { + if(LoadIsciXreference(rda->system()->isciXreferencePath())) { + sql="update `VERSION` set `LAST_ISCI_XREFERENCE`=now()"; + RDSqlQuery::apply(sql); + xds_isci_datetime=QDateTime(QDate::currentDate(),QTime::currentTime()); + PurgeCuts(); + } + } + } + else { + rda->syslog(LOG_WARNING,"unable to load ISCI cross reference file \"%s\"", + (const char *)rda->system()->isciXreferencePath().toUtf8()); + } + delete fi; +} + + +bool XdsCue::LoadIsciXreference(const QString &filename) +{ + FILE *f=NULL; + char line[1024]; + QString sql; + RDSqlQuery *q; + RDStringList fields; + unsigned cartnum; + QStringList datelist; + QDate date; + bool ok=false; + unsigned linenum=3; + + if((f=fopen(filename.toUtf8(),"r"))==NULL) { + rda->syslog(LOG_WARNING, + "unable to load ISCI cross reference file \"%s\" [%s]", + (const char *)rda->system()->isciXreferencePath().toUtf8(), + strerror(errno)); + return false; + } + + // + // Purge Old Data + // + sql="delete from `ISCI_XREFERENCE`"; + q=new RDSqlQuery(sql); + delete q; + + // + // Skip Header + // + if(fgets(line,1024,f)==NULL) { + rda->syslog(LOG_WARNING,"fgets() error reading ISCI xreference data"); + } + if(fgets(line,1024,f)==NULL) { + rda->syslog(LOG_WARNING,"fgets() error reading ISCI xreference data"); + } + + // + // Load Records + // + while(fgets(line,1024,f)!=NULL) { + fields=fields.split(',',line,"\""); + if(fields.size()==9) { + for(int i=0;isyslog(LOG_WARNING,"invalid date in line %d of \"%s\"", + linenum,(const char *)filename.toUtf8()); + } + } + else { + rda->syslog(LOG_WARNING, + "invalid FILENAME field \"%s\" in line %d of \"%s\"", + (const char *)fields[8].toUtf8(),linenum, + (const char *)filename.toUtf8()); + } + } + else { + rda->syslog(LOG_WARNING,"invalid date in line %d of \"%s\"", + linenum,(const char *)filename.toUtf8()); + } + } + else { + rda->syslog(LOG_DEBUG, + "missing/invalid cart number in line %d of \"%s\"", + linenum,(const char *)filename.toUtf8()); + } + } + else { + rda->syslog(LOG_WARNING,"line %d malformed in \"%s\"", + linenum,(const char *)filename.toUtf8()); + } + linenum++; + } + + // + // Clean Up + // + rda->syslog(LOG_INFO,"loaded ISCI cross reference file \"%s\"", + (const char *)rda->system()->isciXreferencePath().toUtf8()); + fclose(f); + return true; +} + + +bool XdsCue::ValidateFilename(const QString &filename) +{ + bool ret=true; + + // + // List of illegal characters taken from 'Illegal Characters4.doc' + // from Citadel + // + ret=ret&&(filename.indexOf(" ")<0); + ret=ret&&(filename.indexOf("\"")<0); + ret=ret&&(filename.indexOf("%")<0); + ret=ret&&(filename.indexOf("*")<0); + ret=ret&&(filename.indexOf("+")<0); + ret=ret&&(filename.indexOf("/")<0); + ret=ret&&(filename.indexOf(":")<0); + ret=ret&&(filename.indexOf(";")<0); + ret=ret&&(filename.indexOf("<")<0); + ret=ret&&(filename.indexOf("=")<0); + ret=ret&&(filename.indexOf(">")<0); + ret=ret&&(filename.indexOf("?")<0); + ret=ret&&(filename.indexOf("@")<0); + ret=ret&&(filename.indexOf("[")<0); + ret=ret&&(filename.indexOf("\\")<0); + ret=ret&&(filename.indexOf("]")<0); + ret=ret&&(filename.indexOf("^")<0); + ret=ret&&(filename.indexOf("{")<0); + ret=ret&&(filename.indexOf("|")<0); + ret=ret&&(filename.indexOf("}")<0); + + return ret; +} + + +void XdsCue::CheckCarts() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + QString now=QDateTime(QDate::currentDate(),QTime::currentTime()).addDays(-6). + toString("yyyy-MM-dd hh:mm:ss"); + + // + // Generate Update List + // + sql=QString("select ")+ + "`CART_NUMBER`,"+ // 00 + "`FILENAME` "+ // 01 + "from `ISCI_XREFERENCE` where "+ + "(`LATEST_DATE`>=now())&&"+ + "(`FILENAME` like '"+RDEscapeString(config()->programCode()+"_")+"%')"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString("select `REPL_CART_STATE`.`ID` from ")+ + "`REPL_CART_STATE` left join `CUTS` "+ + "on `REPL_CART_STATE`.`CART_NUMBER`=`CUTS`.`CART_NUMBER` where "+ + "(`CUTS`.`ORIGIN_DATETIME`<`REPL_CART_STATE`.`ITEM_DATETIME`)&&"+ + "(`REPL_CART_STATE`.`REPLICATOR_NAME`='"+ + RDEscapeString(config()->name())+"')&&"+ + QString::asprintf("(`REPL_CART_STATE`.`CART_NUMBER`=%u)&&", + q->value(0).toUInt())+ + "(`REPL_CART_STATE`.`POSTED_FILENAME`='"+ + RDEscapeString(q->value(1).toString())+"')&&"+ + "(`REPL_CART_STATE`.`ITEM_DATETIME`>'"+RDEscapeString(now)+"')&&"+ + "(`REPL_CART_STATE`.`REPOST`='N')"; + q1=new RDSqlQuery(sql); + if(!q1->first()) { + if(PostCut(RDCut::cutName(q->value(0).toUInt(),1), + q->value(1).toString())) { + sql=QString("select `ID` from `REPL_CART_STATE` where ")+ + "(`REPLICATOR_NAME`='"+RDEscapeString(config()->name())+"')&&"+ + QString::asprintf("(`CART_NUMBER`=%u)&&",q->value(0).toUInt())+ + "(`POSTED_FILENAME`='"+RDEscapeString(q->value(1).toString())+"')"; + q2=new RDSqlQuery(sql); + if(q2->first()) { + sql=QString("update `REPL_CART_STATE` set ")+ + "`ITEM_DATETIME`=now(),"+ + "`REPOST`='N' where "+ + "(`REPLICATOR_NAME`='"+RDEscapeString(config()->name())+"')&&"+ + QString::asprintf("(`CART_NUMBER`=%u)&&",q->value(0).toUInt())+ + "(`POSTED_FILENAME`='"+RDEscapeString(q->value(1).toString())+"')"; + } + else { + sql=QString("insert into `REPL_CART_STATE` set ")+ + "`ITEM_DATETIME`=now(),"+ + "`REPOST`='N',"+ + "`REPLICATOR_NAME`='"+RDEscapeString(config()->name())+"',"+ + QString::asprintf("`CART_NUMBER`=%u,",q->value(0).toUInt())+ + "`POSTED_FILENAME`='"+RDEscapeString(q->value(1).toString())+"'"; + } + delete q2; + RDSqlQuery::apply(sql); + } + } + delete q1; + } + delete q; +} + + +bool XdsCue::PostCut(const QString &cutname,const QString &filename) +{ + // + // Export File + // + RDAudioConvert::ErrorCode conv_err; + RDUpload::ErrorCode upload_err; + float speed_ratio=1.0; + RDCut *cut=new RDCut(cutname); + if(!cut->exists()) { + delete cut; + return false; + } + if(cut->length()==0) { + delete cut; + return true; + } + RDCart *cart=new RDCart(cut->cartNumber()); + if(cart->enforceLength()) { + speed_ratio=(float)cut->length()/(float)cart->forcedLength(); + } + RDSettings *settings=new RDSettings(); + QString tempfile=RDTempDirectory::basePath()+"/"+filename; + RDAudioConvert *conv=new RDAudioConvert(); + conv->setSourceFile(RDCut::pathName(cutname)); + conv->setDestinationFile(tempfile); + conv->setRange(cut->startPoint(),cut->endPoint()); + conv->setSpeedRatio(speed_ratio); + settings->setFormat(config()->format()); + settings->setChannels(config()->channels()); + settings->setSampleRate(config()->sampleRate()); + settings->setBitRate(config()->bitRate()); + settings->setQuality(config()->quality()); + settings->setNormalizationLevel(config()->normalizeLevel()/1000); + conv->setDestinationSettings(settings); + delete cart; + delete cut; + switch(conv_err=conv->convert()) { + case RDAudioConvert::ErrorOk: + break; + + default: + rda->syslog(LOG_WARNING, + "XdsCue: audio conversion failed: %s, cutname: %s", + (const char *)RDAudioConvert::errorText(conv_err).toUtf8(), + (const char *)cutname.toUtf8()); + delete conv; + delete settings; + return false; + } + delete conv; + delete settings; + + // + // Upload File + // + QString err_msg; + RDUpload *upload=new RDUpload(rda->config()); + upload->setSourceFile(tempfile); + upload->setDestinationUrl(config()->url()+"/"+filename); + // + // FIXME: Finish implementing ssh(1) id keys! + // + switch(upload_err=upload->runUpload(config()->urlUsername(), + config()->urlPassword(),"",false,&err_msg, + rda->config()->logXloadDebugData())) { + case RDUpload::ErrorOk: + break; + + default: + rda->syslog(LOG_WARNING,"XdsCue: audio upload failed: %s", + err_msg.toUtf8().constData()); + unlink(tempfile.toUtf8()); + delete upload; + return false; + } + unlink(tempfile.toUtf8()); + delete upload; + rda->syslog(LOG_INFO,"XdsCue: uploaded cut %s to %s/%s", + cutname.toUtf8().constData(), + config()->url().toUtf8().constData(), + filename.toUtf8().constData()); + + return true; +} + + +void XdsCue::PurgeCuts() +{ + QString sql; + RDSqlQuery *q; + RDSqlQuery *q1; + RDSqlQuery *q2; + RDDelete *conv; + RDDelete::ErrorCode conv_err; + + sql=QString("select ")+ + "`ID`,"+ // 00 + "`POSTED_FILENAME` "+ // 01 + "from `REPL_CART_STATE` where "+ + "`REPLICATOR_NAME`='"+RDEscapeString(config()->name())+"'"; + q=new RDSqlQuery(sql); + while(q->next()) { + sql=QString("select `ID` from `ISCI_XREFERENCE` where ")+ + "`FILENAME`='"+RDEscapeString(q->value(1).toString())+"'"; + q1=new RDSqlQuery(sql); + if(!q1->first()) { + QString path=config()->url(); + if(path.right(1)!="/") { + path+="/"; + } + QUrl url(path+q->value(1).toString()); + conv=new RDDelete(rda->config()); + conv->setTargetUrl(url.toString()); + // + // FIXME: Finish implementing ssh(1) key support! + // + if((conv_err=conv->runDelete(config()->urlUsername(), + config()->urlPassword(),"",false, + rda->config()->logXloadDebugData()))== + RDDelete::ErrorOk) { + sql=QString::asprintf("delete from `REPL_CART_STATE` where `ID`=%d", + q->value(0).toInt()); + q2=new RDSqlQuery(sql); + delete q2; + rda->syslog(LOG_INFO,"purged \"%s\" for replicator \"%s\"", + (const char *)url.toString().toUtf8(), + (const char *)config()->name().toUtf8()); + } + else { + rda->syslog(LOG_WARNING, + "unable to delete \"%s\" for replicator \"%s\" [%s]", + (const char *)url.toString().toUtf8(), + (const char *)config()->name().toUtf8(), + (const char *)RDDelete::errorText(conv_err).toUtf8()); + } + delete conv; + } + delete q1; + } + delete q; +} diff --git a/rdrepld/xdscue.h b/rdrepld/xdscue.h new file mode 100644 index 00000000..50f37a09 --- /dev/null +++ b/rdrepld/xdscue.h @@ -0,0 +1,44 @@ +// xdscue.h +// +// Replicator implementation for X-Digital Cue Model Copy-splitting +// +// (C) Copyright 2010-2024 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 +// 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. +// + +#ifndef XDSCUE_H +#define XDSCUE_H + +#include "replfactory.h" + +class XdsCue : public ReplFactory +{ + public: + XdsCue(ReplConfig *repl_config); + void startProcess(); + bool processCart(const unsigned cartnum); + + private: + void CheckIsciXreference(); + bool LoadIsciXreference(const QString &filename); + bool ValidateFilename(const QString &filename); + void CheckCarts(); + bool PostCut(const QString &cutname,const QString &filename); + void PurgeCuts(); + QDateTime xds_isci_datetime; +}; + + +#endif // XDSCUE_H diff --git a/utils/rddbmgr/revertschema.cpp b/utils/rddbmgr/revertschema.cpp index e51645da..c6051223 100644 --- a/utils/rddbmgr/revertschema.cpp +++ b/utils/rddbmgr/revertschema.cpp @@ -2,7 +2,7 @@ // // Revert Rivendell DB schema // -// (C) Copyright 2018-2023 Fred Gleason +// (C) Copyright 2018-2024 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 @@ -40,6 +40,41 @@ bool MainObject::RevertSchema(int cur_schema,int set_schema,QString *err_msg) // NEW SCHEMA REVERSIONS GO HERE... + // + // Revert 374 + // + if((cur_schema == 374) && (set_schema < cur_schema)) + { + DropColumn("RDAIRPLAY","MESSAGE_WIDGET_URL"); + + WriteSchemaVersion(--cur_schema); + } + + // + // Revert 373 + // + if((cur_schema == 373) && (set_schema < cur_schema)) + { + sql=QString("alter table `AUDIO_CARDS` ")+ + "modify column `NAME` varchar(64)"; + if(!RDSqlQuery::apply(sql,err_msg)) { + return false; + } + + WriteSchemaVersion(--cur_schema); + } + + // + // Revert 372 + // + if((cur_schema == 372) && (set_schema < cur_schema)) + { + DropIndex("ISCI_XREFERENCE","FILENAME_IDX"); + DropColumn("REPLICATORS", "PROGRAM_CODE"); + + WriteSchemaVersion(--cur_schema); + } + // // Revert 371 // @@ -50,7 +85,6 @@ bool MainObject::RevertSchema(int cur_schema,int set_schema,QString *err_msg) WriteSchemaVersion(--cur_schema); } - // // Revert 370 // diff --git a/utils/rddbmgr/schemamap.cpp b/utils/rddbmgr/schemamap.cpp index fb993cc1..cab10f80 100644 --- a/utils/rddbmgr/schemamap.cpp +++ b/utils/rddbmgr/schemamap.cpp @@ -2,7 +2,7 @@ // // DB schema version <==> Rivendell version map // -// (C) Copyright 2018-2023 Fred Gleason +// (C) Copyright 2018-2024 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 @@ -162,6 +162,7 @@ void MainObject::InitializeSchemaMap() { global_version_map["3.6"]=347; global_version_map["4.0"]=370; global_version_map["4.1"]=371; + global_version_map["4.2"]=374; } diff --git a/utils/rddbmgr/updateschema.cpp b/utils/rddbmgr/updateschema.cpp index 740e9f32..8e4950af 100644 --- a/utils/rddbmgr/updateschema.cpp +++ b/utils/rddbmgr/updateschema.cpp @@ -2,7 +2,7 @@ // // Update Rivendell DB schema. // -// (C) Copyright 2018-2022 Fred Gleason +// (C) Copyright 2018-2024 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 @@ -11423,6 +11423,43 @@ bool MainObject::UpdateSchema(int cur_schema,int set_schema,QString *err_msg) WriteSchemaVersion(++cur_schema); } + if((cur_schema<372)&&(set_schema>cur_schema)) { + sql=QString("alter table `REPLICATORS` ")+ + "add column `PROGRAM_CODE` varchar(191) "+ + "after `STATION_NAME`"; + if(!RDSqlQuery::apply(sql,err_msg)) { + return false; + } + + sql=QString("create index `FILENAME_IDX` on ")+ + "`ISCI_XREFERENCE` (`FILENAME`)"; + if(!RDSqlQuery::apply(sql,err_msg)) { + return false; + } + + WriteSchemaVersion(++cur_schema); + } + + if((cur_schema<373)&&(set_schema>cur_schema)) { + sql=QString("alter table `AUDIO_CARDS` ")+ + "modify column `NAME` text"; + if(!RDSqlQuery::apply(sql,err_msg)) { + return false; + } + + WriteSchemaVersion(++cur_schema); + } + + if((cur_schema<374)&&(set_schema>cur_schema)) { + sql=QString("alter table `RDAIRPLAY` ")+ + "add column `MESSAGE_WIDGET_URL` text after `AUDITION_PREROLL`"; + if(!RDSqlQuery::apply(sql,err_msg)) { + return false; + } + + WriteSchemaVersion(++cur_schema); + } + // NEW SCHEMA UPDATES GO HERE... diff --git a/versions/PACKAGE_VERSION b/versions/PACKAGE_VERSION index cd9b8f55..09dc44b0 100644 --- a/versions/PACKAGE_VERSION +++ b/versions/PACKAGE_VERSION @@ -1 +1 @@ -4.1.2 \ No newline at end of file +4.1.3int1 \ No newline at end of file