diff --git a/ChangeLog b/ChangeLog index e00a04eb..5df36629 100644 --- a/ChangeLog +++ b/ChangeLog @@ -18918,8 +18918,125 @@ 2019-08-09 Fred Gleason * Refactored 'RDClock' to store events on the heap rather than on the stack. +2019-08-11 Fred Gleason + * Fixed a bug in the 'pypad.update.shouldBeProcessed()' method + that caused log selection directives to be ignored. + * Refactored the 'pypad_icecast2.py' script to work properly with + the fixed 'pypad.update.shouldBeProcessed()' method. + * Refactored the 'pypad_shoutcast2.py' script to work properly with + the fixed 'pypad.update.shouldBeProcessed()' method. 2019-08-12 Fred Gleason * Added 'py-compile' to the 'CLEANFILES' rule in 'Makefile.am'. +2019-08-14 Fred Gleason + * Refactored the 'pypad.Update.shouldBeProcessed()' method to be LBYL. +2019-08-20 Fred Gleason + * Added a 'DROPBOXES.LOG_TO_SYSLOG' field to the database. + * Incremented the database version to 309. + * Added a 'Log Events in Syslog' checkbox to the + 'Dropbox Configuration' dialog in rdadmin(1). + * Added special name logic to RDApplication to detect when a + dropbox is being started. + * Modified the '--log-filename=' switch in rdimport(1) to accept + both directory and filename components. + * Removed the '--log-directory=' switch from rdimport(1). + * Added an 'ID' column to the list of dropbox configurations in the + 'Rivendell Dropbox Configurations; dialog in rdadmin(1). +2019-08-21 Fred Gleason + * Added code to dump the parent query to STDERR when an invalid + 'RDSqlQuery::value()' is requested. +2019-08-21 Fred Gleason + * Refactored code to eliminate 'QSqlQuery::value: not positioned + on a valid record' errors when starting rdairplay(1). +2019-08-21 Fred Gleason + * Fixed a bug in rdairplay(1) where a hard time with a 'Make Next' + attribute would instead be treated as 'Start Immediately' if + the target event was unplayable. + * Fixed a bug in rdairplay(1) where a hard time with a 'Wait up to' + attribute would instead be treated as 'Start Immediately' if + the target event was unplayable. +2019-08-21 Fred Gleason + * Re-indented switch() statements in 'lib/rdlogplay.cpp'. +2019-08-24 Fred Gleason + * Refactored rdalsaconfig(8) to use ALSA device IDs rather than + ordinal numbers in asound.conf(5). +2019-08-26 Fred Gleason + * Updated rdalsaconfig(8) to include a 'rate ' line in + each asound.conf(5) entry. +2019-08-26 Fred Gleason + * Fixed a bug in rdalsaconfig(8) that caused a 'Service not + active' error to be generated at startup. +2019-08-26 Fred Gleason + * Reimplemented the '--asoundrc-file=' directive in + rdalsaconfig(8). +2019-08-26 Fred Gleason + * Reimplemented the '--manage-daemons' directive in + rdalsaconfig(8). +2019-08-26 Fred Gleason + * Reimplemented the '--autogen' directive in rdalsaconfig(8). + * Added a '--rewrite' directive in rdalsaconfig(8). +2019-08-26 Fred Gleason + * Added an rdalsaconfig(1) man page. +2019-08-26 Fred Gleason + * Fixed a regression in caed(8) that broke timescaling support. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_ando.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_filewrite.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_inno713.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in rdadmin(1) that allowed more than one PyPAD + instance to be selected at a time in the 'List PyPAD Instances' + dialog. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_liqcomp.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_live365.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_serial.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_spinitron.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_spottrap.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_tunein.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_udp.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_urlwrite.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_walltime.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_xds.py' PyPAD script that caused + an infinite loop. +2019-08-26 Fred Gleason + * Fixed a bug in the 'pypad_xmpad.py' PyPAD script that caused + an infinite loop. +2019-08-28 Fred Gleason + * Added a statement to explicitly disable sorting of the + events list in the 'List Clocks' dialog in rdlogmanager(1). +2019-08-28 Fred Gleason + * Fixed a bug in rdlogmanager(1) that threw a segfault when + adding an event to the end of the event list in the 'Edit + Clock' dialog. +2019-08-28 Fred Gleason + * Refactored the 'RDClock::insert()' method to calculate the + ordinal position of the inserted event automatically. + * Fixed a bug in rdlogmanager(1) that caused newly added events + to be incorrectly sorted in the event list in the 'Edit Clock' + dialog. 2019-08-29 Patrick Linstruth * Modified caed(8) to skip JACK startup, rather than crash, if no command line is specified in rdadmin(1). diff --git a/apis/pypad/api/pypad.py b/apis/pypad/api/pypad.py index 220e1175..b1684423 100644 --- a/apis/pypad/api/pypad.py +++ b/apis/pypad/api/pypad.py @@ -84,7 +84,6 @@ PAD_TCP_PORT=34289 class Update(object): def __init__(self,pad_data,config,rd_config): self.__fields=pad_data - #print('PAD: '+str(self.__fields)) self.__config=config self.__rd_config=rd_config @@ -726,30 +725,46 @@ class Update(object): section - The '[
]' of the INI configuration from which to take the parameters. """ - try: - if self.__config.get(section,'ProcessNullUpdates')=='0': - return True - if self.__config.get(section,'ProcessNullUpdates')=='1': - return self.hasPadType(pypad.TYPE_NOW) - if self.__config.get(section,'ProcessNullUpdates')=='2': - return self.hasPadType(pypad.TYPE_NEXT) - if self.__config.get(section,'ProcessNullUpdates')=='3': - return self.hasPadType(pypad.TYPE_NOW) and self.hasPadType(pypad.TYPE_NEXT) - except configparser.NoOptionError: - return True + result=True + if self.__config.has_section(section): + if self.__config.has_option(section,'ProcessNullUpdates'): + if self.__config.get(section,'ProcessNullUpdates')=='0': + result=result and True + if self.__config.get(section,'ProcessNullUpdates')=='1': + result=result and self.hasPadType(pypad.TYPE_NOW) + if self.__config.get(section,'ProcessNullUpdates')=='2': + result=result and self.hasPadType(pypad.TYPE_NEXT) + if self.__config.get(section,'ProcessNullUpdates')=='3': + result=result and self.hasPadType(pypad.TYPE_NOW) and self.hasPadType(pypad.TYPE_NEXT) + else: + result=result and True + + log_dict={1: 'MasterLog',2: 'Aux1Log',3: 'Aux2Log', + 101: 'VLog101',102: 'VLog102',103: 'VLog103',104: 'VLog104', + 105: 'VLog105',106: 'VLog106',107: 'VLog107',108: 'VLog108', + 109: 'VLog109',110: 'VLog110',111: 'VLog111',112: 'VLog112', + 113: 'VLog113',114: 'VLog114',115: 'VLog115',116: 'VLog116', + 117: 'VLog117',118: 'VLog118',119: 'VLog119',120: 'VLog120'} + option=log_dict[self.machine()] + if self.__config.has_option(section,option): + if self.__config.get(section,option).lower()=='yes': + result=result and True + else: + if self.__config.get(section,option).lower()=='no': + result=result and False + else: + if self.__config.get(section,option).lower()=='onair': + result=result and self.onairFlag() + else: + result=result and False + else: + result=result and False + else: + result=result and False + #print('machine(): '+str(self.machine())) + #print('result: '+str(result)) + return result - log_dict={1: 'MasterLog',2: 'Aux1Log',3: 'Aux2Log', - 101: 'VLog101',102: 'VLog102',103: 'VLog103',104: 'VLog104', - 105: 'VLog105',106: 'VLog106',107: 'VLog107',108: 'VLog108', - 109: 'VLog109',110: 'VLog110',111: 'VLog111',112: 'VLog112', - 113: 'VLog113',114: 'VLog114',115: 'VLog115',116: 'VLog116', - 117: 'VLog117',118: 'VLog118',119: 'VLog119',120: 'VLog120'} - if self.__config.get(section,log_dict[self.machine()]).lower()=='yes': - return True - if self.__config.get(section,log_dict[self.machine()]).lower()=='no': - return False - if self.__config.get(section,log_dict[self.machine()]).lower()=='onair': - return self.onairFlag() def syslog(self,priority,msg): """ diff --git a/apis/pypad/scripts/pypad_ando.py b/apis/pypad/scripts/pypad_ando.py index ff5b077a..60096ce9 100755 --- a/apis/pypad/scripts/pypad_ando.py +++ b/apis/pypad/scripts/pypad_ando.py @@ -32,14 +32,13 @@ def eprint(*args,**kwargs): def ProcessTimer(config): n=1 - while(True): + section='System'+str(n) + while(config.has_section(section)): + send_sock.sendto('HB'.encode('utf-8'), + (config.get(section,'IpAddress'),int(config.get(section,'UdpPort')))) + n=n+1 section='System'+str(n) - try: - send_sock.sendto('HB'.encode('utf-8'), - (config.get(section,'IpAddress'),int(config.get(section,'UdpPort')))) - n=n+1 - except configparser.NoSectionError: - return + return def ProcessPad(update): try: @@ -48,27 +47,25 @@ def ProcessPad(update): last_updates[update.machine()]=None n=1 - while(True): + section='System'+str(n) + while(update.config().has_section(section)): section='System'+str(n) - try: - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): - last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) - title=update.resolvePadFields(update.config().get(section,'Title'),pypad.ESCAPE_NONE) - artist=update.resolvePadFields(update.config().get(section,'Artist'),pypad.ESCAPE_NONE) - album=update.resolvePadFields(update.config().get(section,'Album'),pypad.ESCAPE_NONE) - label=update.resolvePadFields(update.config().get(section,'Label'),pypad.ESCAPE_NONE) - secs=update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH) - duration=('%02d:' % (secs//60000))+('%02d' % ((secs%60000)//1000)) - group=update.padField(pypad.TYPE_NOW,pypad.FIELD_GROUP_NAME) - if update.config().get(section,'Label')=='': - msg='^'+artist+'~'+title+'~'+duration+'~'+group+'~'+album+'~'+str(update.padField(pypad.TYPE_NOW,pypad.FIELD_CART_NUMBER))+'|' - else: - msg='^'+artist+'~'+title+'~'+duration+'~'+group+'~'+str(update.padField(pypad.TYPE_NOW,pypad.FIELD_CART_NUMBER))+'~'+album+'~'+label+'|' - send_sock.sendto(msg.encode('utf-8'), - (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) - n=n+1 - except configparser.NoSectionError: - return + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): + last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) + title=update.resolvePadFields(update.config().get(section,'Title'),pypad.ESCAPE_NONE) + artist=update.resolvePadFields(update.config().get(section,'Artist'),pypad.ESCAPE_NONE) + album=update.resolvePadFields(update.config().get(section,'Album'),pypad.ESCAPE_NONE) + label=update.resolvePadFields(update.config().get(section,'Label'),pypad.ESCAPE_NONE) + secs=update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH) + duration=('%02d:' % (secs//60000))+('%02d' % ((secs%60000)//1000)) + group=update.padField(pypad.TYPE_NOW,pypad.FIELD_GROUP_NAME) + if update.config().get(section,'Label')=='': + msg='^'+artist+'~'+title+'~'+duration+'~'+group+'~'+album+'~'+str(update.padField(pypad.TYPE_NOW,pypad.FIELD_CART_NUMBER))+'|' + else: + msg='^'+artist+'~'+title+'~'+duration+'~'+group+'~'+str(update.padField(pypad.TYPE_NOW,pypad.FIELD_CART_NUMBER))+'~'+album+'~'+label+'|' + send_sock.sendto(msg.encode('utf-8'), + (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) + n=n+1 # # 'Main' function diff --git a/apis/pypad/scripts/pypad_filewrite.py b/apis/pypad/scripts/pypad_filewrite.py index 764d9b70..ce657680 100755 --- a/apis/pypad/scripts/pypad_filewrite.py +++ b/apis/pypad/scripts/pypad_filewrite.py @@ -4,7 +4,7 @@ # # Write PAD updates to files # -# (C) Copyright 2018 Fred Gleason +# (C) Copyright 2018-2019 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,21 +29,19 @@ def eprint(*args,**kwargs): def ProcessPad(update): n=1 - try: - while(True): - section='File'+str(n) - if update.shouldBeProcessed(section): - fmtstr=update.config().get(section,'FormatString') - mode='w' - if update.config().get(section,'Append')=='1': - mode='a' - f=open(update.resolveFilepath(update.config().get(section,'Filename'),update.dateTime()),mode) - f.write(update.resolvePadFields(fmtstr,int(update.config().get(section,'Encoding')))) - f.close() - n=n+1 + section='File'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section): + fmtstr=update.config().get(section,'FormatString') + mode='w' + if update.config().get(section,'Append')=='1': + mode='a' + f=open(update.resolveFilepath(update.config().get(section,'Filename'),update.dateTime()),mode) + f.write(update.resolvePadFields(fmtstr,int(update.config().get(section,'Encoding')))) + f.close() + n=n+1 + section='File'+str(n) - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_icecast2.py b/apis/pypad/scripts/pypad_icecast2.py index 095436c6..390ed6d9 100755 --- a/apis/pypad/scripts/pypad_icecast2.py +++ b/apis/pypad/scripts/pypad_icecast2.py @@ -34,25 +34,37 @@ def ProcessPad(update): if update.hasPadType(pypad.TYPE_NOW): n=1 while(True): + # + # First, get all of our configuration values + # section='Icecast'+str(n) try: values={} values['mount']=update.config().get(section,'Mountpoint') values['song']=update.resolvePadFields(update.config().get(section,'FormatString'),pypad.ESCAPE_NONE) values['mode']='updinfo' - update.syslog(syslog.LOG_INFO,'Updating '+update.config().get(section,'Hostname')+': song='+values['song']) - url="http://%s:%s/admin/metadata" % (update.config().get(section,'Hostname'),update.config().get(section,'Tcpport')) - try: - response=requests.get(url,auth=HTTPBasicAuth(update.config().get(section,'Username'),update.config().get(section,'Password')),params=values) - response.raise_for_status() - except requests.exceptions.RequestException as e: - update.syslog(syslog.LOG_WARNING,str(e)) - n=n+1 + hostname=update.config().get(section,'Hostname') + tcpport=update.config().get(section,'Tcpport') + username=update.config().get(section,'Username') + password=update.config().get(section,'Password') + url="http://%s:%s/admin/metadata" % (hostname,tcpport) except configparser.NoSectionError: if(n==1): update.syslog(syslog.LOG_WARNING,'No icecast config found') return + # + # Now, send the update + # + if update.shouldBeProcessed(section): + try: + response=requests.get(url,auth=HTTPBasicAuth(username,password),params=values) + response.raise_for_status() + update.syslog(syslog.LOG_INFO,'Updating '+hostname+': song='+values['song']) + except requests.exceptions.RequestException as e: + update.syslog(syslog.LOG_WARNING,str(e)) + n=n+1 + # # Program Name # diff --git a/apis/pypad/scripts/pypad_inno713.py b/apis/pypad/scripts/pypad_inno713.py index 5698e876..3f8412cb 100755 --- a/apis/pypad/scripts/pypad_inno713.py +++ b/apis/pypad/scripts/pypad_inno713.py @@ -32,55 +32,52 @@ def eprint(*args,**kwargs): def ProcessPad(update): n=1 - while(True): + section='Rds'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW): + dps='' + if(len(update.config().get(section,'DynamicPsString'))!=0): + dps='DPS='+update.resolvePadFields(update.config().get(section,'DynamicPsString'),pypad.ESCAPE_NONE)+'\r\n' + ps='' + if(len(update.config().get(section,'PsString'))!=0): + ps='PS='+update.resolvePadFields(update.config().get(section,'PsString'),pypad.ESCAPE_NONE)+'\r\n' + text='' + if(len(update.config().get(section,'RadiotextString'))!=0): + text='TEXT='+update.resolvePadFields(update.config().get(section,'RadiotextString'),pypad.ESCAPE_NONE)+'\r\n' + if(update.config().has_option(section,'Device')): + # + # Use serial output + # + tty_dev=update.config().get(section,'Device') + speed=int(update.config().get(section,'Speed')) + parity=serial.PARITY_NONE + if int(update.config().get(section,'Parity'))==1: + parity=serial.PARITY_EVEN + if int(update.config().get(section,'Parity'))==2: + parity=serial.PARITY_ODD + bytesize=int(update.config().get(section,'WordSize')) + dev=serial.Serial(tty_dev,speed,parity=parity,bytesize=bytesize) + if(len(dps)!=0): + dev.write(dps.encode('utf-8')) + if(len(ps)!=0): + dev.write(ps.encode('utf-8')) + if(len(text)!=0): + dev.write(text.encode('utf-8')) + dev.close() + else: + # + # Use UDP output + # + ipaddr=update.config().get(section,'IpAddress') + port=int(update.config().get(section,'UdpPort')) + if(len(dps)!=0): + send_sock.sendto(dps.encode('utf-8'),(ipaddr,port)) + if(len(ps)!=0): + send_sock.sendto(ps.encode('utf-8'),(ipaddr,port)) + if(len(text)!=0): + send_sock.sendto(text.encode('utf-8'),(ipaddr,port)) + n=n+1 section='Rds'+str(n) - try: - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW): - dps='' - if(len(update.config().get(section,'DynamicPsString'))!=0): - dps='DPS='+update.resolvePadFields(update.config().get(section,'DynamicPsString'),pypad.ESCAPE_NONE)+'\r\n' - ps='' - if(len(update.config().get(section,'PsString'))!=0): - ps='PS='+update.resolvePadFields(update.config().get(section,'PsString'),pypad.ESCAPE_NONE)+'\r\n' - text='' - if(len(update.config().get(section,'RadiotextString'))!=0): - text='TEXT='+update.resolvePadFields(update.config().get(section,'RadiotextString'),pypad.ESCAPE_NONE)+'\r\n' - try: - # - # Use serial output - # - tty_dev=update.config().get(section,'Device') - speed=int(update.config().get(section,'Speed')) - parity=serial.PARITY_NONE - if int(update.config().get(section,'Parity'))==1: - parity=serial.PARITY_EVEN - if int(update.config().get(section,'Parity'))==2: - parity=serial.PARITY_ODD - bytesize=int(update.config().get(section,'WordSize')) - dev=serial.Serial(tty_dev,speed,parity=parity,bytesize=bytesize) - if(len(dps)!=0): - dev.write(dps.encode('utf-8')) - if(len(ps)!=0): - dev.write(ps.encode('utf-8')) - if(len(text)!=0): - dev.write(text.encode('utf-8')) - dev.close() - - except configparser.NoOptionError: - # - # Use UDP output - # - ipaddr=update.config().get(section,'IpAddress') - port=int(update.config().get(section,'UdpPort')) - if(len(dps)!=0): - send_sock.sendto(dps.encode('utf-8'),(ipaddr,port)) - if(len(ps)!=0): - send_sock.sendto(ps.encode('utf-8'),(ipaddr,port)) - if(len(text)!=0): - send_sock.sendto(text.encode('utf-8'),(ipaddr,port)) - n=n+1 - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_liqcomp.py b/apis/pypad/scripts/pypad_liqcomp.py index 33ef4328..6e0f1825 100755 --- a/apis/pypad/scripts/pypad_liqcomp.py +++ b/apis/pypad/scripts/pypad_liqcomp.py @@ -37,23 +37,21 @@ def ProcessPad(update): last_updates[update.machine()]=None n=1 - while(True): + section='System'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): + last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) + title=update.resolvePadFields(update.config().get(section,'Title'),pypad.ESCAPE_NONE) + artist=update.resolvePadFields(update.config().get(section,'Artist'),pypad.ESCAPE_NONE) + album=update.resolvePadFields(update.config().get(section,'Album'),pypad.ESCAPE_NONE) + label=update.resolvePadFields(update.config().get(section,'Label'),pypad.ESCAPE_NONE) + secs=update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH) + group=update.padField(pypad.TYPE_NOW,pypad.FIELD_GROUP_NAME) + msg='|'+title+'|'+artist+'|'+str(update.padField(pypad.TYPE_NOW,pypad.FIELD_CART_NUMBER))+'|'+str(secs)+'|'+group+'|'+album+'|'+label+'|\n' + send_sock.sendto(msg.encode('utf-8'), + (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) + n=n+1 section='System'+str(n) - try: - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): - last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) - title=update.resolvePadFields(update.config().get(section,'Title'),pypad.ESCAPE_NONE) - artist=update.resolvePadFields(update.config().get(section,'Artist'),pypad.ESCAPE_NONE) - album=update.resolvePadFields(update.config().get(section,'Album'),pypad.ESCAPE_NONE) - label=update.resolvePadFields(update.config().get(section,'Label'),pypad.ESCAPE_NONE) - secs=update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH) - group=update.padField(pypad.TYPE_NOW,pypad.FIELD_GROUP_NAME) - msg='|'+title+'|'+artist+'|'+str(update.padField(pypad.TYPE_NOW,pypad.FIELD_CART_NUMBER))+'|'+str(secs)+'|'+group+'|'+album+'|'+label+'|\n' - send_sock.sendto(msg.encode('utf-8'), - (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) - n=n+1 - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_live365.py b/apis/pypad/scripts/pypad_live365.py index c154a26e..78d75beb 100755 --- a/apis/pypad/scripts/pypad_live365.py +++ b/apis/pypad/scripts/pypad_live365.py @@ -32,34 +32,32 @@ def eprint(*args,**kwargs): def ProcessPad(update): n=1 - try: - while(True): - section='Station'+str(n) - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW): - member=update.escape(update.config().get(section,'MemberName'),pypad.ESCAPE_URL) - password=update.escape(update.config().get(section,'Password'),pypad.ESCAPE_URL) - title=update.resolvePadFields(update.config().get(section,'TitleString'),pypad.ESCAPE_URL) - artist=update.resolvePadFields(update.config().get(section,'ArtistString'),pypad.ESCAPE_URL) - album=update.resolvePadFields(update.config().get(section,'AlbumString'),pypad.ESCAPE_URL) - seconds=str(update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH)//1000) - buf=BytesIO() - curl=pycurl.Curl() - url='http://www.live365.com/cgi-bin/add_song.cgi?member_name='+member+'&password='+password+'&version=2&filename=Rivendell&seconds='+seconds+'&title='+title+'&artist='+artist+'&album='+album - curl.setopt(curl.URL,url) - curl.setopt(curl.WRITEDATA,buf) - curl.setopt(curl.FOLLOWLOCATION,True) - try: - curl.perform() - code=curl.getinfo(pycurl.RESPONSE_CODE) - if (code<200) or (code>=300): - update.syslog(syslog.LOG_WARNING,'['+section+'] returned response code '+str(code)) - except pycurl.error: - update.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr()) - curl.close() - n=n+1 + section='Station'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW): + member=update.escape(update.config().get(section,'MemberName'),pypad.ESCAPE_URL) + password=update.escape(update.config().get(section,'Password'),pypad.ESCAPE_URL) + title=update.resolvePadFields(update.config().get(section,'TitleString'),pypad.ESCAPE_URL) + artist=update.resolvePadFields(update.config().get(section,'ArtistString'),pypad.ESCAPE_URL) + album=update.resolvePadFields(update.config().get(section,'AlbumString'),pypad.ESCAPE_URL) + seconds=str(update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH)//1000) + buf=BytesIO() + curl=pycurl.Curl() + url='http://www.live365.com/cgi-bin/add_song.cgi?member_name='+member+'&password='+password+'&version=2&filename=Rivendell&seconds='+seconds+'&title='+title+'&artist='+artist+'&album='+album + curl.setopt(curl.URL,url) + curl.setopt(curl.WRITEDATA,buf) + curl.setopt(curl.FOLLOWLOCATION,True) + try: + curl.perform() + code=curl.getinfo(pycurl.RESPONSE_CODE) + if (code<200) or (code>=300): + update.syslog(syslog.LOG_WARNING,'['+section+'] returned response code '+str(code)) + except pycurl.error: + update.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr()) + curl.close() + n=n+1 + section='Station'+str(n) - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_serial.py b/apis/pypad/scripts/pypad_serial.py index 71cca180..77f35808 100755 --- a/apis/pypad/scripts/pypad_serial.py +++ b/apis/pypad/scripts/pypad_serial.py @@ -32,27 +32,25 @@ def eprint(*args,**kwargs): def ProcessPad(update): n=1 - try: - while(True): - section='Serial'+str(n) - if update.shouldBeProcessed(section): - devname=update.config().get(section,'Device') - speed=int(update.config().get(section,'Speed')) - parity=serial.PARITY_NONE - if int(update.config().get(section,'Parity'))==1: - parity=serial.PARITY_EVEN - if int(update.config().get(section,'Parity'))==2: - parity=serial.PARITY_ODD - bytesize=int(update.config().get(section,'WordSize')) - dev=serial.Serial(devname,speed,parity=parity,bytesize=bytesize) - fmtstr=update.config().get(section,'FormatString') - esc=int(update.config().get(section,'Encoding')) - dev.write(update.resolvePadFields(fmtstr,esc).encode('utf-8')) - dev.close() - n=n+1 + section='Serial'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section): + devname=update.config().get(section,'Device') + speed=int(update.config().get(section,'Speed')) + parity=serial.PARITY_NONE + if int(update.config().get(section,'Parity'))==1: + parity=serial.PARITY_EVEN + if int(update.config().get(section,'Parity'))==2: + parity=serial.PARITY_ODD + bytesize=int(update.config().get(section,'WordSize')) + dev=serial.Serial(devname,speed,parity=parity,bytesize=bytesize) + fmtstr=update.config().get(section,'FormatString') + esc=int(update.config().get(section,'Encoding')) + dev.write(update.resolvePadFields(fmtstr,esc).encode('utf-8')) + dev.close() + n=n+1 + section='Serial'+str(n) - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_shoutcast1.py b/apis/pypad/scripts/pypad_shoutcast1.py index fa434d74..5d9fb1ba 100755 --- a/apis/pypad/scripts/pypad_shoutcast1.py +++ b/apis/pypad/scripts/pypad_shoutcast1.py @@ -27,23 +27,18 @@ import pycurl import pypad from io import BytesIO -last_updates={} - def eprint(*args,**kwargs): print(*args,file=sys.stderr,**kwargs) def ProcessPad(update): - try: - last_updates[update.machine()] - except KeyError: - last_updates[update.machine()]=None - - n=1 - try: + if update.hasPadType(pypad.TYPE_NOW): + n=1 while(True): + # + # First, get all of our configuration values + # section='Shoutcast'+str(n) - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): - last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) + try: song=update.resolvePadFields(update.config().get(section,'FormatString'),pypad.ESCAPE_URL) url='http://'+update.config().get(section,'Hostname')+':'+str(update.config().get(section,'Tcpport'))+'/admin.cgi?pass='+update.escape(update.config().get(section,'Password'),pypad.ESCAPE_URL)+'&mode=updinfo&song='+song curl=pycurl.Curl() @@ -55,6 +50,13 @@ def ProcessPad(update): # headers.append('User-Agent: '+'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.2) Gecko/20070219 Firefox/2.0.0.2') curl.setopt(curl.HTTPHEADER,headers); + except configparser.NoSectionError: + return + + # + # Now, send the update + # + if update.shouldBeProcessed(section): try: curl.perform() code=curl.getinfo(pycurl.RESPONSE_CODE) @@ -65,8 +67,6 @@ def ProcessPad(update): curl.close() n=n+1 - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_spinitron.py b/apis/pypad/scripts/pypad_spinitron.py index fa35b32e..fdb193bd 100755 --- a/apis/pypad/scripts/pypad_spinitron.py +++ b/apis/pypad/scripts/pypad_spinitron.py @@ -48,70 +48,68 @@ def ProcessPad(update): last_updates[update.machine()]=None n=1 - try: - while(True): - section='Spinitron'+str(n) - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): - last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) - title=update.resolvePadFields(update.config().get(section,'Title'),pypad.ESCAPE_JSON) - artist=update.resolvePadFields(update.config().get(section,'Artist'),pypad.ESCAPE_JSON) - album=update.resolvePadFields(update.config().get(section,'Album'),pypad.ESCAPE_JSON) - label=update.resolvePadFields(update.config().get(section,'Label'),pypad.ESCAPE_JSON) - composer=update.resolvePadFields(update.config().get(section,'Composer'),pypad.ESCAPE_JSON) - conductor=update.resolvePadFields(update.config().get(section,'Conductor'),pypad.ESCAPE_JSON) - notes=update.resolvePadFields(update.config().get(section,'Notes'),pypad.ESCAPE_JSON) + section='Spinitron'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): + last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) + title=update.resolvePadFields(update.config().get(section,'Title'),pypad.ESCAPE_JSON) + artist=update.resolvePadFields(update.config().get(section,'Artist'),pypad.ESCAPE_JSON) + album=update.resolvePadFields(update.config().get(section,'Album'),pypad.ESCAPE_JSON) + label=update.resolvePadFields(update.config().get(section,'Label'),pypad.ESCAPE_JSON) + composer=update.resolvePadFields(update.config().get(section,'Composer'),pypad.ESCAPE_JSON) + conductor=update.resolvePadFields(update.config().get(section,'Conductor'),pypad.ESCAPE_JSON) + notes=update.resolvePadFields(update.config().get(section,'Notes'),pypad.ESCAPE_JSON) - json='{\r\n' - pmode=update.config().get(section,'PlaylistMode') - if pmode=='Full': - json+=' "live": false\r\n' - if pmode=='Assist': - json+=' "live:" true\r\n' - if pmode=='Follow': - if update.mode()=='Automatic': - json+=' "live": false,\r\n' - else: - json+=' "live": true,\r\n' - duration=str(update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH)//1000) - year=update.padField(pypad.TYPE_NOW,pypad.FIELD_YEAR) - if year==None: - json+=' "released": null,\r\n' + json='{\r\n' + pmode=update.config().get(section,'PlaylistMode') + if pmode=='Full': + json+=' "live": false\r\n' + if pmode=='Assist': + json+=' "live:" true\r\n' + if pmode=='Follow': + if update.mode()=='Automatic': + json+=' "live": false,\r\n' else: - json+=' "released": '+str(year)+',\r\n' - json+=' "duration": '+duration+',\r\n' - json+=JsonField(update,'artist',artist) - json+=JsonField(update,'release',album) - json+=JsonField(update,'label',label) - json+=JsonField(update,'song',title) - json+=JsonField(update,'composer',composer) - json+=JsonField(update,'conductor',conductor) - json+=JsonField(update,'note',notes) - json+=JsonField(update,'isrc',update.padField(pypad.TYPE_NOW,pypad.FIELD_ISRC),True) - json+='}\r\n' - send_buf=BytesIO(json.encode('utf-8')) - recv_buf=BytesIO() - curl=pycurl.Curl() - curl.setopt(curl.URL,'https://spinitron.com/api/spins') - headers=[] - headers.append('Authorization: Bearer '+update.config().get(section,'APIKey')) - headers.append('Content-Type: application/json') - headers.append('Content-Length: '+str(len(json.encode('utf-8')))) - curl.setopt(curl.HTTPHEADER,headers); - curl.setopt(curl.POST,True) - curl.setopt(curl.READDATA,send_buf) - curl.setopt(curl.WRITEDATA,recv_buf) - try: - curl.perform() - code=curl.getinfo(pycurl.RESPONSE_CODE) - if (code<200) or (code>=300): - update.syslog(syslog.LOG_WARNING,'['+section+'] returned response code '+str(code)) - except pycurl.error: - update.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr()) - curl.close() - n=n+1 + json+=' "live": true,\r\n' + duration=str(update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH)//1000) + year=update.padField(pypad.TYPE_NOW,pypad.FIELD_YEAR) + if year==None: + json+=' "released": null,\r\n' + else: + json+=' "released": '+str(year)+',\r\n' + json+=' "duration": '+duration+',\r\n' + json+=JsonField(update,'artist',artist) + json+=JsonField(update,'release',album) + json+=JsonField(update,'label',label) + json+=JsonField(update,'song',title) + json+=JsonField(update,'composer',composer) + json+=JsonField(update,'conductor',conductor) + json+=JsonField(update,'note',notes) + json+=JsonField(update,'isrc',update.padField(pypad.TYPE_NOW,pypad.FIELD_ISRC),True) + json+='}\r\n' + send_buf=BytesIO(json.encode('utf-8')) + recv_buf=BytesIO() + curl=pycurl.Curl() + curl.setopt(curl.URL,'https://spinitron.com/api/spins') + headers=[] + headers.append('Authorization: Bearer '+update.config().get(section,'APIKey')) + headers.append('Content-Type: application/json') + headers.append('Content-Length: '+str(len(json.encode('utf-8')))) + curl.setopt(curl.HTTPHEADER,headers); + curl.setopt(curl.POST,True) + curl.setopt(curl.READDATA,send_buf) + curl.setopt(curl.WRITEDATA,recv_buf) + try: + curl.perform() + code=curl.getinfo(pycurl.RESPONSE_CODE) + if (code<200) or (code>=300): + update.syslog(syslog.LOG_WARNING,'['+section+'] returned response code '+str(code)) + except pycurl.error: + update.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr()) + curl.close() + n=n+1 + section='Spinitron'+str(n) - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_spottrap.py b/apis/pypad/scripts/pypad_spottrap.py index d8331848..fee63eda 100755 --- a/apis/pypad/scripts/pypad_spottrap.py +++ b/apis/pypad/scripts/pypad_spottrap.py @@ -4,7 +4,7 @@ # # Output Now & Next data on the basis of Group and Length. # -# (C) Copyright 2018 Fred Gleason +# (C) Copyright 2018-2019 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 @@ -38,21 +38,20 @@ def ProcessPad(update): last_updates[update.machine()]=None n=1 - while(True): + section='Rule'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): + last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) + length=update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH) + if update.padField(pypad.TYPE_NOW,pypad.FIELD_GROUP_NAME)==update.config().get(section,'GroupName') and length>=int(update.config().get(section,'MinimumLength')) and length<=int(update.config().get(section,'MaximumLength')): + msg=update.resolvePadFields(update.config().get(section,'FormatString'),pypad.ESCAPE_NONE) + else: + msg=update.resolvePadFields(update.config().get(section,'DefaultFormatString'),pypad.ESCAPE_NONE) + send_sock.sendto(msg.encode('utf-8'), + (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) + n=n+1 section='Rule'+str(n) - try: - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and (last_updates[update.machine()] != update.startDateTimeString(pypad.TYPE_NOW)): - last_updates[update.machine()]=update.startDateTimeString(pypad.TYPE_NOW) - length=update.padField(pypad.TYPE_NOW,pypad.FIELD_LENGTH) - if update.padField(pypad.TYPE_NOW,pypad.FIELD_GROUP_NAME)==update.config().get(section,'GroupName') and length>=int(update.config().get(section,'MinimumLength')) and length<=int(update.config().get(section,'MaximumLength')): - msg=update.resolvePadFields(update.config().get(section,'FormatString'),pypad.ESCAPE_NONE) - else: - msg=update.resolvePadFields(update.config().get(section,'DefaultFormatString'),pypad.ESCAPE_NONE) - send_sock.sendto(msg.encode('utf-8'), - (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) - n=n+1 - except configparser.NoSectionError: - return + # # 'Main' function diff --git a/apis/pypad/scripts/pypad_tunein.py b/apis/pypad/scripts/pypad_tunein.py index 5ffef9df..3a7119d2 100755 --- a/apis/pypad/scripts/pypad_tunein.py +++ b/apis/pypad/scripts/pypad_tunein.py @@ -31,33 +31,31 @@ import configparser def ProcessPad(update): if update.hasPadType(pypad.TYPE_NOW): - n=1 - while(True): section='Station'+str(n) + n=1 + while(update.config().has_section(section)): + values={} + values['id']=update.config().get(section,'StationID') + values['partnerId']=update.config().get(section,'PartnerID') + values['partnerKey']=update.config().get(section,'PartnerKey') + values['title']=update.resolvePadFields(update.config().get(section,'TitleString'),pypad.ESCAPE_NONE) + values['artist']=update.resolvePadFields(update.config().get(section,'ArtistString'),pypad.ESCAPE_NONE) + values['album']=update.resolvePadFields(update.config().get(section,'AlbumString'),pypad.ESCAPE_NONE) + update.syslog(syslog.LOG_INFO,'Updating TuneIn: artist='+values['artist']+' title='+values['title']+' album='+values['album']) try: - values={} - values['id']=update.config().get(section,'StationID') - values['partnerId']=update.config().get(section,'PartnerID') - values['partnerKey']=update.config().get(section,'PartnerKey') - values['title']=update.resolvePadFields(update.config().get(section,'TitleString'),pypad.ESCAPE_NONE) - values['artist']=update.resolvePadFields(update.config().get(section,'ArtistString'),pypad.ESCAPE_NONE) - values['album']=update.resolvePadFields(update.config().get(section,'AlbumString'),pypad.ESCAPE_NONE) - update.syslog(syslog.LOG_INFO,'Updating TuneIn: artist='+values['artist']+' title='+values['title']+' album='+values['album']) - try: - response=requests.get('http://air.radiotime.com/Playing.ashx',params=values) - response.raise_for_status() - except requests.exceptions.RequestException as e: - update.syslog(syslog.LOG_WARNING,str(e)) - else: - xml=ET.fromstring(response.text) - status=xml.find('./head/status') - if(status.text!='200'): - update.syslog(syslog.LOG_WARNING,'Update Failed: '+xml.find('./head/fault').text) - n=n+1 - except configparser.NoSectionError: - if(n==1): - update.syslog(syslog.LOG_WARNING,'No station config found') - return + response=requests.get('http://air.radiotime.com/Playing.ashx',params=values) + response.raise_for_status() + except requests.exceptions.RequestException as e: + update.syslog(syslog.LOG_WARNING,str(e)) + else: + xml=ET.fromstring(response.text) + status=xml.find('./head/status') + if(status.text!='200'): + update.syslog(syslog.LOG_WARNING,'Update Failed: '+xml.find('./head/fault').text) + n=n+1 + section='Station'+str(n) + if(n==1): + update.syslog(syslog.LOG_WARNING,'No station config found') # # Program Name diff --git a/apis/pypad/scripts/pypad_udp.py b/apis/pypad/scripts/pypad_udp.py index a4cfc8d6..57aad168 100755 --- a/apis/pypad/scripts/pypad_udp.py +++ b/apis/pypad/scripts/pypad_udp.py @@ -4,7 +4,7 @@ # # Send PAD updates via UDP # -# (C) Copyright 2018 Fred Gleason +# (C) Copyright 2018-2019 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,16 +30,17 @@ def eprint(*args,**kwargs): def ProcessPad(update): n=1 - while(True): + section='Udp'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section): + fmtstr=update.config().get(section,'FormatString') + send_sock.sendto(update.resolvePadFields(fmtstr,int(update.config().get(section,'Encoding'))).encode('utf-8'), + (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) + n=n+1 section='Udp'+str(n) - try: - if update.shouldBeProcessed(section): - fmtstr=update.config().get(section,'FormatString') - send_sock.sendto(update.resolvePadFields(fmtstr,int(update.config().get(section,'Encoding'))).encode('utf-8'), - (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) - n=n+1 - except configparser.NoSectionError: - return + if(n==1): + update.syslog(syslog.LOG_WARNING,'No UDP config found') + # # 'Main' function diff --git a/apis/pypad/scripts/pypad_urlwrite.py b/apis/pypad/scripts/pypad_urlwrite.py index 30b3e845..56f6d6d1 100755 --- a/apis/pypad/scripts/pypad_urlwrite.py +++ b/apis/pypad/scripts/pypad_urlwrite.py @@ -32,27 +32,25 @@ def eprint(*args,**kwargs): def ProcessPad(update): n=1 - try: - while(True): - section='Url'+str(n) - if update.shouldBeProcessed(section): - fmtstr=update.config().get(section,'FormatString') - buf=BytesIO(update.resolvePadFields(fmtstr,int(update.config().get(section,'Encoding'))).encode('utf-8')) - curl=pycurl.Curl() - curl.setopt(curl.URL,update.resolveFilepath(update.config().get(section,'Url'),update.dateTime())) - curl.setopt(curl.USERNAME,update.config().get(section,'Username')) - curl.setopt(curl.PASSWORD,update.config().get(section,'Password')) - curl.setopt(curl.UPLOAD,True) - curl.setopt(curl.READDATA,buf) - try: - curl.perform() - except pycurl.error: - update.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr()) - curl.close() - n=n+1 + section='Url'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section): + fmtstr=update.config().get(section,'FormatString') + buf=BytesIO(update.resolvePadFields(fmtstr,int(update.config().get(section,'Encoding'))).encode('utf-8')) + curl=pycurl.Curl() + curl.setopt(curl.URL,update.resolveFilepath(update.config().get(section,'Url'),update.dateTime())) + curl.setopt(curl.USERNAME,update.config().get(section,'Username')) + curl.setopt(curl.PASSWORD,update.config().get(section,'Password')) + curl.setopt(curl.UPLOAD,True) + curl.setopt(curl.READDATA,buf) + try: + curl.perform() + except pycurl.error: + update.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr()) + curl.close() + n=n+1 + section='Url'+str(n) - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_walltime.py b/apis/pypad/scripts/pypad_walltime.py index e9ab191a..c4cea975 100755 --- a/apis/pypad/scripts/pypad_walltime.py +++ b/apis/pypad/scripts/pypad_walltime.py @@ -32,27 +32,25 @@ def eprint(*args,**kwargs): def ProcessPad(update): n=1 - try: - while(True): - section='Walltime'+str(n) - if update.shouldBeProcessed(section): - fmtstr=update.config().get(section,'FormatString') - buf=BytesIO(update.resolvePadFields(fmtstr,pypad.ESCAPE_NONE).encode('utf-8')) - curl=pycurl.Curl() - curl.setopt(curl.URL,'http://'+update.config().get(section,'IpAddress')+'/webwidget'); - curl.setopt(curl.USERNAME,'user') - curl.setopt(curl.PASSWORD,update.config().get(section,'Password')) - curl.setopt(curl.UPLOAD,True) - curl.setopt(curl.READDATA,buf) - try: - curl.perform() - except pycurl.error: - update.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr()) - curl.close() - n=n+1 + section='Walltime'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section): + fmtstr=update.config().get(section,'FormatString') + buf=BytesIO(update.resolvePadFields(fmtstr,pypad.ESCAPE_NONE).encode('utf-8')) + curl=pycurl.Curl() + curl.setopt(curl.URL,'http://'+update.config().get(section,'IpAddress')+'/webwidget'); + curl.setopt(curl.USERNAME,'user') + curl.setopt(curl.PASSWORD,update.config().get(section,'Password')) + curl.setopt(curl.UPLOAD,True) + curl.setopt(curl.READDATA,buf) + try: + curl.perform() + except pycurl.error: + update.syslog(syslog.LOG_WARNING,'['+section+'] failed: '+curl.errstr()) + curl.close() + n=n+1 + section='Walltime'+str(n) - except configparser.NoSectionError: - return # # 'Main' function diff --git a/apis/pypad/scripts/pypad_xds.py b/apis/pypad/scripts/pypad_xds.py index d6f3b990..0bfff149 100755 --- a/apis/pypad/scripts/pypad_xds.py +++ b/apis/pypad/scripts/pypad_xds.py @@ -4,7 +4,7 @@ # # Send CICs via UDP or serial # -# (C) Copyright 2018 Fred Gleason +# (C) Copyright 2018-2019 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 @@ -61,31 +61,30 @@ def FilterField(string): def ProcessPad(update): n=1 - while(True): - section='Udp'+str(n) - try: - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and update.hasService(): - packet='0:'+update.serviceProgramCode()+':'+update.config().get(section,'IsciPrefix')+FilterField(update.padField(pypad.TYPE_NOW,pypad.FIELD_EXTERNAL_EVENT_ID))+':*' - try: - # - # Use serial output - # - tty_dev=update.config().get(section,'TtyDevice') - speed=int(update.config().get(section,'TtySpeed')) - parity=serial.PARITY_NONE - dev=serial.Serial(tty_dev,speed,parity=parity,bytesize=8) - dev.write(packet.encode('utf-8')) - dev.close() + section='Udp'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW) and update.hasService(): + packet='0:'+update.serviceProgramCode()+':'+update.config().get(section,'IsciPrefix')+FilterField(update.padField(pypad.TYPE_NOW,pypad.FIELD_EXTERNAL_EVENT_ID))+':*' + try: + # + # Use serial output + # + tty_dev=update.config().get(section,'TtyDevice') + speed=int(update.config().get(section,'TtySpeed')) + parity=serial.PARITY_NONE + dev=serial.Serial(tty_dev,speed,parity=parity,bytesize=8) + dev.write(packet.encode('utf-8')) + dev.close() - except configparser.NoOptionError: - # - # Use UDP output - # - send_sock.sendto(packet.encode('utf-8'), + except configparser.NoOptionError: + # + # Use UDP output + # + send_sock.sendto(packet.encode('utf-8'), (update.config().get(section,'IpAddress'),int(update.config().get(section,'UdpPort')))) - n=n+1 - except configparser.NoSectionError: - return + n=n+1 + section='Udp'+str(n) + # # 'Main' function diff --git a/apis/pypad/scripts/pypad_xmpad.py b/apis/pypad/scripts/pypad_xmpad.py index 23837aa7..eb5a1dd2 100755 --- a/apis/pypad/scripts/pypad_xmpad.py +++ b/apis/pypad/scripts/pypad_xmpad.py @@ -149,24 +149,22 @@ def ProcessTimer(config): def ProcessPad(update): n=1 - try: - while(True): - section='Serial'+str(n) - if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW): - dev=OpenSerialDevice(update.config(),section) - b4=MakeB4(update,section) - a4=MakeA4(update,section) - a5=MakeA5(update,section) - dev.write(b4.encode('utf-8')) - dev.write(b4.encode('utf-8')) - dev.write(b4.encode('utf-8')) - dev.write(a4.encode('utf-8')) - dev.write(a5.encode('utf-8')) - dev.close() - n=n+1 + section='Serial'+str(n) + while(update.config().has_section(section)): + if update.shouldBeProcessed(section) and update.hasPadType(pypad.TYPE_NOW): + dev=OpenSerialDevice(update.config(),section) + b4=MakeB4(update,section) + a4=MakeA4(update,section) + a5=MakeA5(update,section) + dev.write(b4.encode('utf-8')) + dev.write(b4.encode('utf-8')) + dev.write(b4.encode('utf-8')) + dev.write(a4.encode('utf-8')) + dev.write(a5.encode('utf-8')) + dev.close() + n=n+1 + section='Serial'+str(n) - except configparser.NoSectionError: - return # # 'Main' function diff --git a/cae/cae.cpp b/cae/cae.cpp index b9a0821e..0a76506e 100644 --- a/cae/cae.cpp +++ b/cae/cae.cpp @@ -714,10 +714,10 @@ void MainObject::timescalingSupportData(int id,unsigned card) break; } if(state) { - cae_server->sendCommand(id,"TS +!"); + cae_server->sendCommand(id,QString().sprintf("TS %u +!",card)); } else { - cae_server->sendCommand(id,"TS -!"); + cae_server->sendCommand(id,QString().sprintf("TS %u -!",card)); } } diff --git a/docs/manpages/Makefile.am b/docs/manpages/Makefile.am index c63c847e..d015072b 100644 --- a/docs/manpages/Makefile.am +++ b/docs/manpages/Makefile.am @@ -32,6 +32,7 @@ xsltproc $(DOCBOOK_STYLESHEETS)/manpages/docbook.xsl $< all-local: rdairplay.1\ + rdalsaconfig.1\ rdclilogedit.1\ rdconvert.1\ rddbmgr.8\ @@ -45,6 +46,7 @@ all-local: rdairplay.1\ rdservice.8 man_MANS = rdairplay.1\ + rdalsaconfig.1\ rdclilogedit.1\ rdconvert.1\ rddbmgr.8\ @@ -59,6 +61,8 @@ man_MANS = rdairplay.1\ EXTRA_DIST = rdairplay.1\ rdairplay.xml\ + rdalsaconfig.1\ + rdalsaconfig.xml\ rdclilogedit.1\ rdclilogedit.xml\ rdconvert.1\ diff --git a/docs/manpages/rdalsaconfig.xml b/docs/manpages/rdalsaconfig.xml new file mode 100644 index 00000000..70d1fdd1 --- /dev/null +++ b/docs/manpages/rdalsaconfig.xml @@ -0,0 +1,106 @@ + + + + + rdalsaconfig + 1 + August 2019 + Linux Audio Manual + + + rdalsaconfig + + Utility for managing Rivendell ALSA configuration + + + + + + Fred + Gleason + fredg@paravelsystems.com + + Application Author + + + + + + + rdalsaconfig + options + + + + + Description + + When invoked with no options, + rdalsaconfig1 will + query the system for the list of available ALSA PCM devices and + display the results in a GUI applet, with the device(s) currently + configured for use by Rivendell highlighted. The user may select and/or + deselect devices for Rivendell and save the result. + + + + Options + + + + + + + + Load and save the Rivendell configuration file from + filename. Default value is + /etc/asound.conf. + + + + + + + + + + Generate and save a Rivendell configuration containing all + available ALSA PCM devices, then exit. This option is mutually + exclusive with the --rewrite option (see below). + + + + + + + + + + Restart the Rivendell service as necessary to make configuration + changes active (requires root permission). + + + + + + + + + + Load the current Rivendell configuration, save it back to the + same location, then exit (useful for upgrading an existing v2.x + configuration to the enhanced v3.x format). This option is mutually + exclusive with the --autogen option (see above). + + + + + + + + + diff --git a/docs/manpages/rdimport.xml b/docs/manpages/rdimport.xml index dde9d775..1e7ba9b4 100644 --- a/docs/manpages/rdimport.xml +++ b/docs/manpages/rdimport.xml @@ -222,21 +222,6 @@ - - - directory - - - - The directory to write logs to. - Overrides the [Logs] section of - rd.conf5. - The option must also be specified. - This option is mutually exclusive with the option. - - - - filename @@ -244,52 +229,15 @@ The filename to write logs to. - Overrides the [Logs] section of - rd.conf5. - The option must also be specified. - This option is mutually exclusive with the option. + This option is mutually exclusive with the + option. - The following wildcards can be used can be used in filename: + Rivendell "Filepath" wildcards can be used in + filename. See the + rivendell-wildcards7 + man page for details. - - - %d - - The day of the month (01 - 31) - - - - %h - - The hour (00 - 23) - - - - %M - - The month (01 - 12) - - - - %n - - The name of the originating module --e.g. 'rdairplay', 'caed'. - - - - %s - - The second (00 - 60) - - - - %Y - - The four digit year - - - diff --git a/docs/opsguide/rdadmin.dropbox_configuration_dialog.png b/docs/opsguide/rdadmin.dropbox_configuration_dialog.png index 251ccf1c..1d527caf 100644 Binary files a/docs/opsguide/rdadmin.dropbox_configuration_dialog.png and b/docs/opsguide/rdadmin.dropbox_configuration_dialog.png differ diff --git a/docs/opsguide/rdadmin.rivendell_dropbox_configurations_dialog.png b/docs/opsguide/rdadmin.rivendell_dropbox_configurations_dialog.png index f5a20441..529fb004 100644 Binary files a/docs/opsguide/rdadmin.rivendell_dropbox_configurations_dialog.png and b/docs/opsguide/rdadmin.rivendell_dropbox_configurations_dialog.png differ diff --git a/docs/opsguide/rdadmin.xml b/docs/opsguide/rdadmin.xml index f35e1fe7..fb31f4fb 100644 --- a/docs/opsguide/rdadmin.xml +++ b/docs/opsguide/rdadmin.xml @@ -1684,6 +1684,19 @@ + + + Log events in Syslog + + + + If ticked, log messages for this dropbox will be sent to + the system syslog. Otherwise, these events will be sent to + the file specified by the + Log File: setting below. + + + Log File: diff --git a/docs/tables/dropboxes.txt b/docs/tables/dropboxes.txt index f77eb466..5368eab8 100644 --- a/docs/tables/dropboxes.txt +++ b/docs/tables/dropboxes.txt @@ -24,6 +24,7 @@ METADATA_PATTERN varchar(64) STARTDATE_OFFSET int(11) ENDDATE_OFFSET int(11) FIX_BROKEN_FORMATS enum('N','Y') +LOG_TO_SYSLOG enum('N','Y') LOG_PATH varchar(191) IMPORT_CREATE_DATES enum('N','Y') CREATE_STARTDATE_OFFSET int(11) diff --git a/lib/dbversion.h b/lib/dbversion.h index 8587f872..57e47ee0 100644 --- a/lib/dbversion.h +++ b/lib/dbversion.h @@ -24,7 +24,7 @@ /* * Current Database Version */ -#define RD_VERSION_DATABASE 308 +#define RD_VERSION_DATABASE 309 #endif // DBVERSION_H diff --git a/lib/rdapplication.cpp b/lib/rdapplication.cpp index 81d976fc..37b0f26e 100644 --- a/lib/rdapplication.cpp +++ b/lib/rdapplication.cpp @@ -112,6 +112,8 @@ bool RDApplication::open(QString *err_msg,RDApplication::ErrorType *err_type, int schema=0; QString db_err; bool skip_db_check=false; + int persistent_dropbox_id=-1; + bool ok=false; if(err_type!=NULL) { *err_type=RDApplication::ErrorOk; @@ -127,6 +129,13 @@ bool RDApplication::open(QString *err_msg,RDApplication::ErrorType *err_type, skip_db_check=true; app_cmd_switch->setProcessed(i,true); } + if(app_cmd_switch->key(i)=="--persistent-dropbox-id") { + persistent_dropbox_id=app_cmd_switch->value(i).toUInt(&ok); + if(ok) { + app_command_name=QString().sprintf("dropbox[%u]",persistent_dropbox_id); + } + app_cmd_switch->setProcessed(i,true); + } } // diff --git a/lib/rdclock.cpp b/lib/rdclock.cpp index c0d7c9b4..b64ab34c 100644 --- a/lib/rdclock.cpp +++ b/lib/rdclock.cpp @@ -226,27 +226,42 @@ bool RDClock::save() } -bool RDClock::insert(const QString &event_name,int line) +int RDClock::insert(const QString &event_name,const QTime &time,int len) { + int line=-1; + QString sql=QString("select NAME from EVENTS where ")+ "NAME=\""+RDEscapeString(event_name)+"\""; RDSqlQuery *q=new RDSqlQuery(sql); if(!q->first()) { delete q; - return false; + return -1; } delete q; - if(line>=size()) { - clock_events.push_back(new RDEventLine(clock_station)); + if((clock_events.size()==0)||(timestartTime())) { + line=0; + clock_events.insert(0,new RDEventLine(clock_station)); } else { - clock_events.insert(line,new RDEventLine(clock_station)); - // QList::iterator it=clock_events.begin()+line; - //clock_events.insert(it,1,RDEventLine(clock_station)); + for(int i=0;iclock_events.at(i)->startTime())&& + (timestartTime())) { + line=i+1; + clock_events.insert(line,new RDEventLine(clock_station)); + break; + } + } + if(line<0) { + line=clock_events.size(); + clock_events.push_back(new RDEventLine(clock_station)); + } } clock_events.at(line)->setName(event_name); + clock_events.at(line)->setStartTime(time); + clock_events.at(line)->setLength(len); clock_events.at(line)->load(); - return true; + + return line; } @@ -254,35 +269,6 @@ void RDClock::remove(int line) { delete clock_events[line]; clock_events.removeAt(line); - // std::vector::iterator it=clock_events.begin()+line; - // clock_events.erase(it,it+1); -} - - -void RDClock::move(int from_line,int to_line) -{ - int src_offset=0; - int dest_offset=1; - RDEventLine *srcline; - RDEventLine *destline; - - if(to_linename(),to_line+dest_offset); - if((to_line+1)>=size()) { - to_line=clock_events.size()-1; - dest_offset=0; - } - - if(((destline=eventLine(to_line+dest_offset))==NULL)|| - (srcline=eventLine(from_line+src_offset))==NULL) { - remove(to_line+dest_offset); - return; - } - *destline=*srcline; - remove(from_line+src_offset); } diff --git a/lib/rdclock.h b/lib/rdclock.h index 9bc47c4a..6cca5220 100644 --- a/lib/rdclock.h +++ b/lib/rdclock.h @@ -48,9 +48,8 @@ class RDClock int size() const; bool load(); bool save(); - bool insert(const QString &event_name,int line); + int insert(const QString &event_name,const QTime &start,int len); void remove(int line); - void move(int from_line,int to_line); bool validate(const QTime &start_time,int length,int except_line=-1); bool generateLog(int hour,const QString &logname,const QString &svc_name, QString *errors); diff --git a/lib/rddb.cpp b/lib/rddb.cpp index b41b4e5b..cff9f1fc 100644 --- a/lib/rddb.cpp +++ b/lib/rddb.cpp @@ -95,6 +95,18 @@ int RDSqlQuery::columns() const } +QVariant RDSqlQuery::value(int index) const +{ + QVariant ret=QSqlQuery::value(index); + + if(!ret.isValid()) { + fprintf(stderr,"for query: %s\n\n",(const char *)executedQuery().toUtf8()); + } + + return ret; +} + + QVariant RDSqlQuery::run(const QString &sql,bool *ok) { QVariant ret; diff --git a/lib/rddb.h b/lib/rddb.h index ac648636..f37222f6 100644 --- a/lib/rddb.h +++ b/lib/rddb.h @@ -33,6 +33,7 @@ class RDSqlQuery : public QSqlQuery public: RDSqlQuery(const QString &query = QString::null,bool reconnect=true); int columns() const; + QVariant value(int index) const; static QVariant run(const QString &sql,bool *ok=NULL); static bool apply(const QString &sql,QString *err_msg=NULL); static int rows(const QString &sql); diff --git a/lib/rddropbox.cpp b/lib/rddropbox.cpp index 5f8710b7..623911f4 100644 --- a/lib/rddropbox.cpp +++ b/lib/rddropbox.cpp @@ -300,6 +300,19 @@ void RDDropbox::setFixBrokenFormats(bool state) const } +bool RDDropbox::logToSyslog() const +{ + return RDBool(RDGetSqlValue("DROPBOXES","ID",box_id,"LOG_TO_SYSLOG"). + toString()); +} + + +void RDDropbox::setLogToSyslog(bool state) const +{ + SetRow("LOG_TO_SYSLOG",state); +} + + QString RDDropbox::logPath() const { return RDGetSqlValue("DROPBOXES","ID",box_id,"LOG_PATH").toString(); diff --git a/lib/rddropbox.h b/lib/rddropbox.h index 86b09339..bd0334af 100644 --- a/lib/rddropbox.h +++ b/lib/rddropbox.h @@ -64,6 +64,8 @@ class RDDropbox void setEnddateOffset(int offset) const; bool fixBrokenFormats() const; void setFixBrokenFormats(bool state) const; + bool logToSyslog() const; + void setLogToSyslog(bool state) const; QString logPath() const; void setLogPath(const QString &path) const; bool createDates() const; diff --git a/lib/rdlogplay.cpp b/lib/rdlogplay.cpp index 4c038f1f..ef0f8f3f 100644 --- a/lib/rdlogplay.cpp +++ b/lib/rdlogplay.cpp @@ -78,7 +78,7 @@ RDLogPlay::RDLogPlay(int id,RDEventPlayer *player,QObject *parent) // play_pad_socket=new RDUnixSocket(this); if(!play_pad_socket->connectToAbstract(RD_PAD_SOURCE_UNIX_ADDRESS)) { - fprintf(stderr,"RDLogPlat: unable to connect to rdpadd\n"); + fprintf(stderr,"RDLogPlay: unable to connect to rdpadd\n"); } // @@ -154,9 +154,11 @@ RDLogPlay::RDLogPlay(int id,RDEventPlayer *player,QObject *parent) // Transition Timers // play_trans_timer=new QTimer(this); + play_trans_timer->setSingleShot(true); connect(play_trans_timer,SIGNAL(timeout()), this,SLOT(transTimerData())); play_grace_timer=new QTimer(this); + play_grace_timer->setSingleShot(true); connect(play_grace_timer,SIGNAL(timeout()), this,SLOT(graceTimerData())); } @@ -1164,10 +1166,8 @@ RDLogLine::TransType RDLogPlay::nextTrans() RDLogLine::TransType RDLogPlay::nextTrans(int line) { RDLogLine *logline; - -// if((logline=logLine(nextLine(line)))!=NULL) { - int next_line; + next_line=nextLine(line); logline=logLine(next_line); if(logline!=NULL) { @@ -1203,14 +1203,14 @@ void RDLogPlay::transportEvents(int line[]) return; } switch(logline->status()) { - case RDLogLine::Scheduled: - if(countisActive()) { play_grace_timer->stop(); } if(play_op_mode==RDAirPlayConf::Auto) { + if((logline=logLine(play_trans_line))!=NULL) { + if(logline->graceTime()==-1) { // Make Next + makeNext(play_trans_line); + SetTransTimer(); + return; + } + if(logline->graceTime()>0) { + if(running_events>0) { + if(logline->transType()==RDLogLine::Stop) { + logline->setTransType(RDLogLine::Play); + } + logline->setStartTime(RDLogLine::Predicted,logline-> + startTime(RDLogLine::Predicted). + addMSecs(grace)); + play_grace_line=play_trans_line; + play_grace_timer->start(logline->graceTime()); + return; + } + else { + } + } + } if(!GetNextPlayable(&play_trans_line,false)) { SetTransTimer(); return; @@ -1408,45 +1431,12 @@ void RDLogPlay::transTimerData() if((logline=logLine(play_trans_line))!=NULL) { grace=logline->graceTime(); } - if((runningEvents(lines)==0)) { + if(running_events==0) { makeNext(play_trans_line); if(logline->transType()!=RDLogLine::Stop || grace>=0) { StartEvent(trans_line,RDLogLine::Play,0,RDLogLine::StartTime); } } - else { - if(logline==NULL) { - SetTransTimer(); - return; - } - switch(logline->graceTime()) { - case 0: - makeNext(play_trans_line); - if(play_trans_length==0) { - StartEvent(trans_line,RDLogLine::Play,0,RDLogLine::StartTime); - } - else { - StartEvent(trans_line,RDLogLine::Segue,play_trans_length, - RDLogLine::StartTime); - } - break; - - case -1: - makeNext(play_trans_line); - break; - - default: - if(logline->transType()==RDLogLine::Stop) { - logline->setTransType(RDLogLine::Play); - } - logline->setStartTime(RDLogLine::Predicted,logline-> - startTime(RDLogLine::Predicted). - addMSecs(grace)); - play_grace_line=play_trans_line; - play_grace_timer->start(grace,true); - break; - } - } } SetTransTimer(); } @@ -1462,9 +1452,6 @@ void RDLogPlay::graceTimerData() SetTransTimer(); return; } - if(line!=play_grace_line) { - return; - } if((runningEvents(lines)==0)) { makeNext(play_grace_line); StartEvent(play_grace_line,RDLogLine::Play,0,RDLogLine::StartTime); @@ -1489,25 +1476,25 @@ void RDLogPlay::playStateChangedData(int id,RDPlayDeck::State state) printf("playStateChangedData(%d,%d), log: %s\n",id,state,(const char *)logName()); #endif switch(state) { - case RDPlayDeck::Playing: - Playing(id); - break; + case RDPlayDeck::Playing: + Playing(id); + break; - case RDPlayDeck::Paused: - Paused(id); - break; + case RDPlayDeck::Paused: + Paused(id); + break; - case RDPlayDeck::Stopping: - Stopping(id); - break; + case RDPlayDeck::Stopping: + Stopping(id); + break; - case RDPlayDeck::Stopped: - Stopped(id); - break; + case RDPlayDeck::Stopped: + Stopped(id); + break; - case RDPlayDeck::Finished: - Finished(id); - break; + case RDPlayDeck::Finished: + Finished(id); + break; } } @@ -1797,59 +1784,59 @@ bool RDLogPlay::StartEvent(int line,RDLogLine::TransType trans_type, running=runningEvents(lines); if(play_op_mode!=RDAirPlayConf::Manual) { switch(trans_type) { - case RDLogLine::Play: - for(int i=0;itype()==RDLogLine::Cart)|| - (logLine(lines[i])->type()==RDLogLine::Macro))&& - (logLine(lines[i])->status()!=RDLogLine::Paused)) { - switch(logLine(lines[i])->cartType()) { - case RDCart::Audio: - ((RDPlayDeck *)logLine(lines[i])->playDeck())->stop(); - break; + case RDLogLine::Play: + for(int i=0;itype()==RDLogLine::Cart)|| + (logLine(lines[i])->type()==RDLogLine::Macro))&& + (logLine(lines[i])->status()!=RDLogLine::Paused)) { + switch(logLine(lines[i])->cartType()) { + case RDCart::Audio: + ((RDPlayDeck *)logLine(lines[i])->playDeck())->stop(); + break; - case RDCart::Macro: - play_macro_deck->stop(); - break; + case RDCart::Macro: + play_macro_deck->stop(); + break; - case RDCart::All: - break; - } - } + case RDCart::All: + break; } } - break; + } + } + break; - case RDLogLine::Segue: - for(int i=0;istatus()==RDLogLine::Playing) { - if(((prev_logline->type()==RDLogLine::Cart)|| - (prev_logline->type()==RDLogLine::Macro))&& - (prev_logline->status()!=RDLogLine::Paused)) { - switch(logLine(lines[i])->cartType()) { - case RDCart::Audio: - prev_logline->setStatus(RDLogLine::Finishing); - ((RDPlayDeck *)prev_logline->playDeck())-> - stop(trans_length); - break; + case RDLogLine::Segue: + for(int i=0;istatus()==RDLogLine::Playing) { + if(((prev_logline->type()==RDLogLine::Cart)|| + (prev_logline->type()==RDLogLine::Macro))&& + (prev_logline->status()!=RDLogLine::Paused)) { + switch(logLine(lines[i])->cartType()) { + case RDCart::Audio: + prev_logline->setStatus(RDLogLine::Finishing); + ((RDPlayDeck *)prev_logline->playDeck())-> + stop(trans_length); + break; - case RDCart::Macro: - play_macro_deck->stop(); - break; + case RDCart::Macro: + play_macro_deck->stop(); + break; - case RDCart::All: - break; - } - } + case RDCart::All: + break; } } } - break; + } + } + break; - default: - break; + default: + break; } } @@ -1867,208 +1854,208 @@ bool RDLogPlay::StartEvent(int line,RDLogLine::TransType trans_type, // logline->setStartSource(src); switch(logline->type()) { - case RDLogLine::Cart: - if(!StartAudioEvent(line)) { - rda->airplayConf()->setLogCurrentLine(play_id,nextLine()); - return false; - } - aport=GetNextChannel(mport,&card,&port); - playdeck=(RDPlayDeck *)logline->playDeck(); - playdeck->setCard(card); - playdeck->setPort(port); - playdeck->setChannel(aport); - logline->setPauseCard(card); - logline->setPausePort(port); - logline->setPortName(GetPortName(playdeck->card(), - playdeck->port())); - if(logline->portName().toInt()==2){ - playdeck->duckVolume(play_duck_volume_port2,0); - } - else { - playdeck->duckVolume(play_duck_volume_port1,0); - } + case RDLogLine::Cart: + if(!StartAudioEvent(line)) { + rda->airplayConf()->setLogCurrentLine(play_id,nextLine()); + return false; + } + aport=GetNextChannel(mport,&card,&port); + playdeck=(RDPlayDeck *)logline->playDeck(); + playdeck->setCard(card); + playdeck->setPort(port); + playdeck->setChannel(aport); + logline->setPauseCard(card); + logline->setPausePort(port); + logline->setPortName(GetPortName(playdeck->card(), + playdeck->port())); + if(logline->portName().toInt()==2){ + playdeck->duckVolume(play_duck_volume_port2,0); + } + else { + playdeck->duckVolume(play_duck_volume_port1,0); + } - if(!playdeck->setCart(logline,logline->status()!=RDLogLine::Paused)) { - // No audio to play, so fake it - logline->setZombified(true); - playStateChangedData(playdeck->id(),RDPlayDeck::Playing); - logline->setStatus(RDLogLine::Playing); - playStateChangedData(playdeck->id(),RDPlayDeck::Finished); - logline->setStatus(RDLogLine::Finished); - rda->syslog(LOG_WARNING, - "log engine: RDLogPlay::StartEvent(): no audio,CUT=%s", - (const char *)logline->cutName().toUtf8()); - rda->airplayConf()->setLogCurrentLine(play_id,nextLine()); - return false; - } - emit modified(line); - logline->setCutNumber(playdeck->cut()->cutNumber()); - logline->setEvergreen(playdeck->cut()->evergreen()); - if(play_timescaling_available&&logline->enforceLength()) { - logline->setTimescalingActive(true); - } - RDSetMixerOutputPort(play_cae,playdeck->card(), - playdeck->stream(), - playdeck->port()); - if((int)logline->playPosition()>logline->effectiveLength()) { - rda->syslog(LOG_DEBUG,"log engine: *** position out of bounds: Line: %d Cart: %d Pos: %d ***",line,logline->cartNumber(),logline->playPosition()); - logline->setPlayPosition(0); - } - playdeck->play(logline->playPosition(),-1,-1,duck_length); - if(logline->status()==RDLogLine::RDLogLine::Paused) { - logline-> - setStartTime(RDLogLine::Actual,playdeck->startTime()); - was_paused=true; - } - else { - logline-> - setStartTime(RDLogLine::Initial,playdeck->startTime()); - } - logline->setStatus(RDLogLine::Playing); - if(!play_start_rml[aport].isEmpty()) { - play_event_player-> - exec(logline->resolveWildcards(play_start_rml[aport])); - } - /* - printf("channelStarted(%d,%d,%d,%d)\n", - play_id,playdeck->channel(), - playdeck->card(),playdeck->port()); - */ - emit channelStarted(play_id,playdeck->channel(), - playdeck->card(),playdeck->port()); - rda->syslog(LOG_INFO,"log engine: started audio cart: Line: %d Cart: %u Cut: %u Pos: %d Card: %d Stream: %d Port: %d", - line,logline->cartNumber(), - playdeck->cut()->cutNumber(), - logline->playPosition(), - playdeck->card(), - playdeck->stream(), - playdeck->port()); + if(!playdeck->setCart(logline,logline->status()!=RDLogLine::Paused)) { + // No audio to play, so fake it + logline->setZombified(true); + playStateChangedData(playdeck->id(),RDPlayDeck::Playing); + logline->setStatus(RDLogLine::Playing); + playStateChangedData(playdeck->id(),RDPlayDeck::Finished); + logline->setStatus(RDLogLine::Finished); + rda->syslog(LOG_WARNING, + "log engine: RDLogPlay::StartEvent(): no audio,CUT=%s", + (const char *)logline->cutName().toUtf8()); + rda->airplayConf()->setLogCurrentLine(play_id,nextLine()); + return false; + } + emit modified(line); + logline->setCutNumber(playdeck->cut()->cutNumber()); + logline->setEvergreen(playdeck->cut()->evergreen()); + if(play_timescaling_available&&logline->enforceLength()) { + logline->setTimescalingActive(true); + } + RDSetMixerOutputPort(play_cae,playdeck->card(), + playdeck->stream(), + playdeck->port()); + if((int)logline->playPosition()>logline->effectiveLength()) { + rda->syslog(LOG_DEBUG,"log engine: *** position out of bounds: Line: %d Cart: %d Pos: %d ***",line,logline->cartNumber(),logline->playPosition()); + logline->setPlayPosition(0); + } + playdeck->play(logline->playPosition(),-1,-1,duck_length); + if(logline->status()==RDLogLine::RDLogLine::Paused) { + logline-> + setStartTime(RDLogLine::Actual,playdeck->startTime()); + was_paused=true; + } + else { + logline-> + setStartTime(RDLogLine::Initial,playdeck->startTime()); + } + logline->setStatus(RDLogLine::Playing); + if(!play_start_rml[aport].isEmpty()) { + play_event_player-> + exec(logline->resolveWildcards(play_start_rml[aport])); + } + /* + printf("channelStarted(%d,%d,%d,%d)\n", + play_id,playdeck->channel(), + playdeck->card(),playdeck->port()); + */ + emit channelStarted(play_id,playdeck->channel(), + playdeck->card(),playdeck->port()); + rda->syslog(LOG_INFO,"log engine: started audio cart: Line: %d Cart: %u Cut: %u Pos: %d Card: %d Stream: %d Port: %d", + line,logline->cartNumber(), + playdeck->cut()->cutNumber(), + logline->playPosition(), + playdeck->card(), + playdeck->stream(), + playdeck->port()); - // - // Assign Next Event - // - if((play_next_line>=0)&&(!was_paused)) { - play_next_line=line+1; - if((next_logline=logLine(play_next_line))!=NULL) { - if(next_logline->id()==-2) { - play_start_next=false; - } - } - emit nextEventChanged(play_next_line); + // + // Assign Next Event + // + if((play_next_line>=0)&&(!was_paused)) { + play_next_line=line+1; + if((next_logline=logLine(play_next_line))!=NULL) { + if(next_logline->id()==-2) { + play_start_next=false; } - break; + } + emit nextEventChanged(play_next_line); + } + break; - case RDLogLine::Macro: - // - // Assign Next Event - // - if(play_next_line>=0) { - play_next_line=line+1; - if((next_logline=logLine(play_next_line))!=NULL) { - if(logline->id()==-2) { - play_start_next=false; - } - if(logline->forcedStop()) { - next_logline->setTransType(RDLogLine::Stop); - } - } + case RDLogLine::Macro: + // + // Assign Next Event + // + if(play_next_line>=0) { + play_next_line=line+1; + if((next_logline=logLine(play_next_line))!=NULL) { + if(logline->id()==-2) { + play_start_next=false; } - if(logline->asyncronous()) { - RDMacro *rml=new RDMacro(); - rml->setCommand(RDMacro::EX); - QHostAddress addr; - addr.setAddress("127.0.0.1"); - rml->setAddress(addr); - rml->setRole(RDMacro::Cmd); - rml->setEchoRequested(false); - rml->addArg(logline->cartNumber()); // Arg 0 - rda->ripc()->sendRml(rml); - delete rml; - emit played(line); - logline->setStartTime(RDLogLine::Actual,QTime::currentTime()); - logline->setStatus(RDLogLine::Finished); - LogTraffic(logline,(RDLogLine::PlaySource)(play_id+1), - RDAirPlayConf::TrafficMacro,play_onair_flag); - FinishEvent(line); - emit transportChanged(); - rda->syslog(LOG_INFO, - "log engine: asynchronously executed macro cart: Line: %d Cart: %u", - line,logline->cartNumber()); + if(logline->forcedStop()) { + next_logline->setTransType(RDLogLine::Stop); } - else { - play_macro_deck->load(logline->cartNumber()); - play_macro_deck->setLine(line); - rda->syslog(LOG_INFO, - "log engine: started macro cart: Line: %d Cart: %u", - line,logline->cartNumber()); - play_macro_deck->exec(); - } - break; + } + } + if(logline->asyncronous()) { + RDMacro *rml=new RDMacro(); + rml->setCommand(RDMacro::EX); + QHostAddress addr; + addr.setAddress("127.0.0.1"); + rml->setAddress(addr); + rml->setRole(RDMacro::Cmd); + rml->setEchoRequested(false); + rml->addArg(logline->cartNumber()); // Arg 0 + rda->ripc()->sendRml(rml); + delete rml; + emit played(line); + logline->setStartTime(RDLogLine::Actual,QTime::currentTime()); + logline->setStatus(RDLogLine::Finished); + LogTraffic(logline,(RDLogLine::PlaySource)(play_id+1), + RDAirPlayConf::TrafficMacro,play_onair_flag); + FinishEvent(line); + emit transportChanged(); + rda->syslog(LOG_INFO, + "log engine: asynchronously executed macro cart: Line: %d Cart: %u", + line,logline->cartNumber()); + } + else { + play_macro_deck->load(logline->cartNumber()); + play_macro_deck->setLine(line); + rda->syslog(LOG_INFO, + "log engine: started macro cart: Line: %d Cart: %u", + line,logline->cartNumber()); + play_macro_deck->exec(); + } + break; - case RDLogLine::Marker: - case RDLogLine::Track: - case RDLogLine::MusicLink: - case RDLogLine::TrafficLink: - // - // Assign Next Event - // - if(play_next_line>=0) { - play_next_line=line+1; - if((next_logline=logLine(play_next_line))!=NULL) { - if(logLine(play_next_line)->id()==-2) { - play_start_next=false; - } - } - else { - play_start_next=false; - } + case RDLogLine::Marker: + case RDLogLine::Track: + case RDLogLine::MusicLink: + case RDLogLine::TrafficLink: + // + // Assign Next Event + // + if(play_next_line>=0) { + play_next_line=line+1; + if((next_logline=logLine(play_next_line))!=NULL) { + if(logLine(play_next_line)->id()==-2) { + play_start_next=false; } + } + else { + play_start_next=false; + } + } - // - // Skip Past - // - logline->setStatus(RDLogLine::Finished); - UpdateStartTimes(line); - emit played(line); - FinishEvent(line); - emit nextEventChanged(play_next_line); - break; + // + // Skip Past + // + logline->setStatus(RDLogLine::Finished); + UpdateStartTimes(line); + emit played(line); + FinishEvent(line); + emit nextEventChanged(play_next_line); + break; - case RDLogLine::Chain: - // - // Assign Next Event - // - if(play_next_line>0) { - play_next_line=line+1; - if((next_logline=logLine(play_next_line))!=NULL) { - if(logLine(play_next_line)->id()==-2) { - play_start_next=false; - } - } - else { - play_start_next=false; - } + case RDLogLine::Chain: + // + // Assign Next Event + // + if(play_next_line>0) { + play_next_line=line+1; + if((next_logline=logLine(play_next_line))!=NULL) { + if(logLine(play_next_line)->id()==-2) { + play_start_next=false; } - if(GetTransType(logline->markerLabel(),0)!=RDLogLine::Stop) { - play_macro_deck-> - load(QString().sprintf("LL %d %s -2!", - play_id+1, - (const char *)logline->markerLabel())); - } - else { - play_macro_deck-> - load(QString().sprintf("LL %d %s -2!", - play_id+1, - (const char *)logline->markerLabel())); - } - play_macro_deck->setLine(line); - play_macro_deck->exec(); - rda->syslog(LOG_INFO,"log engine: chained to log: Line: %d Log: %s", - line,(const char *)logline->markerLabel()); - break; + } + else { + play_start_next=false; + } + } + if(GetTransType(logline->markerLabel(),0)!=RDLogLine::Stop) { + play_macro_deck-> + load(QString().sprintf("LL %d %s -2!", + play_id+1, + (const char *)logline->markerLabel())); + } + else { + play_macro_deck-> + load(QString().sprintf("LL %d %s -2!", + play_id+1, + (const char *)logline->markerLabel())); + } + play_macro_deck->setLine(line); + play_macro_deck->exec(); + rda->syslog(LOG_INFO,"log engine: chained to log: Line: %d Log: %s", + line,(const char *)logline->markerLabel()); + break; - default: - break; + default: + break; } while((play_next_linestate()==RDLogLine::Ok)|| @@ -2202,19 +2189,19 @@ void RDLogPlay::UpdateStartTimes(int line) } stop=false; switch(logline->status()) { - case RDLogLine::Playing: - case RDLogLine::Finishing: - time=logline->startTime(RDLogLine::Actual); - break; + case RDLogLine::Playing: + case RDLogLine::Finishing: + time=logline->startTime(RDLogLine::Actual); + break; - default: - time=GetStartTime(logline->startTime(RDLogLine::Logged), - logline->transType(), - logline->timeType(), - time,prev_total_length,prev_segue_length, - &stop,running); - logline->setStartTime(RDLogLine::Predicted,time); - break; + default: + time=GetStartTime(logline->startTime(RDLogLine::Logged), + logline->transType(), + logline->timeType(), + time,prev_total_length,prev_segue_length, + &stop,running); + logline->setStartTime(RDLogLine::Predicted,time); + break; } if(stop&&(!stop_set)) { next_stop=time.addMSecs(prev_total_length); @@ -2302,24 +2289,24 @@ QTime RDLogPlay::GetStartTime(QTime sched_time, return QTime(); } switch(trans_type) { - case RDLogLine::Play: - if(!prev_time.isNull()) { - time=prev_time.addMSecs(prev_total_length); - } - break; + case RDLogLine::Play: + if(!prev_time.isNull()) { + time=prev_time.addMSecs(prev_total_length); + } + break; - case RDLogLine::Segue: - if(!prev_time.isNull()) { - time=prev_time.addMSecs(prev_segue_length); - } - break; + case RDLogLine::Segue: + if(!prev_time.isNull()) { + time=prev_time.addMSecs(prev_segue_length); + } + break; - case RDLogLine::Stop: - time=QTime(); - break; + case RDLogLine::Stop: + time=QTime(); + break; - default: - break; + default: + break; } switch(time_type) { case RDLogLine::Relative: @@ -2380,18 +2367,18 @@ QTime RDLogPlay::GetNextStop(int line) if(running&&(play_op_mode==RDAirPlayConf::Auto)&& (status(i)==RDLogLine::Scheduled)) { switch(logLine(i)->transType()) { - case RDLogLine::Stop: - return time; - break; + case RDLogLine::Stop: + return time; + break; - case RDLogLine::Play: - case RDLogLine::Segue: - time=time.addMSecs(logLine(i)->segueLength(nextTrans(i))- - logLine(i)->playPosition()); - break; + case RDLogLine::Play: + case RDLogLine::Segue: + time=time.addMSecs(logLine(i)->segueLength(nextTrans(i))- + logLine(i)->playPosition()); + break; - default: - break; + default: + break; } } } @@ -2525,7 +2512,7 @@ void RDLogPlay::SetTransTimer(QTime current_time,bool stop) } if(next_line>=0) { play_trans_line=next_line; - play_trans_timer->start(current_time.msecsTo(next_time),true); + play_trans_timer->start(current_time.msecsTo(next_time)); } } @@ -2754,13 +2741,18 @@ void RDLogPlay::Stopped(int id) CleanupEvent(id); UpdateStartTimes(line); emit stopped(line); + LogTraffic(logLine(line),(RDLogLine::PlaySource)(play_id+1), + RDAirPlayConf::TrafficStop,play_onair_flag); + if(play_grace_timer->isActive()) { // Pending Hard Time Event + play_grace_timer->stop(); + play_grace_timer->start(0); + return; + } AdvanceActiveEvent(); UpdatePostPoint(); if(runningEvents(lines)==0) { next_channel=0; } - LogTraffic(logLine(line),(RDLogLine::PlaySource)(play_id+1), - RDAirPlayConf::TrafficStop,play_onair_flag); emit transportChanged(); } @@ -2774,16 +2766,16 @@ void RDLogPlay::Finished(int id) return; } switch(logline->status()) { - case RDLogLine::Playing: - CleanupEvent(id); - FinishEvent(line); - break; + case RDLogLine::Playing: + CleanupEvent(id); + FinishEvent(line); + break; - case RDLogLine::Auditioning: - break; + case RDLogLine::Auditioning: + break; - default: - break; + default: + break; } UpdatePostPoint(); if(runningEvents(lines)==0) { diff --git a/rdadmin/edit_dropbox.cpp b/rdadmin/edit_dropbox.cpp index 6fb5bc95..4150be87 100644 --- a/rdadmin/edit_dropbox.cpp +++ b/rdadmin/edit_dropbox.cpp @@ -154,26 +154,40 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); // - // Log Path + // Logging // - box_log_path_edit=new QLineEdit(this); - box_log_path_edit->setGeometry(120,120,sizeHint().width()-190,19); - box_log_path_edit->setMaxLength(255); - label= - new QLabel(box_log_path_edit,tr("&Log File:"),this); - label->setGeometry(10,120,105,19); + box_log_to_syslog_check=new QCheckBox(this); + box_log_to_syslog_check->setGeometry(50,124,15,15); + label=new QLabel(box_log_to_syslog_check,tr("Log events in Syslog"),this); + label->setGeometry(70,122,250,19); label->setFont(font); - label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); - button=new QPushButton(tr("Select"),this); - button->setGeometry(sizeHint().width()-60,118,50,23); - button->setFont(normal_font); - connect(button,SIGNAL(clicked()),this,SLOT(selectLogPathData())); + label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + + box_log_path_edit=new QLineEdit(this); + box_log_path_edit->setGeometry(120,141,sizeHint().width()-190,19); + box_log_path_edit->setMaxLength(255); + connect(box_log_to_syslog_check,SIGNAL(toggled(bool)), + box_log_path_edit,SLOT(setDisabled(bool))); + box_log_path_label= + new QLabel(box_log_path_edit,tr("&Log File:"),this); + box_log_path_label->setGeometry(10,141,105,19); + box_log_path_label->setFont(font); + box_log_path_label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); + connect(box_log_to_syslog_check,SIGNAL(toggled(bool)), + box_log_path_label,SLOT(setDisabled(bool))); + box_log_path_button=new QPushButton(tr("Select"),this); + box_log_path_button->setGeometry(sizeHint().width()-60,138,50,23); + box_log_path_button->setFont(normal_font); + connect(box_log_path_button,SIGNAL(clicked()), + this,SLOT(selectLogPathData())); + connect(box_log_to_syslog_check,SIGNAL(toggled(bool)), + box_log_path_button,SLOT(setDisabled(bool))); // // Scheduler Codes // box_schedcodes_button=new QPushButton(tr("Scheduler Codes"),this); - box_schedcodes_button->setGeometry(110,145,200,25); + box_schedcodes_button->setGeometry(110,167,200,25); box_schedcodes_button->setFont(font); connect(box_schedcodes_button,SIGNAL(clicked()),this,SLOT(schedcodesData())); @@ -181,10 +195,10 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // Delete Source // box_delete_source_box=new QCheckBox(this); - box_delete_source_box->setGeometry(90,177,15,15); + box_delete_source_box->setGeometry(90,199,15,15); label=new QLabel(box_delete_source_box,tr("Delete source files after import"), this); - label->setGeometry(110,175,sizeHint().width()-120,20); + label->setGeometry(110,197,sizeHint().width()-120,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); @@ -192,9 +206,9 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // Force To Mono // box_force_to_mono_box=new QCheckBox(this); - box_force_to_mono_box->setGeometry(90,199,15,15); + box_force_to_mono_box->setGeometry(90,221,15,15); label=new QLabel(box_force_to_mono_box,tr("Force to Monaural"),this); - label->setGeometry(110,197,sizeHint().width()-120,20); + label->setGeometry(110,219,sizeHint().width()-120,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); @@ -202,20 +216,20 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // Normalization // box_normalization_box=new QCheckBox(this); - box_normalization_box->setGeometry(90,221,15,15); + box_normalization_box->setGeometry(90,243,15,15); label=new QLabel(box_normalization_box,tr("Normalize Levels"),this); - label->setGeometry(110,219,100,20); + label->setGeometry(110,241,100,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); box_normalization_level_spin=new QSpinBox(this); - box_normalization_level_spin->setGeometry(275,219,50,20); + box_normalization_level_spin->setGeometry(275,241,50,20); box_normalization_level_spin->setRange(-100,-1); box_normalization_level_label=new QLabel(tr("Level:"),this); - box_normalization_level_label->setGeometry(210,219,60,20); + box_normalization_level_label->setGeometry(210,241,60,20); box_normalization_level_label->setFont(font); box_normalization_level_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); box_normalization_level_unit=new QLabel(tr("dBFS"),this); - box_normalization_level_unit->setGeometry(330,219,60,20); + box_normalization_level_unit->setGeometry(330,241,60,20); box_normalization_level_unit->setAlignment(Qt::AlignVCenter|Qt::AlignLeft); connect(box_normalization_box,SIGNAL(toggled(bool)), this,SLOT(normalizationToggledData(bool))); @@ -224,20 +238,20 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // Autotrim // box_autotrim_box=new QCheckBox(this); - box_autotrim_box->setGeometry(90,245,15,15); + box_autotrim_box->setGeometry(90,267,15,15); label=new QLabel(box_autotrim_box,tr("Autotrim Cuts"),this); - label->setGeometry(110,243,100,20); + label->setGeometry(110,265,100,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); box_autotrim_level_spin=new QSpinBox(this); - box_autotrim_level_spin->setGeometry(275,243,50,20); + box_autotrim_level_spin->setGeometry(275,265,50,20); box_autotrim_level_spin->setRange(-100,-1); box_autotrim_level_label=new QLabel(tr("Level:"),this); - box_autotrim_level_label->setGeometry(210,243,60,20); + box_autotrim_level_label->setGeometry(210,265,60,20); box_autotrim_level_label->setFont(font); box_autotrim_level_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); box_autotrim_level_unit=new QLabel(tr("dBFS"),this); - box_autotrim_level_unit->setGeometry(330,243,60,20); + box_autotrim_level_unit->setGeometry(330,265,60,20); box_autotrim_level_unit->setAlignment(Qt::AlignVCenter|Qt::AlignLeft); connect(box_autotrim_box,SIGNAL(toggled(bool)), this,SLOT(autotrimToggledData(bool))); @@ -246,51 +260,45 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // Segue // box_segue_box=new QCheckBox(this); - box_segue_box->setGeometry(90,271,15,15); - label=new QLabel(box_segue_box,tr("Insert Segue Markers"), - this); - label->setGeometry(110,269,sizeHint().width()-40,20); + box_segue_box->setGeometry(90,293,15,15); + label=new QLabel(box_segue_box,tr("Insert Segue Markers"),this); + label->setGeometry(110,291,sizeHint().width()-40,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); - box_segue_level_spin= - new QSpinBox(this); - box_segue_level_spin->setGeometry(300,295,50,20); + box_segue_level_spin=new QSpinBox(this); + box_segue_level_spin->setGeometry(300,317,50,20); box_segue_level_spin->setRange(-100,0); box_segue_level_label= - new QLabel(box_segue_level_spin,tr("Segue Level:"), - this); - box_segue_level_label->setGeometry(120,295,160,20); + new QLabel(box_segue_level_spin,tr("Segue Level:"),this); + box_segue_level_label->setGeometry(120,317,160,20); box_segue_level_label->setFont(font); box_segue_level_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); - box_segue_level_unit= - new QLabel(box_segue_level_spin,("dBFS"),this); - box_segue_level_unit->setGeometry(360,296,60,20); + box_segue_level_unit=new QLabel(box_segue_level_spin,("dBFS"),this); + box_segue_level_unit->setGeometry(360,318,60,20); box_segue_level_unit->setAlignment(Qt::AlignVCenter|Qt::AlignLeft); box_segue_length_spin=new QSpinBox(this); - box_segue_length_spin->setGeometry(300,320,70,20); + box_segue_length_spin->setGeometry(300,342,70,20); box_segue_length_spin->setRange(0,180000); box_segue_length_label= - new QLabel(box_segue_length_spin,tr("Segue Length:"), - this); - box_segue_length_label->setGeometry(120,320,160,20); + new QLabel(box_segue_length_spin,tr("Segue Length:"),this); + box_segue_length_label->setGeometry(120,342,160,20); box_segue_length_label->setFont(font); box_segue_length_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); - box_segue_length_unit= - new QLabel(box_segue_length_spin,("msec"),this); - box_segue_length_unit->setGeometry(375,321,60,20); + box_segue_length_unit=new QLabel(box_segue_length_spin,("msec"),this); + box_segue_length_unit->setGeometry(375,343,60,20); box_segue_length_unit->setAlignment(Qt::AlignVCenter|Qt::AlignLeft); connect(box_segue_box,SIGNAL(toggled(bool)), - this,SLOT(segueToggledData(bool))); + this,SLOT(segueToggledData(bool))); // // Use CartChunk ID // box_use_cartchunk_id_box=new QCheckBox(this); - box_use_cartchunk_id_box->setGeometry(90,350,15,15); + box_use_cartchunk_id_box->setGeometry(90,372,15,15); label=new QLabel(box_use_cartchunk_id_box, tr("Get cart number from CartChunk CutID"),this); - label->setGeometry(110,348,sizeHint().width()-40,20); + label->setGeometry(110,370,sizeHint().width()-40,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); @@ -298,10 +306,10 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // Title from CartChunk ID // box_title_from_cartchunk_id_box=new QCheckBox(this); - box_title_from_cartchunk_id_box->setGeometry(90,374,15,15); + box_title_from_cartchunk_id_box->setGeometry(90,396,15,15); label=new QLabel(box_title_from_cartchunk_id_box, tr("Get cart title from CartChunk CutID"),this); - label->setGeometry(110,372,sizeHint().width()-40,20); + label->setGeometry(110,394,sizeHint().width()-40,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); @@ -309,10 +317,10 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // Fix Broken Formats // box_fix_broken_formats_box=new QCheckBox(this); - box_fix_broken_formats_box->setGeometry(90,398,15,15); + box_fix_broken_formats_box->setGeometry(90,420,15,15); label=new QLabel(box_fix_broken_formats_box, tr("Attempt to work around malformatted input files"),this); - label->setGeometry(110,396,sizeHint().width()-40,20); + label->setGeometry(110,418,sizeHint().width()-40,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); @@ -321,30 +329,29 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // box_startoffset_spin= new QSpinBox(this); - box_startoffset_spin->setGeometry(215,422,50,20); + box_startoffset_spin->setGeometry(215,444,50,20); box_startoffset_spin->setRange(-7,7); label=new QLabel(box_startoffset_spin,tr("Offset start date by"),this); - label->setGeometry(90,422,120,20); + label->setGeometry(90,444,120,20); label->setFont(font); - label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); label=new QLabel(box_startoffset_spin,tr("days"),this); - label->setGeometry(275,424,100,20); + label->setGeometry(275,446,100,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); // // End Date Offset // - box_endoffset_spin= - new QSpinBox(this); - box_endoffset_spin->setGeometry(215,446,50,20); + box_endoffset_spin=new QSpinBox(this); + box_endoffset_spin->setGeometry(215,468,50,20); box_endoffset_spin->setRange(-7,7); label=new QLabel(box_endoffset_spin,tr("Offset end date by"),this); - label->setGeometry(90,446,120,20); + label->setGeometry(90,468,120,20); label->setFont(font); - label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + label->setAlignment(Qt::AlignRight|Qt::AlignVCenter); label=new QLabel(box_endoffset_spin,tr("days"),this); - label->setGeometry(275,446,100,20); + label->setGeometry(275,468,100,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); @@ -352,38 +359,38 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) // Create Dates // box_create_dates_box=new QCheckBox(this); - box_create_dates_box->setGeometry(90,470,15,15); + box_create_dates_box->setGeometry(90,492,15,15); label=new QLabel(box_create_dates_box,tr("Create Dates when no Dates Exist"), this); - label->setGeometry(110,468,sizeHint().width()-40,20); + label->setGeometry(110,490,sizeHint().width()-40,20); label->setFont(font); label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); - box_create_startdate_offset_spin= - new QSpinBox(this); - box_create_startdate_offset_spin->setGeometry(300,494,50,20); + box_create_startdate_offset_spin=new QSpinBox(this); + box_create_startdate_offset_spin->setGeometry(285,516,50,20); box_create_startdate_offset_spin->setRange(-180,180); box_create_startdate_label= new QLabel(box_create_startdate_offset_spin,tr("Create start date offset:"), this); - box_create_startdate_label->setGeometry(120,494,160,20); + box_create_startdate_label->setGeometry(120,516,160,20); box_create_startdate_label->setFont(font); box_create_startdate_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); box_create_startdate_unit= new QLabel(box_create_startdate_offset_spin,("days"),this); - box_create_startdate_unit->setGeometry(360,495,60,20); + box_create_startdate_unit->setGeometry(345,517,60,20); box_create_startdate_unit->setAlignment(Qt::AlignVCenter|Qt::AlignLeft); + box_create_enddate_offset_spin=new QSpinBox(this); - box_create_enddate_offset_spin->setGeometry(300,524,50,20); + box_create_enddate_offset_spin->setGeometry(285,538,50,20); box_create_enddate_offset_spin->setRange(-180,180); box_create_enddate_label= new QLabel(box_create_enddate_offset_spin,tr("Create end date offset:"), this); - box_create_enddate_label->setGeometry(120,524,160,20); + box_create_enddate_label->setGeometry(120,536,160,20); box_create_enddate_label->setFont(font); box_create_enddate_label->setAlignment(Qt::AlignVCenter|Qt::AlignRight); box_create_enddate_unit= new QLabel(box_create_enddate_offset_spin,("days"),this); - box_create_enddate_unit->setGeometry(360,524,60,20); + box_create_enddate_unit->setGeometry(345,536,60,20); box_create_enddate_unit->setAlignment(Qt::AlignVCenter|Qt::AlignLeft); connect(box_create_dates_box,SIGNAL(toggled(bool)), this,SLOT(createDatesToggledData(bool))); @@ -451,6 +458,12 @@ EditDropbox::EditDropbox(int id,bool duplicate,QWidget *parent) box_title_from_cartchunk_id_box->setChecked(box_dropbox->titleFromCartchunkId()); box_log_path_edit->setText(box_dropbox->logPath()); box_fix_broken_formats_box->setChecked(box_dropbox->fixBrokenFormats()); + + box_log_to_syslog_check->setChecked(box_dropbox->logToSyslog()); + box_log_path_label->setDisabled(box_dropbox->logToSyslog()); + box_log_path_edit->setDisabled(box_dropbox->logToSyslog()); + box_log_path_button->setDisabled(box_dropbox->logToSyslog()); + box_startoffset_spin->setValue(box_dropbox->startdateOffset()); box_endoffset_spin->setValue(box_dropbox->enddateOffset()); box_create_dates_box->setChecked(box_dropbox->createDates()); @@ -647,6 +660,7 @@ void EditDropbox::okData() } box_dropbox->setUseCartchunkId(box_use_cartchunk_id_box->isChecked()); box_dropbox->setTitleFromCartchunkId(box_title_from_cartchunk_id_box->isChecked()); + box_dropbox->setLogToSyslog(box_log_to_syslog_check->isChecked()); box_dropbox->setLogPath(box_log_path_edit->text()); box_dropbox->setFixBrokenFormats(box_fix_broken_formats_box->isChecked()); box_dropbox->setStartdateOffset(box_startoffset_spin->value()); diff --git a/rdadmin/edit_dropbox.h b/rdadmin/edit_dropbox.h index c0b4a568..4b6da681 100644 --- a/rdadmin/edit_dropbox.h +++ b/rdadmin/edit_dropbox.h @@ -73,7 +73,10 @@ class EditDropbox : public QDialog QLabel *box_force_to_mono_label; QLineEdit *box_metadata_pattern_edit; QLineEdit *box_user_defined_edit; + QCheckBox *box_log_to_syslog_check; + QLabel *box_log_path_label; QLineEdit *box_log_path_edit; + QPushButton *box_log_path_button; QCheckBox *box_delete_source_box; QCheckBox *box_normalization_box; QLabel *box_normalization_level_label; diff --git a/rdadmin/list_dropboxes.cpp b/rdadmin/list_dropboxes.cpp index d36fad89..de171878 100644 --- a/rdadmin/list_dropboxes.cpp +++ b/rdadmin/list_dropboxes.cpp @@ -110,6 +110,8 @@ ListDropboxes::ListDropboxes(const QString &stationname,QWidget *parent) list_dropboxes_view=new RDListView(this); list_dropboxes_view->setFont(list_font); list_dropboxes_view->setAllColumnsShowFocus(true); + list_dropboxes_view->addColumn(tr("ID")); + list_dropboxes_view->setColumnAlignment(0,Qt::AlignVCenter|Qt::AlignRight); list_dropboxes_view->addColumn(tr("Group")); list_dropboxes_view->setColumnAlignment(0,Qt::AlignVCenter|Qt::AlignLeft); list_dropboxes_view->addColumn(tr("Path")); @@ -328,16 +330,22 @@ void ListDropboxes::RefreshItem(RDListViewItem *item) QString sql; RDSqlQuery *q; - sql=QString().sprintf("select DROPBOXES.ID,DROPBOXES.GROUP_NAME,\ - DROPBOXES.PATH,DROPBOXES.NORMALIZATION_LEVEL,\ - DROPBOXES.AUTOTRIM_LEVEL,\ - DROPBOXES.TO_CART,DROPBOXES.USE_CARTCHUNK_ID,\ - DROPBOXES.DELETE_CUTS,DROPBOXES.METADATA_PATTERN,\ - DROPBOXES.FIX_BROKEN_FORMATS,\ - DROPBOXES.SET_USER_DEFINED,GROUPS.COLOR \ - from DROPBOXES left join GROUPS on \ - DROPBOXES.GROUP_NAME=GROUPS.NAME \ - where DROPBOXES.ID=%d",item->id()); + sql=QString("select ")+ + "DROPBOXES.ID,"+ // 00 + "DROPBOXES.GROUP_NAME,"+ // 01 + "DROPBOXES.PATH,"+ // 02 + "DROPBOXES.NORMALIZATION_LEVEL,"+ // 03 + "DROPBOXES.AUTOTRIM_LEVEL,"+ // 04 + "DROPBOXES.TO_CART,"+ // 05 + "DROPBOXES.USE_CARTCHUNK_ID,"+ // 06 + "DROPBOXES.DELETE_CUTS,"+ // 07 + "DROPBOXES.METADATA_PATTERN,"+ // 08 + "DROPBOXES.FIX_BROKEN_FORMATS,"+ // 09 + "DROPBOXES.SET_USER_DEFINED,"+ // 10 + "GROUPS.COLOR "+ // 11 + "from DROPBOXES left join GROUPS on "+ + "DROPBOXES.GROUP_NAME=GROUPS.NAME where "+ + QString().sprintf("DROPBOXES.ID=%d",item->id()); q=new RDSqlQuery(sql); if(q->next()) { WriteItem(item,q); @@ -349,35 +357,36 @@ void ListDropboxes::RefreshItem(RDListViewItem *item) void ListDropboxes::WriteItem(RDListViewItem *item,RDSqlQuery *q) { item->setId(q->value(0).toInt()); - item->setText(0,q->value(1).toString()); - item->setTextColor(0,q->value(11).toString(),QFont::Bold); - item->setText(1,q->value(2).toString()); + item->setText(0,QString().sprintf("%d",q->value(0).toInt())); + item->setText(1,q->value(1).toString()); + item->setTextColor(1,q->value(11).toString(),QFont::Bold); + item->setText(2,q->value(2).toString()); if(q->value(3).toInt()<0) { - item->setText(2,QString().sprintf("%d",q->value(3).toInt()/100)); - } - else { - item->setText(2,tr("[off]")); - } - if(q->value(4).toInt()<0) { - item->setText(3,QString().sprintf("%d",q->value(4).toInt()/100)); + item->setText(3,QString().sprintf("%d",q->value(3).toInt()/100)); } else { item->setText(3,tr("[off]")); } + if(q->value(4).toInt()<0) { + item->setText(4,QString().sprintf("%d",q->value(4).toInt()/100)); + } + else { + item->setText(4,tr("[off]")); + } if(q->value(5).toUInt()>0) { - item->setText(4,QString().sprintf("%06u",q->value(5).toUInt())); + item->setText(5,QString().sprintf("%06u",q->value(5).toUInt())); } else { - item->setText(4,tr("[auto]")); + item->setText(5,tr("[auto]")); } - item->setText(5,q->value(6).toString()); - item->setText(6,q->value(7).toString()); + item->setText(6,q->value(6).toString()); + item->setText(7,q->value(7).toString()); if(q->value(8).toString().isEmpty()) { - item->setText(7,tr("[none]")); + item->setText(8,tr("[none]")); } else { - item->setText(7,q->value(8).toString()); + item->setText(8,q->value(8).toString()); } - item->setText(8,q->value(9).toString()); - item->setText(9,q->value(10).toString()); + item->setText(9,q->value(9).toString()); + item->setText(10,q->value(10).toString()); } diff --git a/rdadmin/list_pypads.cpp b/rdadmin/list_pypads.cpp index 11ed6d49..3bb889b6 100644 --- a/rdadmin/list_pypads.cpp +++ b/rdadmin/list_pypads.cpp @@ -75,6 +75,7 @@ ListPypads::ListPypads(RDStation *station,QWidget *parent) // Instances List Box // list_list_view=new RDListView(this); + list_list_view->setSelectionMode(Q3ListView::Single); list_list_view->setAllColumnsShowFocus(true); list_list_view->setItemMargin(5); list_list_view->addColumn(" "); @@ -198,7 +199,9 @@ void ListPypads::addData() RDListViewItem *item=new RDListViewItem(list_list_view); item->setId(id); RefreshItem(item); + list_list_view->clearSelection(); list_list_view->ensureItemVisible(item); + list_list_view->setCurrentItem(item); item->setSelected(true); RDNotification notify=RDNotification(RDNotification::PypadType, RDNotification::AddAction,id); diff --git a/rdadmin/rdadmin_cs.ts b/rdadmin/rdadmin_cs.ts index 63e28b41..57110b52 100644 --- a/rdadmin/rdadmin_cs.ts +++ b/rdadmin/rdadmin_cs.ts @@ -1294,6 +1294,10 @@ files, causing any whose files remain to be imported again. Segue Length: + + Log events in Syslog + + EditEncoder @@ -4657,6 +4661,10 @@ Jste si jistý, že chcete pokračovat? D&uplicate + + ID + + ListEncoders diff --git a/rdadmin/rdadmin_de.ts b/rdadmin/rdadmin_de.ts index 77ad2a78..79855cca 100644 --- a/rdadmin/rdadmin_de.ts +++ b/rdadmin/rdadmin_de.ts @@ -1218,6 +1218,10 @@ files, causing any whose files remain to be imported again. Segue Length: + + Log events in Syslog + + EditEncoder @@ -4519,6 +4523,10 @@ anzeigen D&uplicate + + ID + + ListEncoders diff --git a/rdadmin/rdadmin_es.ts b/rdadmin/rdadmin_es.ts index 65e8aea2..2a013c75 100644 --- a/rdadmin/rdadmin_es.ts +++ b/rdadmin/rdadmin_es.ts @@ -1296,6 +1296,10 @@ files, causing any whose files remain to be imported again. Segue Length: + + Log events in Syslog + + EditEncoder @@ -4624,6 +4628,10 @@ Are you sure you want to continue? D&uplicate + + ID + + ListEncoders diff --git a/rdadmin/rdadmin_fr.ts b/rdadmin/rdadmin_fr.ts index 41382d65..223a1d6f 100644 --- a/rdadmin/rdadmin_fr.ts +++ b/rdadmin/rdadmin_fr.ts @@ -921,6 +921,10 @@ files, causing any whose files remain to be imported again. Segue Length: + + Log events in Syslog + + EditEndpoint @@ -3770,6 +3774,10 @@ PARTICULAR PURPOSE. Touch the "View License" button for details.D&uplicate + + ID + + ListEndpoints diff --git a/rdadmin/rdadmin_nb.ts b/rdadmin/rdadmin_nb.ts index 7ac6e2e8..60dd71a8 100644 --- a/rdadmin/rdadmin_nb.ts +++ b/rdadmin/rdadmin_nb.ts @@ -1200,6 +1200,10 @@ files, causing any whose files remain to be imported again. Segue Length: + + Log events in Syslog + + EditEncoder @@ -4424,6 +4428,10 @@ Klikk på "Lisens"-knappen for fleire opplysningar. D&uplicate + + ID + + ListEncoders diff --git a/rdadmin/rdadmin_nn.ts b/rdadmin/rdadmin_nn.ts index 7ac6e2e8..60dd71a8 100644 --- a/rdadmin/rdadmin_nn.ts +++ b/rdadmin/rdadmin_nn.ts @@ -1200,6 +1200,10 @@ files, causing any whose files remain to be imported again. Segue Length: + + Log events in Syslog + + EditEncoder @@ -4424,6 +4428,10 @@ Klikk på "Lisens"-knappen for fleire opplysningar. D&uplicate + + ID + + ListEncoders diff --git a/rdadmin/rdadmin_pt_BR.ts b/rdadmin/rdadmin_pt_BR.ts index ead24f5b..c9899026 100644 --- a/rdadmin/rdadmin_pt_BR.ts +++ b/rdadmin/rdadmin_pt_BR.ts @@ -1189,6 +1189,10 @@ files, causing any whose files remain to be imported again. Segue Length: + + Log events in Syslog + + EditEncoder @@ -4499,6 +4503,10 @@ FINALIDADE PARTICULAR. Aperte o botão VER LICENÇA para mais detalhes.D&uplicate + + ID + + ListEncoders diff --git a/rdairplay/loglinebox.cpp b/rdairplay/loglinebox.cpp index 9830b84b..06a2e73b 100644 --- a/rdairplay/loglinebox.cpp +++ b/rdairplay/loglinebox.cpp @@ -430,7 +430,12 @@ void LogLineBox::setEvent(int line,RDLogLine::TransType next_type, case RDLogLine::Cart: line_comment_label->hide(); cart=new RDCart(logline->cartNumber()); - cut=new RDCut(logline->cartNumber(),logline->cutNumber()); + if(logline->cutNumber()>0) { + cut=new RDCut(logline->cartNumber(),logline->cutNumber()); + } + else { + cut=NULL; + } if(!cart->exists()) { line_cart_label-> setText(QString().sprintf("%06u",logline->cartNumber())); @@ -453,15 +458,15 @@ void LogLineBox::setEvent(int line,RDLogLine::TransType next_type, break; } setBackgroundColor(QColor(LOGLINEBOX_MISSING_COLOR)); - delete cart; - delete cut; } else { if(((cart->forcedLength()==0)&&(cart->type()==RDCart::Audio))|| (line_logline->state()==RDLogLine::NoCut)) { line_cart_label-> setText(QString().sprintf("%06u",logline->cartNumber())); - line_description_label->setText(cut->description()); + if(cut!=NULL) { + line_description_label->setText(cut->description()); + } line_artist_label->setText(tr("[NO AUDIO AVAILABLE]")); line_cut_label->clear(); line_group_label->clear(); @@ -474,8 +479,6 @@ void LogLineBox::setEvent(int line,RDLogLine::TransType next_type, line_icon_label->setPixmap(*line_playout_map); line_title_label->setText(logline->title()); setBackgroundColor(QColor(LOGLINEBOX_MISSING_COLOR)); - delete cart; - delete cut; } else { line_cart_label-> @@ -557,13 +560,15 @@ void LogLineBox::setEvent(int line,RDLogLine::TransType next_type, line_cut_label->clear(); line_outcue_label->setText(tr("[NO VALID CUT AVAILABLE]")); } - delete cart; - delete cut; setMode(line_mode); line_title_label->show(); line_artist_label->show(); } } + delete cart; + if(cut!=NULL) { + delete cut; + } break; case RDLogLine::Marker: diff --git a/rdlogmanager/edit_clock.cpp b/rdlogmanager/edit_clock.cpp index ab3dd4c5..50474a09 100644 --- a/rdlogmanager/edit_clock.cpp +++ b/rdlogmanager/edit_clock.cpp @@ -2,7 +2,7 @@ // // Edit Rivendell Log Clock // -// (C) Copyright 2002-2018 Fred Gleason +// (C) Copyright 2002-2019 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 @@ -100,6 +100,7 @@ EditClock::EditClock(QString clockname,bool new_clock, edit_clocks_list->setGeometry(10,35,CENTER_LINE-20,sizeHint().height()-250); edit_clocks_list->setAllColumnsShowFocus(true); edit_clocks_list->setItemMargin(5); + edit_clocks_list->setSorting(-1); edit_clocks_list->addColumn(tr("Start")); edit_clocks_list->addColumn(tr("End")); edit_clocks_list->addColumn(tr("Event")); @@ -288,26 +289,22 @@ void EditClock::addData() { int line=0; RDEventLine eventline(rda->station()); - - RDListViewItem *item=(RDListViewItem *)edit_clocks_list->selectedItem(); - if(item!=NULL) { - if(item->text(4).isEmpty()) { - line=edit_clock->size(); - } - else { - line=item->text(4).toInt(); - } - } EditEventLine *edit_eventline= new EditEventLine(&eventline,edit_clock,-1,this); if(edit_eventline->exec()<0) { return; } delete edit_eventline; - edit_clock->insert(eventline.name(),line); - edit_clock->eventLine(line)->setStartTime(eventline.startTime()); - edit_clock->eventLine(line)->setLength(eventline.length()); - edit_clock->eventLine(line)->load(); + if(line<0) { + line=edit_clock->size(); + } + line=edit_clock-> + insert(eventline.name(),eventline.startTime(),eventline.length()); + if(line<0) { + QMessageBox::warning(this,"RDLogManager - "+tr("Error"), + tr("That event does not exist.")); + return; + } edit_modified=true; RefreshList(line); } @@ -366,10 +363,13 @@ void EditClock::cloneData() return; } delete edit_eventline; - edit_clock->insert(eventline.name(),line); - edit_clock->eventLine(line)->setStartTime(eventline.startTime()); - edit_clock->eventLine(line)->setLength(eventline.length()); - edit_clock->eventLine(line)->load(); + line=edit_clock-> + insert(eventline.name(),eventline.startTime(),eventline.length()); + if(line<0) { + QMessageBox::warning(this,"RDLogManager - "+tr("Error"), + tr("That event does not exist.")); + return; + } edit_modified=true; RefreshList(line); } @@ -525,8 +525,8 @@ void EditClock::doubleClickedData(Q3ListViewItem *item,const QPoint &,int) void EditClock::colorData() { - QColor color=QColorDialog::getColor(edit_color_button->backgroundColor(), - this,"color_dialog"); + QColor color= + QColorDialog::getColor(edit_color_button->backgroundColor(),this); if(color.isValid()) { edit_color_button->setPalette(QPalette(color,backgroundColor())); } @@ -619,18 +619,10 @@ void EditClock::Save() void EditClock::RefreshList(int select_line) { UpdateClock(); - RDListViewItem *prev_item=(RDListViewItem *)edit_clocks_list->selectedItem(); - - if((prev_item!=NULL)&&(select_line>=0)) { - select_line=prev_item->text(4).toInt(); - } RDListViewItem *item; RDEventLine *eventline; edit_clocks_list->clear(); - item=new RDListViewItem(edit_clocks_list); - item->setText(2,tr("--- End of clock ---")); - item->setText(4,"-2"); for(int i=edit_clock->size()-1;i>=0;i--) { if((eventline=edit_clock->eventLine(i))!=NULL) { item=new RDListViewItem(edit_clocks_list); diff --git a/rdlogmanager/rdlogmanager_cs.ts b/rdlogmanager/rdlogmanager_cs.ts index af445208..31294d82 100644 --- a/rdlogmanager/rdlogmanager_cs.ts +++ b/rdlogmanager/rdlogmanager_cs.ts @@ -169,7 +169,7 @@ Chcete je uložit? --- End of clock --- - --- Konec hodin --- + --- Konec hodin --- Invalid Code @@ -208,6 +208,14 @@ Chcete je uložit? Are you sure you want to delete + + Error + + + + That event does not exist. + + EditEvent diff --git a/rdlogmanager/rdlogmanager_de.ts b/rdlogmanager/rdlogmanager_de.ts index fa85d2a2..2d06f001 100644 --- a/rdlogmanager/rdlogmanager_de.ts +++ b/rdlogmanager/rdlogmanager_de.ts @@ -169,7 +169,7 @@ Wollen Sie sie speichern? --- End of clock --- - --- Ende der Uhr --- + --- Ende der Uhr --- Invalid Code @@ -208,6 +208,14 @@ Wollen Sie sie speichern? Are you sure you want to delete + + Error + + + + That event does not exist. + + EditEvent diff --git a/rdlogmanager/rdlogmanager_es.ts b/rdlogmanager/rdlogmanager_es.ts index 5f8180bb..91c15bf4 100644 --- a/rdlogmanager/rdlogmanager_es.ts +++ b/rdlogmanager/rdlogmanager_es.ts @@ -149,7 +149,7 @@ Do you want to save? --- End of clock --- - --- Fin de la torta --- + --- Fin de la torta --- Invalid Code @@ -210,6 +210,14 @@ horario Are you sure you want to delete + + Error + + + + That event does not exist. + + EditEvent diff --git a/rdlogmanager/rdlogmanager_fr.ts b/rdlogmanager/rdlogmanager_fr.ts index e8ffb00d..e18e83bf 100644 --- a/rdlogmanager/rdlogmanager_fr.ts +++ b/rdlogmanager/rdlogmanager_fr.ts @@ -151,10 +151,6 @@ Do you want to save? Clock already exists! Overwrite? - - --- End of clock --- - - Invalid Code @@ -192,6 +188,14 @@ Do you want to save? Are you sure you want to delete + + Error + + + + That event does not exist. + + EditEvent diff --git a/rdlogmanager/rdlogmanager_nb.ts b/rdlogmanager/rdlogmanager_nb.ts index b09a5a1c..63c08ebc 100644 --- a/rdlogmanager/rdlogmanager_nb.ts +++ b/rdlogmanager/rdlogmanager_nb.ts @@ -170,7 +170,7 @@ Vil du lagra? --- End of clock --- - --- Slutt på klokka --- + --- Slutt på klokka --- Invalid Code @@ -209,6 +209,14 @@ Vil du lagra? Are you sure you want to delete + + Error + + + + That event does not exist. + + EditEvent diff --git a/rdlogmanager/rdlogmanager_nn.ts b/rdlogmanager/rdlogmanager_nn.ts index b09a5a1c..63c08ebc 100644 --- a/rdlogmanager/rdlogmanager_nn.ts +++ b/rdlogmanager/rdlogmanager_nn.ts @@ -170,7 +170,7 @@ Vil du lagra? --- End of clock --- - --- Slutt på klokka --- + --- Slutt på klokka --- Invalid Code @@ -209,6 +209,14 @@ Vil du lagra? Are you sure you want to delete + + Error + + + + That event does not exist. + + EditEvent diff --git a/rdlogmanager/rdlogmanager_pt_BR.ts b/rdlogmanager/rdlogmanager_pt_BR.ts index 5dc20915..6774a59b 100644 --- a/rdlogmanager/rdlogmanager_pt_BR.ts +++ b/rdlogmanager/rdlogmanager_pt_BR.ts @@ -175,7 +175,7 @@ Você quer salvar? --- End of clock --- - -- Fim do Relógio -- + -- Fim do Relógio -- Invalid Code @@ -210,6 +210,14 @@ Você quer salvar? Are you sure you want to delete + + Error + + + + That event does not exist. + + EditEvent diff --git a/rdservice/startup.cpp b/rdservice/startup.cpp index 5990c9a0..dd9ecca7 100644 --- a/rdservice/startup.cpp +++ b/rdservice/startup.cpp @@ -210,18 +210,19 @@ bool MainObject::StartDropboxes(QString *err_msg) "DELETE_CUTS,"+ // 08 "METADATA_PATTERN,"+ // 09 "FIX_BROKEN_FORMATS,"+ // 10 - "LOG_PATH,"+ // 11 - "DELETE_SOURCE,"+ // 12 - "STARTDATE_OFFSET,"+ // 13 - "ENDDATE_OFFSET,"+ // 14 - "ID,"+ // 15 - "IMPORT_CREATE_DATES,"+ // 16 - "CREATE_STARTDATE_OFFSET,"+ // 17 - "CREATE_ENDDATE_OFFSET,"+ // 18 - "SET_USER_DEFINED,"+ // 19 - "FORCE_TO_MONO,"+ // 20 - "SEGUE_LEVEL,"+ // 21 - "SEGUE_LENGTH "+ // 22 + "LOG_TO_SYSLOG,"+ // 11 + "LOG_PATH,"+ // 12 + "DELETE_SOURCE,"+ // 13 + "STARTDATE_OFFSET,"+ // 14 + "ENDDATE_OFFSET,"+ // 15 + "ID,"+ // 16 + "IMPORT_CREATE_DATES,"+ // 17 + "CREATE_STARTDATE_OFFSET,"+ // 18 + "CREATE_ENDDATE_OFFSET,"+ // 19 + "SET_USER_DEFINED,"+ // 20 + "FORCE_TO_MONO,"+ // 21 + "SEGUE_LEVEL,"+ // 22 + "SEGUE_LENGTH "+ // 23 "from DROPBOXES where "+ "STATION_NAME=\""+RDEscapeString(rda->config()->stationName())+"\""; q=new RDSqlQuery(sql); @@ -229,7 +230,7 @@ bool MainObject::StartDropboxes(QString *err_msg) QStringList args; args.push_back(QString().sprintf("--persistent-dropbox-id=%d", - q->value(15).toInt())); + q->value(16).toInt())); args.push_back("--drop-box"); sql=QString("select SCHED_CODE from DROPBOX_SCHED_CODES where ")+ QString().sprintf("DROPBOX_ID=%d",q->value(0).toInt()); @@ -249,11 +250,11 @@ bool MainObject::StartDropboxes(QString *err_msg) if(q->value(6).toString()=="Y") { args.push_back("--use-cartchunk-cutid"); } - if(q->value(21).toInt()<1) { + if(q->value(22).toInt()<1) { args.push_back(QString().sprintf("--segue-level=%d", - q->value(21).toInt())); + q->value(22).toInt())); args.push_back(QString().sprintf("--segue-length=%u", - q->value(22).toUInt())); + q->value(23).toUInt())); } if(q->value(7).toString()=="Y") { args.push_back("--title-from-cartchunk-cutid"); @@ -261,7 +262,7 @@ bool MainObject::StartDropboxes(QString *err_msg) if(q->value(8).toString()=="Y") { args.push_back("--delete-cuts"); } - if(q->value(20).toString()=="Y") { + if(q->value(21).toString()=="Y") { args.push_back("--to-mono"); } if(!q->value(9).toString().isEmpty()) { @@ -270,29 +271,29 @@ bool MainObject::StartDropboxes(QString *err_msg) if(q->value(10).toString()=="Y") { args.push_back("--fix-broken-formats"); } - if(q->value(12).toString()=="Y") { + if(q->value(13).toString()=="Y") { args.push_back("--delete-source"); } - if(q->value(16).toString()=="Y") { + if(q->value(17).toString()=="Y") { args.push_back(QString().sprintf("--create-startdate-offset=%d", - q->value(17).toInt())); - args.push_back(QString().sprintf("--create-enddate-offset=%d", q->value(18).toInt())); + args.push_back(QString().sprintf("--create-enddate-offset=%d", + q->value(19).toInt())); } - if(!q->value(19).toString().isEmpty()) { - args.push_back(QString("--set-user-defined=")+q->value(19).toString()); + if(!q->value(20).toString().isEmpty()) { + args.push_back(QString("--set-user-defined=")+q->value(20).toString()); } args.push_back(QString().sprintf("--startdate-offset=%d", - q->value(13).toInt())); - args.push_back(QString().sprintf("--enddate-offset=%d", q->value(14).toInt())); - if(!q->value(11).toString().isEmpty()) { - QFileInfo *fileinfo=new QFileInfo(q->value(11).toString()); - args.push_back(QString().sprintf("--log-filename=%s", - (const char *)fileinfo->fileName())); - args.push_back(QString().sprintf("--log-directory=%s", - (const char *)fileinfo->absolutePath())); - args.push_back("--verbose"); + args.push_back(QString().sprintf("--enddate-offset=%d", + q->value(15).toInt())); + if(RDBool(q->value(11).toString())) { + args.push_back("--log-syslog"); + } + else { + if(!q->value(12).toString().isEmpty()) { + args.push_back("--log-filename="+q->value(12).toString()); + } } args.push_back(q->value(1).toString()); args.push_back(q->value(2).toString()); diff --git a/rivendell.spec.in b/rivendell.spec.in index a1e708b2..664bff1c 100644 --- a/rivendell.spec.in +++ b/rivendell.spec.in @@ -389,6 +389,7 @@ rm -rf $RPM_BUILD_ROOT /etc/pam.d/rivendell /lib/systemd/system/rivendell.service %{_mandir}/man1/rdairplay.1.gz +%{_mandir}/man1/rdalsaconfig.1.gz %{_mandir}/man1/rdclilogedit.1.gz %{_mandir}/man1/rdconvert.1.gz %{_mandir}/man1/rdexport.1.gz diff --git a/utils/rdalsaconfig/Makefile.am b/utils/rdalsaconfig/Makefile.am index 47601e1d..e17a5310 100644 --- a/utils/rdalsaconfig/Makefile.am +++ b/utils/rdalsaconfig/Makefile.am @@ -1,6 +1,6 @@ ## Makefile.am ## -## (C) Copyright 2009,2016-2018 Fred Gleason +## (C) Copyright 2009-2019 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,10 +29,12 @@ moc_%.cpp: %.h bin_PROGRAMS = rdalsaconfig dist_rdalsaconfig_SOURCES = alsaitem.cpp alsaitem.h\ - rdalsa.cpp rdalsa.h\ + rdalsacard.cpp rdalsacard.h\ + rdalsamodel.cpp rdalsamodel.h\ rdalsaconfig.cpp rdalsaconfig.h -nodist_rdalsaconfig_SOURCES = moc_rdalsaconfig.cpp +nodist_rdalsaconfig_SOURCES = moc_rdalsamodel.cpp\ + moc_rdalsaconfig.cpp rdalsaconfig_LDADD = @LIB_RDLIBS@ @LIBVORBIS@ @LIBALSA@ @QT4_LIBS@ -lQt3Support diff --git a/utils/rdalsaconfig/alsaitem.cpp b/utils/rdalsaconfig/alsaitem.cpp index e929b6be..17002e38 100644 --- a/utils/rdalsaconfig/alsaitem.cpp +++ b/utils/rdalsaconfig/alsaitem.cpp @@ -2,7 +2,7 @@ // // QListBoxItem for ALSA PCM devices. // -// (C) Copyright 2009-2018 Fred Gleason +// (C) Copyright 2009-2019 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,38 +29,37 @@ AlsaItem::AlsaItem(Q3ListBox *listbox,const QString &text) AlsaItem::AlsaItem(const QString &text) : Q3ListBoxText(text) { - alsa_card=-1; - alsa_device=-1; + alsa_card_number=-1; + alsa_pcm_number=-1; } AlsaItem::AlsaItem(const AlsaItem &item) { - setText(item.text()); - setCard(item.card()); - setDevice(item.device()); + setCardNumber(item.cardNumber()); + setPcmNumber(item.pcmNumber()); } -int AlsaItem::card() const +int AlsaItem::cardNumber() const { - return alsa_card; + return alsa_card_number; } -void AlsaItem::setCard(int card) +void AlsaItem::setCardNumber(int cardnum) { - alsa_card=card; + alsa_card_number=cardnum; } -int AlsaItem::device() const +int AlsaItem::pcmNumber() const { - return alsa_device; + return alsa_pcm_number; } -void AlsaItem::setDevice(int device) +void AlsaItem::setPcmNumber(int pcmnum) { - alsa_device=device; + alsa_pcm_number=pcmnum; } diff --git a/utils/rdalsaconfig/alsaitem.h b/utils/rdalsaconfig/alsaitem.h index b1feebb7..30cbb8d3 100644 --- a/utils/rdalsaconfig/alsaitem.h +++ b/utils/rdalsaconfig/alsaitem.h @@ -30,14 +30,13 @@ class AlsaItem : public Q3ListBoxText AlsaItem(Q3ListBox *listbox,const QString &text=QString::null); AlsaItem(const QString &text=QString::null); AlsaItem(const AlsaItem &item); - int card() const; - void setCard(int card); - int device() const; - void setDevice(int device); - + int cardNumber() const; + void setCardNumber(int cardnum); + int pcmNumber() const; + void setPcmNumber(int pcmnum); private: - int alsa_card; - int alsa_device; + int alsa_card_number; + int alsa_pcm_number; }; diff --git a/utils/rdalsaconfig/rdalsa.cpp b/utils/rdalsaconfig/rdalsa.cpp deleted file mode 100644 index 87cbbd99..00000000 --- a/utils/rdalsaconfig/rdalsa.cpp +++ /dev/null @@ -1,296 +0,0 @@ -// rdalsa.cpp -// -// Abstract an ALSA configuration. -// -// (C) Copyright 2009-2018 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 - -RDAlsa::RDAlsa() -{ - clear(); -} - - -unsigned RDAlsa::cards() const -{ - return card_ids.size(); -} - - -QString RDAlsa::cardId(unsigned cardnum) const -{ - if(cardnum>=card_ids.size()) { - return QString("[invalid card]"); - } - return card_ids[cardnum]; -} - - -QString RDAlsa::cardDriver(unsigned cardnum) const -{ - if(cardnum>=card_drivers.size()) { - return QString("[invalid card]"); - } - return card_drivers[cardnum]; -} - - -QString RDAlsa::cardName(unsigned cardnum) const -{ - if(cardnum>=card_names.size()) { - return QString("[invalid card]"); - } - return card_names[cardnum]; -} - - -QString RDAlsa::cardLongName(unsigned cardnum) const -{ - if(cardnum>=card_long_names.size()) { - return QString("[invalid card]"); - } - return card_long_names[cardnum]; -} - - -QString RDAlsa::cardMixerName(unsigned cardnum) const -{ - if(cardnum>=card_mixer_names.size()) { - return QString("[invalid card]"); - } - return card_mixer_names[cardnum]; -} - - -int RDAlsa::pcmDevices(unsigned cardnum) const -{ - if(cardnum>=card_pcm_names.size()) { - return -1; - } - return card_pcm_names[cardnum].size(); -} - - -QString RDAlsa::pcmName(unsigned cardnum,unsigned pcm) const -{ - if(cardnum>=card_pcm_names.size()) { - return QString("[invalid pcm device]"); - } - if(pcm>=card_pcm_names[cardnum].size()) { - return QString("[invalid pcm device]"); - } - return card_pcm_names[cardnum][pcm]; -} - - -int RDAlsa::rivendellCard(int slot) const -{ - return card_rivendell_cards[slot]; -} - - -void RDAlsa::setRivendellCard(int slot,int cardnum) -{ - if(slot>=RD_MAX_CARDS) { - return; - } - card_rivendell_cards[slot]=cardnum; -} - - -int RDAlsa::rivendellDevice(int slot) const -{ - return card_rivendell_devices[slot]; -} - - -void RDAlsa::setRivendellDevice(int slot,int devnum) -{ - if(slot>=RD_MAX_CARDS) { - return; - } - card_rivendell_devices[slot]=devnum; -} - - -bool RDAlsa::load(const QString &filename) -{ - LoadSystemConfig(); - return LoadAsoundConfig(filename); -} - - -bool RDAlsa::save(const QString &filename) -{ - return SaveAsoundConfig(filename); -} - - -void RDAlsa::clear() -{ - card_ids.clear(); - card_drivers.clear(); - card_names.clear(); - card_long_names.clear(); - card_mixer_names.clear(); - card_pcm_names.clear(); - for(unsigned i=0;i=0) { - snd_ctl_card_info(snd_ctl,card_info); - card_ids.push_back(snd_ctl_card_info_get_id(card_info)); - card_drivers.push_back(snd_ctl_card_info_get_driver(card_info)); - card_names.push_back(snd_ctl_card_info_get_name(card_info)); - card_long_names.push_back(snd_ctl_card_info_get_longname(card_info)); - card_mixer_names.push_back(snd_ctl_card_info_get_mixername(card_info)); - std::vector pcms; - if(snd_ctl_pcm_info(snd_ctl,pcm_info)==0) { - pcm=0; - while(pcm>=0) { - pcms.push_back(QString().sprintf("%s [%02u]", - (const char *)snd_pcm_info_get_name(pcm_info),pcm+1)); - snd_ctl_pcm_next_device(snd_ctl,&pcm); - } - } - card_pcm_names.push_back(pcms); - snd_ctl_close(snd_ctl); - card++; - } -} - - -bool RDAlsa::LoadAsoundConfig(const QString &filename) -{ - FILE *f=NULL; - char line[1024]; - int istate=0; - int port=0; - int card=0; - int device=0; - QStringList list; - - if((f=fopen(filename,"r"))==NULL) { - return false; - } - while(fgets(line,1024,f)!=NULL) { - QString str=line; - str.replace("\n",""); - if((str!=START_MARKER)&&(str!=END_MARKER)) { - switch(istate) { - case 0: - if(str.left(6)=="pcm.rd") { - port=str.mid(6,1).toInt(); - istate=1; - } - else { - if(str.left(6)=="ctl.rd") { - istate=10; - } - else { - card_other_lines.push_back(str+"\n"); - } - } - break; - - case 1: - list=str.split(" "); - if(list[0]=="}") { - if((port>=0)&&(port=0)&&(card_rivendell_devices[i]>=0)) { - fprintf(f,"pcm.rd%d {\n",i); - fprintf(f," type hw\n"); - fprintf(f," card %d\n",card_rivendell_cards[i]); - fprintf(f," device %d\n",card_rivendell_devices[i]); - fprintf(f,"}\n"); - fprintf(f,"ctl.rd%d {\n",i); - fprintf(f," type hw\n"); - fprintf(f," card %d\n",card_rivendell_cards[i]); - fprintf(f,"}\n"); - } - } - fprintf(f,"%s\n",END_MARKER); - - fclose(f); - return true; -} diff --git a/utils/rdalsaconfig/rdalsa.h b/utils/rdalsaconfig/rdalsa.h deleted file mode 100644 index 399d50fb..00000000 --- a/utils/rdalsaconfig/rdalsa.h +++ /dev/null @@ -1,69 +0,0 @@ -// rdalsa.h -// -// Abstract an ALSA configuration. -// -// (C) Copyright 2009-2018 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 RDALSA_H -#define RDALSA_H - -#include - -#include - -#include - -#define START_MARKER "# *** Start of Rivendell configuration generated by rdalsaconfig(1) ***" -#define END_MARKER "# *** End of Rivendell configuration generated by rdalsaconfig(1) ***" - -class RDAlsa -{ - public: - RDAlsa(); - unsigned cards() const; - QString cardId(unsigned cardnum) const; - QString cardDriver(unsigned cardnum) const; - QString cardName(unsigned cardnum) const; - QString cardLongName(unsigned cardnum) const; - QString cardMixerName(unsigned cardnum) const; - int pcmDevices(unsigned cardnum) const; - QString pcmName(unsigned cardnum,unsigned pcm) const; - int rivendellCard(int slot) const; - void setRivendellCard(int slot,int cardnum); - int rivendellDevice(int slot) const; - void setRivendellDevice(int slot,int devnum); - bool load(const QString &filename); - bool save(const QString &filename); - void clear(); - - private: - void LoadSystemConfig(); - bool LoadAsoundConfig(const QString &filename); - bool SaveAsoundConfig(const QString &filename); - std::vector card_ids; - std::vector card_drivers; - std::vector card_names; - std::vector card_long_names; - std::vector card_mixer_names; - std::vector > card_pcm_names; - int card_rivendell_cards[RD_MAX_CARDS]; - int card_rivendell_devices[RD_MAX_CARDS]; - QStringList card_other_lines; -}; - - -#endif // RDALSA_H diff --git a/utils/rdalsaconfig/rdalsacard.cpp b/utils/rdalsaconfig/rdalsacard.cpp new file mode 100644 index 00000000..b6d31c86 --- /dev/null +++ b/utils/rdalsaconfig/rdalsacard.cpp @@ -0,0 +1,127 @@ +// rdalsacard.cpp +// +// Abstract ALSA 'card' information +// +// (C) Copyright 2019 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 "rdalsacard.h" + +RDAlsaCard::RDAlsaCard(snd_ctl_t *ctl,int index) +{ + snd_ctl_card_info_t *card_info; + snd_pcm_info_t *pcm_info; + int pcm=0; + + card_index=index; + + snd_ctl_card_info_malloc(&card_info); + snd_pcm_info_malloc(&pcm_info); + + snd_ctl_card_info(ctl,card_info); + card_id=QString(snd_ctl_card_info_get_id(card_info)); + card_driver=QString(snd_ctl_card_info_get_driver(card_info)); + card_name=QString(snd_ctl_card_info_get_name(card_info)); + card_long_name=QString(snd_ctl_card_info_get_longname(card_info)); + card_mixer_name=QString(snd_ctl_card_info_get_mixername(card_info)); + if(snd_ctl_pcm_info(ctl,pcm_info)==0) { + pcm=0; + while(pcm>=0) { + card_pcm_names.push_back(snd_pcm_info_get_name(pcm_info)+ + QString().sprintf("[%02d]",pcm+1)); + snd_ctl_pcm_next_device(ctl,&pcm); + card_enableds.push_back(false); + } + } + snd_pcm_info_free(pcm_info); + snd_ctl_card_info_free(card_info); +} + + +int RDAlsaCard::index() const +{ + return card_index; +} + + +QString RDAlsaCard::id() const +{ + return card_id; +} + + +QString RDAlsaCard::driver() const +{ + return card_driver; +} + + +QString RDAlsaCard::name() const +{ + return card_name; +} + + +QString RDAlsaCard::longName() const +{ + return card_long_name; +} + + +QString RDAlsaCard::mixerName() const +{ + return card_long_name; +} + + +bool RDAlsaCard::isEnabled(int pcm_num) const +{ + return card_enableds.at(pcm_num); +} + + +void RDAlsaCard::setEnabled(int pcm_num,bool state) +{ + card_enableds[pcm_num]=state; +} + + +QString RDAlsaCard::dump() const +{ + QString ret=QString().sprintf("Card %d\n",index()); + + ret+=" ID: "+id()+"\n"; + ret+=" Name: "+name()+"\n"; + ret+=" LongName: "+longName()+"\n"; + ret+=" MixerName: "+mixerName()+"\n"; + for(int i=0;i +// +// 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 RDALSACARD_H +#define RDALSACARD_H + +#include + +#include +#include + +class RDAlsaCard +{ + public: + RDAlsaCard(snd_ctl_t *ctl,int index); + int index() const; + QString id() const; + QString driver() const; + QString name() const; + QString longName() const; + QString mixerName() const; + int pcmQuantity() const; + QString pcmName(int n) const; + bool isEnabled(int pcm_num) const; + void setEnabled(int pcm_num,bool state); + QString dump() const; + + private: + int card_index; + QString card_id; + QString card_driver; + QString card_name; + QString card_long_name; + QString card_mixer_name; + QStringList card_pcm_names; + QList card_enableds; +}; + + +#endif // RDALSACARD_H diff --git a/utils/rdalsaconfig/rdalsaconfig.cpp b/utils/rdalsaconfig/rdalsaconfig.cpp index 5c9199fe..62ff65f4 100644 --- a/utils/rdalsaconfig/rdalsaconfig.cpp +++ b/utils/rdalsaconfig/rdalsaconfig.cpp @@ -2,7 +2,7 @@ // // A Qt-based application to display info about ALSA cards. // -// (C) Copyright 2009-2018 Fred Gleason +// (C) Copyright 2009-2019 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 @@ -25,8 +25,11 @@ #include #include +#include #include +#include + #include #include @@ -40,6 +43,7 @@ // QString alsa_filename; bool alsa_autogen=false; +bool alsa_rewrite=false; bool alsa_manage_daemons=false; bool alsa_daemon_start_needed=false; @@ -65,6 +69,8 @@ void StartDaemons() MainWidget::MainWidget(QWidget *parent) : QWidget(parent) { + QString err_msg; + setWindowTitle(tr("RDAlsaConfig")+" v"+VERSION); // @@ -78,6 +84,15 @@ MainWidget::MainWidget(QWidget *parent) setMinimumWidth(sizeHint().width()); setMinimumHeight(sizeHint().height()); + // + // Open the Database + // + rda=new RDApplication("RDAlsaConfig","rdalsaconfig",RDALSACONFIG_USAGE,this); + if(!rda->open(&err_msg,NULL,false)) { + QMessageBox::critical(this,"RDAlsaConfig - "+tr("Error"),err_msg); + exit(1); + } + // // Generate Fonts // @@ -87,36 +102,21 @@ MainWidget::MainWidget(QWidget *parent) label_font.setPixelSize(12); // - // Available Devices + // ALSA Sound Devices // - alsa_system_list=new Q3ListBox(this); + alsa_system_list=new QListView(this); alsa_system_list->setFont(font); + alsa_system_list->setSelectionMode(QAbstractItemView::MultiSelection); alsa_system_label= - new QLabel(alsa_system_list,tr("Available Sound Devices"),this); + new QLabel(alsa_system_list,tr("ALSA Sound Devices"),this); alsa_system_label->setFont(label_font); alsa_system_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); - - // - // Up Button - // - alsa_up_button=new RDTransportButton(RDTransportButton::Up,this); - connect(alsa_up_button,SIGNAL(clicked()),this,SLOT(upData())); - - // - // Down Button - // - alsa_down_button= - new RDTransportButton(RDTransportButton::Down,this); - connect(alsa_down_button,SIGNAL(clicked()),this,SLOT(downData())); - - // - // Selected Devices - // - alsa_config_list=new Q3ListBox(this); - alsa_config_list->setFont(font); - alsa_config_label=new QLabel(alsa_config_list,tr("Active Sound Devices"),this); - alsa_config_label->setFont(label_font); - alsa_config_label->setAlignment(Qt::AlignLeft|Qt::AlignVCenter); + alsa_description_label=new QLabel(this); + alsa_description_label-> + setText(tr("Select the audio devices to dedicate for use with Rivendell. (Devices so dedicated will be unavailable for use with other applications.)")); + alsa_description_label->setFont(font); + alsa_description_label->setAlignment(Qt::AlignLeft|Qt::AlignTop); + alsa_description_label->setWordWrap(true); // // Save Button @@ -135,9 +135,9 @@ MainWidget::MainWidget(QWidget *parent) // // Load Available Devices and Configuration // - alsa_alsa=new RDAlsa(); - alsa_alsa->load(alsa_filename); - LoadList(alsa_system_list,alsa_config_list); + alsa_system_model=new RDAlsaModel(rda->system()->sampleRate(),this); + alsa_system_list->setModel(alsa_system_model); + LoadConfig(alsa_filename); // // Daemon Management @@ -168,7 +168,7 @@ MainWidget::~MainWidget() QSize MainWidget::sizeHint() const { - return QSize(400,300); + return QSize(400,400); } @@ -178,42 +178,12 @@ QSizePolicy MainWidget::sizePolicy() const } -void MainWidget::upData() -{ - MoveItem(alsa_config_list,alsa_system_list); -} - - -void MainWidget::downData() -{ - if(alsa_config_list->count()>=RD_MAX_CARDS) { - return; - } - MoveItem(alsa_system_list,alsa_config_list); -} - - void MainWidget::saveData() { - AlsaItem *item=NULL; + SaveConfig(alsa_filename); - for(int i=0;iitem(i))==NULL) { - alsa_alsa->setRivendellCard(i,-1); - alsa_alsa->setRivendellDevice(i,-1); - } - else { - alsa_alsa->setRivendellCard(i,item->card()); - alsa_alsa->setRivendellDevice(i,item->device()); - } - } - if(!alsa_alsa->save(alsa_filename)) { - QMessageBox::warning(this,tr("RDAlsaConfig error"), - tr(QString("Unable to save configuration to \"")+ - alsa_filename+"\"")); - return; - } StartDaemons(); + qApp->quit(); } @@ -227,14 +197,10 @@ void MainWidget::cancelData() void MainWidget::resizeEvent(QResizeEvent *e) { - alsa_system_label->setGeometry(20,5,size().width()-20,20); + alsa_system_label->setGeometry(10,5,size().width()-20,20); + alsa_description_label->setGeometry(10,25,size().width()-20,50); alsa_system_list-> - setGeometry(10,25,size().width()-20,(size().height()-120)/2); - alsa_up_button->setGeometry(size().width()-120,size().height()/2-28,50,30); - alsa_down_button->setGeometry(size().width()-60,size().height()/2-28,50,30); - alsa_config_label->setGeometry(20,size().height()/2-10,size().width()/2,20); - alsa_config_list->setGeometry(10,size().height()/2+10, - size().width()-20,(size().height()-120)/2); + setGeometry(10,75,size().width()-20,size().height()-130); alsa_save_button-> setGeometry(size().width()-120,size().height()-40,50,30); alsa_cancel_button-> @@ -263,88 +229,188 @@ void MainWidget::closeEvent(QCloseEvent *e) } -void MainWidget::LoadList(Q3ListBox *system,Q3ListBox *config) +void MainWidget::LoadConfig(const QString &filename) { - for(unsigned i=0;icards();i++) { - for(int j=0;jpcmDevices(i);j++) { - if(PcmUnused(i,j)) { - AlsaItem *item= - new AlsaItem(alsa_alsa->cardLongName(i)+" - "+ - alsa_alsa->pcmName(i,j)); - item->setCard(i); - item->setDevice(j); - system->insertItem(item); + if(!alsa_system_model->loadConfig(filename)) { + return; + } + for(int i=0;irowCount();i++) { + if(alsa_system_model->isEnabled(i)) { + alsa_system_list->selectionModel()-> + select(alsa_system_model->index(i,0),QItemSelectionModel::Select); + } + else { + alsa_system_list->selectionModel()-> + select(alsa_system_model->index(i,0),QItemSelectionModel::Deselect); + } + } + + /* + FILE *f=NULL; + char line[1024]; + int istate=0; + int port=0; + QString card_id=0; + int device=0; + QStringList list; + bool active_line=false; + QModelIndex index; + + if((f=fopen(filename.toUtf8(),"r"))==NULL) { + return; + } + while(fgets(line,1024,f)!=NULL) { + QString str=line; + str.replace("\n",""); + if(str==START_MARKER) { + active_line=true; + } + if(str==END_MARKER) { + active_line=false; + } + if((str!=START_MARKER)&&(str!=END_MARKER)) { + if(active_line) { + switch(istate) { + case 0: + if(str.left(6)=="pcm.rd") { + port=str.mid(6,1).toInt(); + istate=1; + } + else { + if(str.left(6)=="ctl.rd") { + istate=10; + } + else { + alsa_other_lines.push_back(str+"\n"); + } + } + break; + + case 1: + list=str.split(" ",QString::SkipEmptyParts); + if(list[0]=="}") { + if((port>=0)&&(portindexOf(card_id,device); + if(index.isValid()) { + alsa_system_list->selectionModel()-> + select(index,QItemSelectionModel::Select); + } + } + card_id=""; + device=0; + istate=0; + } + else { + if(list.size()==2) { + if(list[0]=="card") { + card_id=list[1].trimmed(); + } + if(list[0]=="device") { + device=list[1].toInt(); + } + } + } + break; + + case 10: + if(str.left(1)=="}") { + istate=0; + } + break; + } + } + else { + alsa_other_lines.push_back(str+"\n"); } } } - system->sort(); - - for(int i=0;irivendellCard(i)>=0) { - AlsaItem *item= - new AlsaItem(alsa_alsa->cardLongName(alsa_alsa->rivendellCard(i))+" - "+ - alsa_alsa->pcmName(alsa_alsa->rivendellCard(i), - alsa_alsa->rivendellDevice(i))); - item->setCard(alsa_alsa->rivendellCard(i)); - item->setDevice(alsa_alsa->rivendellDevice(i)); - config->insertItem(item); - } - } - config->sort(); + fclose(f); + */ } -bool MainWidget::PcmUnused(int card,int device) +void MainWidget::SaveConfig(const QString &filename) const { - for(int i=0;irivendellCard(i))&& - (device==alsa_alsa->rivendellDevice(i))) { - return false; - } + for(int i=0;irowCount();i++) { + QItemSelectionModel *sel=alsa_system_list->selectionModel(); + alsa_system_model->setEnabled(i,sel->isRowSelected(i,QModelIndex())); } - return true; -} + alsa_system_model->saveConfig(filename); -void MainWidget::MoveItem(Q3ListBox *src,Q3ListBox *dest) -{ - AlsaItem *item=(AlsaItem *)src->selectedItem(); - if(item==NULL) { + /* + QString tempfile=filename+"-temp"; + FILE *f=NULL; + + if((f=fopen(tempfile.toUtf8(),"w"))==NULL) { return; } - dest->insertItem(new AlsaItem(*item)); // Force a deep copy - dest->sort(); - delete item; + for(int i=0;iselectionModel()->selectedIndexes(); + for(int i=0;icard(indexes.at(i))->id().toUtf8()); + fprintf(f," device %d\n",alsa_system_model->pcmNumber(indexes.at(i))); + fprintf(f," rate %u\n",rda->system()->sampleRate()); + if(alsa_system_model->card(indexes.at(i))->id()=="Axia") { + fprintf(f," channels 2\n"); + } + fprintf(f,"}\n"); + fprintf(f,"ctl.rd%d {\n",i); + fprintf(f," type hw\n"); + fprintf(f," card %s\n", + (const char *)alsa_system_model->card(indexes.at(i))->id().toUtf8()); + fprintf(f,"}\n"); + } + fprintf(f,"%s\n",END_MARKER); + + fclose(f); + rename(tempfile.toUtf8(),filename.toUtf8()); + */ } -Autogen::Autogen(QObject *parent) +Autogen::Autogen() + : QObject() { - StopDaemons(); + QString err_msg; // - // Load Available Devices + // Open the Database // - RDAlsa *alsa=new RDAlsa(); - alsa->load(alsa_filename); - - // - // Build Configuration - // - int slot=0; - for(unsigned i=0;icards();i++) { - for(int j=0;jpcmDevices(i);j++) { - alsa->setRivendellCard(slot,i); - alsa->setRivendellDevice(slot,j); - slot++; - } + rda=new RDApplication("RDAlsaConfig","rdalsaconfig",RDALSACONFIG_USAGE); + if(!rda->open(&err_msg,NULL,false)) { + fprintf(stderr,"rdalsaconfig: unable to open database [%s]\n", + (const char *)err_msg.toUtf8()); + exit(1); } - // - // Save Configuration - // - if(!alsa->save(alsa_filename)) { - exit(256); + StopDaemons(); + + RDAlsaModel *model=new RDAlsaModel(rda->system()->sampleRate()); + if(alsa_rewrite) { + if(!model->loadConfig(alsa_filename)) { + fprintf(stderr,"rdalsaconfig: unable to load file \"%s\"\n", + (const char *)alsa_filename.toUtf8()); + StartDaemons(); + exit(1); + } + } + if(alsa_autogen) { + for(int i=0;irowCount();i++) { + model->setEnabled(i,true); + } + } + if(!model->saveConfig(alsa_filename)) { + fprintf(stderr,"rdalsaconfig: unable to load file \"%s\"\n", + (const char *)alsa_filename.toUtf8()); + StartDaemons(); + exit(1); } StartDaemons(); @@ -368,16 +434,16 @@ int main(int argc,char *argv[]) if(cmd->key(i)=="--autogen") { alsa_autogen=true; } + if(cmd->key(i)=="--rewrite") { + alsa_rewrite=true; + } if(cmd->key(i)=="--manage-daemons") { alsa_manage_daemons=true; } } - // - // Autogenerate a full configuration - // - if(alsa_autogen) { - QApplication a(argc,argv,false); + if(alsa_autogen||alsa_rewrite) { + QCoreApplication a(argc,argv); new Autogen(); return a.exec(); } diff --git a/utils/rdalsaconfig/rdalsaconfig.h b/utils/rdalsaconfig/rdalsaconfig.h index 213070b8..a9be0cfd 100644 --- a/utils/rdalsaconfig/rdalsaconfig.h +++ b/utils/rdalsaconfig/rdalsaconfig.h @@ -2,7 +2,7 @@ // // A Qt-based application to display info about ALSA cards. // -// (C) Copyright 2009-2018 Fred Gleason +// (C) Copyright 2009-2019 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,15 +22,15 @@ #define RDALSACONFIG_H #include -#include +#include #include #include #include -#include +#include "rdalsamodel.h" -#define RDALSACONFIG_USAGE "[--asoundrc-file=] [--autogen] [--manage-daemons]\n\nGenerate an ALSA sound card configuration for Rivendell.\n\nThe following options are available:\n\n --asoundrc-file=\n Read and write configuration from (default value \n \"/etc/asound.conf\").\n\n --autogen\n Generate and save a configuration containing all available PCM devices\n and then exit.\n\n --manage-daemons\n Restart the Rivendell daemons as necessary to make configuration\n changes active (requires root permission).\n\n" +#define RDALSACONFIG_USAGE "[options]\n" void StopDaemons(); void StartDaemons(); @@ -45,8 +45,6 @@ class MainWidget : public QWidget QSizePolicy sizePolicy() const; private slots: - void upData(); - void downData(); void saveData(); void cancelData(); @@ -55,18 +53,15 @@ class MainWidget : public QWidget void closeEvent(QCloseEvent *e); private: - void LoadList(Q3ListBox *system,Q3ListBox *config); - bool PcmUnused(int card,int device); - void MoveItem(Q3ListBox *src,Q3ListBox *dest); + void LoadConfig(const QString &filename); + void SaveConfig(const QString &filename) const; QLabel *alsa_system_label; - Q3ListBox *alsa_system_list; - QLabel *alsa_config_label; - Q3ListBox *alsa_config_list; - RDTransportButton *alsa_up_button; - RDTransportButton *alsa_down_button; + QLabel *alsa_description_label; + QListView *alsa_system_list; + RDAlsaModel *alsa_system_model; + QStringList alsa_other_lines; QPushButton *alsa_save_button; QPushButton *alsa_cancel_button; - RDAlsa *alsa_alsa; }; @@ -74,7 +69,7 @@ class Autogen : public QObject { Q_OBJECT public: - Autogen(QObject *parent=0); + Autogen(); }; diff --git a/utils/rdalsaconfig/rdalsamodel.cpp b/utils/rdalsaconfig/rdalsamodel.cpp new file mode 100644 index 00000000..d793802b --- /dev/null +++ b/utils/rdalsaconfig/rdalsamodel.cpp @@ -0,0 +1,327 @@ +// rdalsamodel.cpp +// +// Abstract an ALSA configuration. +// +// (C) Copyright 2009-2019 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 + +RDAlsaModel::RDAlsaModel(unsigned samprate,QObject *parent) + : QAbstractListModel(parent) +{ + model_sample_rate=samprate; + + LoadSystemConfig(); +} + + +int RDAlsaModel::rowCount(const QModelIndex &parent) const +{ + int rows=0; + + for(int i=0;ipcmQuantity(); + } + + return rows; +} + + +Qt::ItemFlags RDAlsaModel::flags(const QModelIndex &index) const +{ + Qt::ItemFlags flags=QAbstractListModel::flags(index); + + if((model_alsa_cards.at(model_card_index.at(index.row()))->id()=="Axia")&& + (model_sample_rate!=48000)) { + flags=flags&Qt::ItemIsEnabled; + } + + return flags; +} + + +QVariant RDAlsaModel::data(const QModelIndex &index,int role) const +{ + int row=index.row(); + + switch((Qt::ItemDataRole)role) { + case Qt::DisplayRole: + return QVariant(model_alsa_cards.at(model_card_index.at(row))->name()+" - "+ + model_alsa_cards.at(model_card_index.at(row))-> + pcmName(model_pcm_index.at(row))); + break; + + case Qt::DecorationRole: + case Qt::EditRole: + case Qt::ToolTipRole: + case Qt::StatusTipRole: + case Qt::WhatsThisRole: + case Qt::SizeHintRole: + case Qt::FontRole: + case Qt::TextAlignmentRole: + case Qt::BackgroundColorRole: + case Qt::TextColorRole: + case Qt::CheckStateRole: + case Qt::AccessibleTextRole: + case Qt::AccessibleDescriptionRole: + case Qt::InitialSortOrderRole: + case Qt::DisplayPropertyRole: + case Qt::DecorationPropertyRole: + case Qt::ToolTipPropertyRole: + case Qt::StatusTipPropertyRole: + case Qt::WhatsThisPropertyRole: + case Qt::UserRole: + break; + } + + return QVariant(); +} + + +QVariant RDAlsaModel::headerData(int section,Qt::Orientation orient, + int role) const +{ + switch(orient) { + case Qt::Horizontal: + return QVariant(tr("ALSA Devices")); + + case Qt::Vertical: + break; + } + + return QVariant(); +} + + +QModelIndex RDAlsaModel::indexOf(const QString &card_id,int pcm_num) const +{ + bool ok=false; + int cardnum=card_id.toUInt(&ok); + + if(ok) { + for(int i=0;iid()==card_id)&& + (model_pcm_index.at(i)==pcm_num)) { + return createIndex(i,0); + } + } + } + + return QModelIndex(); +} + + +RDAlsaCard *RDAlsaModel::card(const QModelIndex &index) const +{ + return model_alsa_cards.at(model_card_index.at(index.row())); +} + + +int RDAlsaModel::pcmNumber(const QModelIndex &index) const +{ + return model_pcm_index.at(index.row()); +} + + +bool RDAlsaModel::isEnabled(int row) const +{ + return model_alsa_cards.at(model_card_index.at(row))-> + isEnabled(model_pcm_index.at(row)); +} + + +void RDAlsaModel::setEnabled(int row,bool state) +{ + return model_alsa_cards.at(model_card_index.at(row))-> + setEnabled(model_pcm_index.at(row),state); +} + + +bool RDAlsaModel::loadConfig(const QString &filename) +{ + FILE *f=NULL; + char line[1024]; + int istate=0; + int port=0; + QString card_id=0; + int card_num=0; + bool ok=false; + int device=0; + QStringList list; + bool active_line=false; + QModelIndex index; + + if((f=fopen(filename.toUtf8(),"r"))==NULL) { + return false; + } + while(fgets(line,1024,f)!=NULL) { + QString str=line; + str.replace("\n",""); + if(str==START_MARKER) { + active_line=true; + } + if(str==END_MARKER) { + active_line=false; + } + if((str!=START_MARKER)&&(str!=END_MARKER)) { + if(active_line) { + switch(istate) { + case 0: + if(str.left(6)=="pcm.rd") { + port=str.mid(6,1).toInt(); + istate=1; + } + else { + if(str.left(6)=="ctl.rd") { + istate=10; + } + else { + model_other_lines.push_back(str+"\n"); + } + } + break; + + case 1: + list=str.split(" ",QString::SkipEmptyParts); + if(list[0]=="}") { + if((port>=0)&&(portindex()) { + if((device>=0)&&(devicepcmQuantity())) { + card->setEnabled(device,true); + } + } + } + else { + if(card_id==card->id()) { + if((device>=0)&&(devicepcmQuantity())) { + card->setEnabled(device,true); + } + } + } + } + } + card_id=""; + device=0; + istate=0; + } + else { + if(list.size()==2) { + if(list[0]=="card") { + card_id=list[1].trimmed(); + } + if(list[0]=="device") { + device=list[1].toInt(); + } + } + } + break; + + case 10: + if(str.left(1)=="}") { + istate=0; + } + break; + } + } + else { + model_other_lines.push_back(str+"\n"); + } + } + } + fclose(f); + + return true; +} + + +bool RDAlsaModel::saveConfig(const QString &filename) +{ + QString tempfile=filename+"-temp"; + FILE *f=NULL; + int index=0; + + if((f=fopen(tempfile.toUtf8(),"w"))==NULL) { + return false; + } + for(int i=0;ipcmQuantity();j++) { + if(card->isEnabled(j)) { + fprintf(f,"pcm.rd%d {\n",index); + fprintf(f," type hw\n"); + fprintf(f," card %s\n",(const char *)card->id().toUtf8()); + fprintf(f," device %d\n",j); + fprintf(f," rate %u\n",rda->system()->sampleRate()); + if(card->id()=="Axia") { + fprintf(f," channels 2\n"); + } + fprintf(f,"}\n"); + fprintf(f,"ctl.rd%d {\n",index); + fprintf(f," type hw\n"); + fprintf(f," card %s\n",(const char *)card->id().toUtf8()); + fprintf(f,"}\n"); + index++; + } + } + } + fprintf(f,"%s\n",END_MARKER); + + fclose(f); + rename(tempfile.toUtf8(),filename.toUtf8()); + + return true; +} + + +void RDAlsaModel::LoadSystemConfig() +{ + snd_ctl_t *snd_ctl=NULL; + int index=0; + + while(snd_ctl_open(&snd_ctl,QString().sprintf("hw:%d",index),0)>=0) { + model_alsa_cards.push_back(new RDAlsaCard(snd_ctl,index)); + for(int i=0;ipcmQuantity();i++) { + model_card_index.push_back(index); + model_pcm_index.push_back(i); + } + snd_ctl_close(snd_ctl); + index++; + } +} diff --git a/utils/rdalsaconfig/rdalsamodel.h b/utils/rdalsaconfig/rdalsamodel.h new file mode 100644 index 00000000..e53c745d --- /dev/null +++ b/utils/rdalsaconfig/rdalsamodel.h @@ -0,0 +1,63 @@ +// rdalsamodel.h +// +// Abstract an ALSA configuration. +// +// (C) Copyright 2009-2018 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 RDALSAMODEL_H +#define RDALSAMODEL_H + +#include +#include +#include + +#include + +#include "rdalsacard.h" + +#define START_MARKER "# *** Start of Rivendell configuration generated by rdalsaconfig(1) ***" +#define END_MARKER "# *** End of Rivendell configuration generated by rdalsaconfig(1) ***" + +class RDAlsaModel : public QAbstractListModel +{ + Q_OBJECT; + public: + RDAlsaModel(unsigned samprate,QObject *parent=0); + int rowCount(const QModelIndex &parent=QModelIndex()) const; + Qt::ItemFlags flags(const QModelIndex &index) const; + QVariant data(const QModelIndex &index,int role=Qt::DisplayRole) const; + QVariant headerData(int section,Qt::Orientation orient, + int role=Qt::DisplayRole) const; + QModelIndex indexOf(const QString &card_id,int pcm_num) const; + RDAlsaCard *card(const QModelIndex &index) const; + int pcmNumber(const QModelIndex &index) const; + bool isEnabled(int row) const; + void setEnabled(int row,bool state); + bool loadConfig(const QString &filename); + bool saveConfig(const QString &filename); + + private: + void LoadSystemConfig(); + QList model_alsa_cards; + QList model_card_index; + QList model_pcm_index; + unsigned model_sample_rate; + QStringList model_other_lines; +}; + + +#endif // RDALSAMODEL_H diff --git a/utils/rddbmgr/revertschema.cpp b/utils/rddbmgr/revertschema.cpp index 5b447220..33279d30 100644 --- a/utils/rddbmgr/revertschema.cpp +++ b/utils/rddbmgr/revertschema.cpp @@ -40,6 +40,19 @@ bool MainObject::RevertSchema(int cur_schema,int set_schema,QString *err_msg) // NEW SCHEMA REVERSIONS GO HERE... + + // + // Revert 309 + // + if((cur_schema==309)&&(set_schemacur_schema)) { + sql=QString("alter table DROPBOXES add column ")+ + "LOG_TO_SYSLOG enum('N','Y') not null "+ + "default 'Y' after FIX_BROKEN_FORMATS"; + if(!RDSqlQuery::apply(sql,err_msg)) { + return false; + } + sql=QString("update DROPBOXES set LOG_TO_SYSLOG='N' where ")+ + "LOG_PATH is not null"; + if(!RDSqlQuery::apply(sql,err_msg)) { + return false; + } + + WriteSchemaVersion(++cur_schema); + } + // NEW SCHEMA UPDATES GO HERE... diff --git a/utils/rdimport/rdimport.cpp b/utils/rdimport/rdimport.cpp index dae818bf..03010619 100644 --- a/utils/rdimport/rdimport.cpp +++ b/utils/rdimport/rdimport.cpp @@ -36,10 +36,11 @@ #include #include -#include #include +#include #include #include +#include #include #include #include @@ -72,7 +73,6 @@ MainObject::MainObject(QObject *parent) import_verbose=false; import_log_syslog=false; import_log_file=false; - import_log_directory=""; import_log_filename=""; import_single_cart=false; import_use_cartchunk_cutid=false; @@ -123,10 +123,6 @@ MainObject::MainObject(QObject *parent) import_log_syslog=true; rda->cmdSwitch()->setProcessed(i,true); } - if(rda->cmdSwitch()->key(i)=="--log-directory") { - import_log_directory=rda->cmdSwitch()->value(i); - rda->cmdSwitch()->setProcessed(i,true); - } if(rda->cmdSwitch()->key(i)=="--log-filename") { import_log_filename=rda->cmdSwitch()->value(i); rda->cmdSwitch()->setProcessed(i,true); @@ -434,6 +430,7 @@ MainObject::MainObject(QObject *parent) Log(LOG_ERR,QString().sprintf("rdimport: --metadata-pattern and --xml are mutually exclusive\n")); exit(255); } + /* if((!import_log_directory.isEmpty())&&import_log_filename.isEmpty()) { Log(LOG_ERR,QString().sprintf("rdimport: --log-directory requires --log-filename\n")); exit(255); @@ -442,6 +439,7 @@ MainObject::MainObject(QObject *parent) Log(LOG_ERR,QString().sprintf("rdimport: --log-filename requires --log-directory\n")); exit(255); } + */ if((!import_log_filename.isEmpty())&&import_log_syslog) { Log(LOG_ERR,QString().sprintf("rdimport: --log-filename and --log-syslog are mutually exclusive\n")); exit(255); @@ -581,181 +579,179 @@ MainObject::MainObject(QObject *parent) // // Print Status Messages // - if(import_verbose) { - Log(LOG_INFO,QString("rdimport started\n")); + Log(LOG_INFO,QString("rdimport started\n")); - Log(LOG_INFO,QString().sprintf("RDImport v%s\n",VERSION)); - if(import_to_mono) { - Log(LOG_INFO,QString(" Force to Mono is ON\n")); + Log(LOG_INFO,QString().sprintf("RDImport v%s\n",VERSION)); + if(import_to_mono) { + Log(LOG_INFO,QString(" Force to Mono is ON\n")); + } + else { + Log(LOG_INFO,QString(" Force to Mono is OFF\n")); + } + if(import_normalization_level==0) { + Log(LOG_INFO,QString(" Normalization is OFF\n")); + } + else { + Log(LOG_INFO,QString().sprintf(" Normalization level = %d dB\n",import_normalization_level/100)); + } + if(import_autotrim_level==0) { + Log(LOG_INFO,QString(" AutoTrim is OFF\n")); + } + else { + Log(LOG_INFO,QString().sprintf(" AutoTrim level = %d dB\n",import_autotrim_level/100)); + } + if(import_cart_number==0) { + if(import_use_cartchunk_cutid) { + Log(LOG_INFO,QString(" Destination cart is taken from CartChunk CutID\n")); } else { - Log(LOG_INFO,QString(" Force to Mono is OFF\n")); + Log(LOG_INFO,QString(" Destination cart is AUTO\n")); } - if(import_normalization_level==0) { - Log(LOG_INFO,QString(" Normalization is OFF\n")); - } - else { - Log(LOG_INFO,QString().sprintf(" Normalization level = %d dB\n",import_normalization_level/100)); - } - if(import_autotrim_level==0) { - Log(LOG_INFO,QString(" AutoTrim is OFF\n")); - } - else { - Log(LOG_INFO,QString().sprintf(" AutoTrim level = %d dB\n",import_autotrim_level/100)); - } - if(import_cart_number==0) { - if(import_use_cartchunk_cutid) { - Log(LOG_INFO,QString(" Destination cart is taken from CartChunk CutID\n")); - } - else { - Log(LOG_INFO,QString(" Destination cart is AUTO\n")); - } - } - else { - Log(LOG_INFO,QString().sprintf(" Destination cart is %06u\n",import_cart_number)); - } - if(import_single_cart) { - Log(LOG_INFO,QString(" Single cart mode is ON\n")); - } - else { - Log(LOG_INFO,QString(" Single cart mode is OFF\n")); - } - if(import_title_from_cartchunk_cutid) { - Log(LOG_INFO,QString(" Destination cart title is taken from CartChunk CutID\n")); - } - if(import_cart_number_offset!=0) { - Log(LOG_INFO,QString().sprintf(" Cart number offset is %d\n",import_cart_number_offset)); - } - if(import_delete_source) { - Log(LOG_INFO,QString(" Delete source mode is ON\n")); - } - else { - Log(LOG_INFO,QString(" Delete source mode is OFF\n")); - } - if(import_delete_cuts) { - Log(LOG_INFO,QString(" Delete cuts mode is ON\n")); - } - else { - Log(LOG_INFO,QString(" Delete cuts mode is OFF\n")); - } - if(import_drop_box) { - Log(LOG_INFO,QString(" DropBox mode is ON\n")); - } - else { - Log(LOG_INFO,QString(" DropBox mode is OFF\n")); - } - if(import_add_scheduler_codes.size()>0) { - Log(LOG_INFO,QString(" Adding Scheduler Code(s):\n")); - for(unsigned i=0;i=0) { - Log(LOG_INFO,QString().sprintf(" Persistent DropBox ID = %d\n",import_persistent_dropbox_id)); - } - if(!import_string_agency.isNull()) { - Log(LOG_INFO,QString().sprintf(" Agency set to: %s\n",(const char *)import_string_agency)); - } - if(!import_string_album.isNull()) { - Log(LOG_INFO,QString().sprintf(" Album set to: %s\n",(const char *)import_string_album)); - } - if(!import_string_artist.isNull()) { - Log(LOG_INFO,QString().sprintf(" Artist set to: %s\n",(const char *)import_string_artist)); - } - if(import_string_bpm!=0) { - Log(LOG_INFO,QString().sprintf(" BPM set to: %d\n",import_string_bpm)); - } - if(!import_string_client.isNull()) { - Log(LOG_INFO,QString().sprintf(" Client set to: %s\n",(const char *)import_string_client)); - } - if(!import_string_composer.isNull()) { - Log(LOG_INFO,QString().sprintf(" Composer set to: %s\n",(const char *)import_string_composer)); - } - if(!import_string_conductor.isNull()) { - Log(LOG_INFO,QString().sprintf(" Conductor set to: %s\n",(const char *)import_string_conductor)); - } - if(!import_string_description.isNull()) { - Log(LOG_INFO,QString().sprintf(" Description set to: %s\n", - (const char *)import_string_description)); - } - if(!import_string_label.isNull()) { - Log(LOG_INFO,QString().sprintf(" Label set to: %s\n",(const char *)import_string_label)); - } - if(!import_string_outcue.isNull()) { - Log(LOG_INFO,QString().sprintf(" Outcue set to: %s\n",(const char *)import_string_outcue)); - } - if(!import_string_publisher.isNull()) { - Log(LOG_INFO,QString().sprintf(" Publisher set to: %s\n",(const char *)import_string_publisher)); - } - if(!import_string_song_id.isNull()) { - Log(LOG_INFO,QString().sprintf(" Song ID set to: %s\n",(const char *)import_string_song_id)); - } - if(!import_string_title.isNull()) { - Log(LOG_INFO,QString().sprintf(" Title set to: %s\n",(const char *)import_string_title)); - } - if(!import_string_user_defined.isNull()) { - Log(LOG_INFO,QString().sprintf(" User Defined set to: %s\n", - (const char *)import_string_user_defined)); - } - if(import_string_year!=0) { - Log(LOG_INFO,QString().sprintf(" Year set to: %d\n",import_string_year)); - } - if(import_xml) { - Log(LOG_INFO,QString().sprintf(" Importing RDXML metadata from external file\n")); - } - import_cut_markers->dump(); - import_talk_markers->dump(); - import_hook_markers->dump(); - import_segue_markers->dump(); - import_fadedown_marker->dump(); - import_fadeup_marker->dump(); - Log(LOG_INFO,QString(" Files to process:\n")); - for(unsigned i=import_file_key;icmdSwitch()->keys();i++) { - Log(LOG_INFO,QString().sprintf(" \"%s\"\n",(const char *)rda->cmdSwitch()->key(i))); + } + else { + Log(LOG_INFO,QString().sprintf(" Destination cart is %06u\n",import_cart_number)); + } + if(import_single_cart) { + Log(LOG_INFO,QString(" Single cart mode is ON\n")); + } + else { + Log(LOG_INFO,QString(" Single cart mode is OFF\n")); + } + if(import_title_from_cartchunk_cutid) { + Log(LOG_INFO,QString(" Destination cart title is taken from CartChunk CutID\n")); + } + if(import_cart_number_offset!=0) { + Log(LOG_INFO,QString().sprintf(" Cart number offset is %d\n",import_cart_number_offset)); + } + if(import_delete_source) { + Log(LOG_INFO,QString(" Delete source mode is ON\n")); + } + else { + Log(LOG_INFO,QString(" Delete source mode is OFF\n")); + } + if(import_delete_cuts) { + Log(LOG_INFO,QString(" Delete cuts mode is ON\n")); + } + else { + Log(LOG_INFO,QString(" Delete cuts mode is OFF\n")); + } + if(import_drop_box) { + Log(LOG_INFO,QString(" DropBox mode is ON\n")); + } + else { + Log(LOG_INFO,QString(" DropBox mode is OFF\n")); + } + if(import_add_scheduler_codes.size()>0) { + Log(LOG_INFO,QString(" Adding Scheduler Code(s):\n")); + for(unsigned i=0;i=0) { + Log(LOG_INFO,QString().sprintf(" Persistent DropBox ID = %d\n",import_persistent_dropbox_id)); + } + if(!import_string_agency.isNull()) { + Log(LOG_INFO,QString().sprintf(" Agency set to: %s\n",(const char *)import_string_agency)); + } + if(!import_string_album.isNull()) { + Log(LOG_INFO,QString().sprintf(" Album set to: %s\n",(const char *)import_string_album)); + } + if(!import_string_artist.isNull()) { + Log(LOG_INFO,QString().sprintf(" Artist set to: %s\n",(const char *)import_string_artist)); + } + if(import_string_bpm!=0) { + Log(LOG_INFO,QString().sprintf(" BPM set to: %d\n",import_string_bpm)); + } + if(!import_string_client.isNull()) { + Log(LOG_INFO,QString().sprintf(" Client set to: %s\n",(const char *)import_string_client)); + } + if(!import_string_composer.isNull()) { + Log(LOG_INFO,QString().sprintf(" Composer set to: %s\n",(const char *)import_string_composer)); + } + if(!import_string_conductor.isNull()) { + Log(LOG_INFO,QString().sprintf(" Conductor set to: %s\n",(const char *)import_string_conductor)); + } + if(!import_string_description.isNull()) { + Log(LOG_INFO,QString().sprintf(" Description set to: %s\n", + (const char *)import_string_description)); + } + if(!import_string_label.isNull()) { + Log(LOG_INFO,QString().sprintf(" Label set to: %s\n",(const char *)import_string_label)); + } + if(!import_string_outcue.isNull()) { + Log(LOG_INFO,QString().sprintf(" Outcue set to: %s\n",(const char *)import_string_outcue)); + } + if(!import_string_publisher.isNull()) { + Log(LOG_INFO,QString().sprintf(" Publisher set to: %s\n",(const char *)import_string_publisher)); + } + if(!import_string_song_id.isNull()) { + Log(LOG_INFO,QString().sprintf(" Song ID set to: %s\n",(const char *)import_string_song_id)); + } + if(!import_string_title.isNull()) { + Log(LOG_INFO,QString().sprintf(" Title set to: %s\n",(const char *)import_string_title)); + } + if(!import_string_user_defined.isNull()) { + Log(LOG_INFO,QString().sprintf(" User Defined set to: %s\n", + (const char *)import_string_user_defined)); + } + if(import_string_year!=0) { + Log(LOG_INFO,QString().sprintf(" Year set to: %d\n",import_string_year)); + } + if(import_xml) { + Log(LOG_INFO,QString().sprintf(" Importing RDXML metadata from external file\n")); + } + import_cut_markers->dump(); + import_talk_markers->dump(); + import_hook_markers->dump(); + import_segue_markers->dump(); + import_fadedown_marker->dump(); + import_fadeup_marker->dump(); + Log(LOG_INFO,QString(" Files to process:\n")); + for(unsigned i=import_file_key;icmdSwitch()->keys();i++) { + Log(LOG_INFO,QString().sprintf(" \"%s\"\n",(const char *)rda->cmdSwitch()->key(i))); + } // // Setup Signal Handling @@ -845,11 +841,8 @@ void MainObject::userData() // Clean Up and Exit // delete import_group; - // delete import_cmd; - if(import_verbose) { - Log(LOG_INFO,QString("rdimport finished\n")); - } + Log(LOG_INFO,QString("rdimport finished\n")); exit(0); } @@ -898,9 +891,7 @@ void MainObject::RunDropBox() sleep(RDIMPORT_DROPBOX_SCAN_INTERVAL); } while(import_run); - if(import_verbose) { - Log(LOG_INFO,QString("rdimport stopped\n")); - } + Log(LOG_INFO,QString("rdimport stopped\n")); } @@ -971,15 +962,11 @@ MainObject::Result MainObject::ImportFile(const QString &filename, } else { if(import_fix_broken_formats) { - if(import_verbose) { - Log(LOG_WARNING,QString().sprintf(" File \"%s\" appears to be malformed, trying workaround ... ", - (const char *)RDGetBasePart(filename).utf8())); - } + Log(LOG_WARNING,QString().sprintf(" File \"%s\" appears to be malformed, trying workaround ... ", + (const char *)RDGetBasePart(filename).utf8())); delete wavefile; if((wavefile=FixFile(filename,wavedata))==NULL) { - if(import_verbose) { - Log(LOG_WARNING,QString().sprintf("failed.\n")); - } + Log(LOG_WARNING,QString().sprintf("failed.\n")); Log(LOG_WARNING,QString().sprintf( " File \"%s\" is not readable or not a recognized format, skipping...\n", (const char *)RDGetBasePart(filename).utf8())); @@ -996,9 +983,7 @@ MainObject::Result MainObject::ImportFile(const QString &filename, } return MainObject::FileBad; } - if(import_verbose) { - Log(LOG_WARNING,QString().sprintf("success.\n")); - } + Log(LOG_WARNING,QString().sprintf("success.\n")); effective_filename=import_temp_fix_filename; } else { @@ -1122,33 +1107,29 @@ MainObject::Result MainObject::ImportFile(const QString &filename, settings->setAutotrimLevel(import_autotrim_level/100); conv->setDestinationSettings(settings); conv->setUseMetadata(cart_created); - if(import_verbose) { - if(wavedata->title().length()==0 || ( (wavedata->title().length()>0) && (wavedata->title()[0] == '\0')) ) { - Log(LOG_INFO,QString().sprintf(" Importing file \"%s\" to cart %06u ... ", - (const char *)RDGetBasePart(filename).utf8(),*cartnum)); + if(wavedata->title().length()==0 || ( (wavedata->title().length()>0) && (wavedata->title()[0] == '\0')) ) { + Log(LOG_INFO,QString().sprintf(" Importing file \"%s\" to cart %06u ... ", + (const char *)RDGetBasePart(filename).utf8(),*cartnum)); + } + else { + if(import_string_title.isNull()) { + Log(LOG_INFO,QString().sprintf(" Importing file \"%s\" [%s] to cart %06u ... ", + (const char *)RDGetBasePart(filename).utf8(), + (const char *)wavedata->title().stripWhiteSpace().utf8(), + *cartnum)); } else { - if(import_string_title.isNull()) { - Log(LOG_INFO,QString().sprintf(" Importing file \"%s\" [%s] to cart %06u ... ", - (const char *)RDGetBasePart(filename).utf8(), - (const char *)wavedata->title().stripWhiteSpace().utf8(), - *cartnum)); - } - else { - Log(LOG_INFO,QString().sprintf(" Importing file \"%s\" [%s] to cart %06u ... ", - (const char *)RDGetBasePart(filename).utf8(), - (const char *)import_string_title.stripWhiteSpace().utf8(), - *cartnum)); - } + Log(LOG_INFO,QString().sprintf(" Importing file \"%s\" [%s] to cart %06u ... ", + (const char *)RDGetBasePart(filename).utf8(), + (const char *)import_string_title.stripWhiteSpace().utf8(), + *cartnum)); } } switch(conv_err=conv->runImport(rda->user()->name(),rda->user()->password(), &audio_conv_err)) { case RDAudioImport::ErrorOk: - if(import_verbose) { - Log(LOG_INFO,QString().sprintf("done.\n")); - } + Log(LOG_INFO,QString().sprintf("done.\n")); break; default: @@ -1356,9 +1337,7 @@ MainObject::Result MainObject::ImportFile(const QString &filename, if(import_delete_source) { unlink(filename.utf8()); - if(import_verbose) { - Log(LOG_INFO,QString().sprintf(" Deleted file \"%s\"\n",(const char *)RDGetBasePart(filename).utf8())); - } + Log(LOG_INFO,QString().sprintf(" Deleted file \"%s\"\n",(const char *)RDGetBasePart(filename).utf8())); } if(!import_run) { exit(0); @@ -1887,9 +1866,8 @@ bool MainObject::VerifyPattern(const QString &pattern) void MainObject::DeleteCuts(unsigned cartnum) { - if(import_verbose) { - Log(LOG_INFO,QString().sprintf(" Deleting cuts from cart %06u\n",cartnum)); - } + Log(LOG_INFO,QString().sprintf(" Deleting cuts from cart %06u\n",cartnum)); + unsigned dev; RDCart *cart=new RDCart(cartnum); cart->removeAllCuts(rda->station(),rda->user(),rda->config()); @@ -1978,23 +1956,17 @@ void MainObject::ReadXmlFile(const QString &basename,RDWaveData *wavedata) const xmlname+=f0[i]+"."; } xmlname+="xml"; - if(import_verbose) { - Log(LOG_INFO,QString().sprintf(" Reading xml metadata from \"%s\": ",(const char *)xmlname)); - } + Log(LOG_INFO,QString().sprintf(" Reading xml metadata from \"%s\": ",(const char *)xmlname)); // // Read XML // wavedata->clear(); if((f=fopen(xmlname,"r"))==NULL) { - if(import_verbose) { - Log(LOG_WARNING,QString().sprintf("failed [%s]\n",strerror(errno))); - return; - } - } - if(import_verbose) { - Log(LOG_INFO,QString("success\n")); + Log(LOG_WARNING,QString().sprintf("failed [%s]\n",strerror(errno))); + return; } + Log(LOG_INFO,QString("success\n")); while(fgets(line,1024,f)!=NULL) { xml+=line; } @@ -2023,16 +1995,30 @@ void MainObject::SendNotification(RDNotification::Action action, void MainObject::Log(int prio,const QString &msg) const { QString m=msg; + FILE *f=NULL; - if (import_drop_box||import_log_syslog||import_log_file) { - rda->syslog(prio,m.replace(QRegExp("^rdimport: "),"").simplified()); + if(import_log_syslog) { + rda->syslog(prio,msg.trimmed()); + } + if(!import_log_filename.isEmpty()) { + QDateTime now=QDateTime::currentDateTime(); + QString filename=RDDateDecode(import_log_filename,now.date(), + rda->station(),rda->config()); + if((f=fopen(filename.toUtf8(),"a"))!=NULL) { + fprintf(f,"%s: %s", + (const char *)now.toString("MMM dd hh:mm:ss").toUtf8(), + (const char *)msg.toUtf8()); + fflush(f); + fclose(f); + } + } + + if(prio==LOG_ERR) { + fprintf(stderr,"%s",(const char *)msg); + fflush(stderr); } else { - if(prio==LOG_ERR) { - fprintf(stderr,"%s",(const char *)msg); - fflush(stderr); - } - else { + if(import_verbose) { fprintf(stdout,"%s",(const char *)msg); fflush(stdout); } diff --git a/utils/rdimport/rdimport.h b/utils/rdimport/rdimport.h index 7bf8019b..d682745b 100644 --- a/utils/rdimport/rdimport.h +++ b/utils/rdimport/rdimport.h @@ -2,7 +2,7 @@ // // A Batch Importer for Rivendell. // -// (C) Copyright 2002-2009,2016-2018 Fred Gleason +// (C) Copyright 2002-2019 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 @@ -80,7 +80,7 @@ class MainObject : public QObject bool import_verbose; bool import_log_syslog; bool import_log_file; - QString import_log_directory; + // QString import_log_directory; QString import_log_filename; bool import_to_mono; bool import_use_cartchunk_cutid;