diff options
author | Ulrich Eckhardt <vdr@uli-eckhardt.de> | 2017-04-23 16:10:16 +0200 |
---|---|---|
committer | Ulrich Eckhardt <vdr@uli-eckhardt.de> | 2017-04-23 16:10:16 +0200 |
commit | 1dbb7611337dc4b61817cad734a47b1a0404b77c (patch) | |
tree | e9b41e387c25c05678d84ce388f9e1977ff18f84 | |
download | vdr-plugin-radio-1dbb7611337dc4b61817cad734a47b1a0404b77c.tar.gz vdr-plugin-radio-1dbb7611337dc4b61817cad734a47b1a0404b77c.tar.bz2 |
Import of original Radio Plugin 1.0.01.0.0
78 files changed, 10541 insertions, 0 deletions
@@ -0,0 +1,340 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + <one line to give the program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) year name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + <signature of Ty Coon>, 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. @@ -0,0 +1,267 @@ +VDR Plugin 'radio' Revision History +----------------------------------- +2013-05-31: Version 1.0.0 + U.Hanke <egal@gmx.info> +- Security-patch formatstrings, thanks to Tobias Grimm +- Update EPG for MusicChoice, thanks to p_body@vdr-portal +- Add Source-charset +- some UTF-8 script cleanups + +2013-02-10: Version 0.9.1 + U.Hanke <egal@gmx.info> +- Makefile,cleanup for vdr >= 1.7.37 +- RT,RT+ osd/list: convert ISO-8859-1 to utf8/locale + +2012-04-07: Version 0.9.0 + U.Hanke <egal@gmx.info> +- Makefilefix for i18n +- change/round OSD corners +- add themes for skin EgalT2 +- seperate thread for mpeg image showing +- add some themes for Skin Elchi +- fix fonthandling @ Osd +- add RDS scanning @ TS-Frames for vdr >= 1.7.x +- cleanup source, vdr >= 1.6.0 needed +- fix radioepg.c for glibc-2.10, thanks to zzam@vdr-portal +- api changes for vdr >= 1.7.26 + +2009-08-20: Version 0.2.5 + U.Hanke <egal@gmx.info> +- fix Rass-Decoding bug: rfu-bytes (old offsetb) +- add some themes for Skin EnigmaNG +- quoting filenames for rass-imagesave/ffmpeg +- change Premiere-/Sky-RadioTransponderID to 17 +- add cAudio::PlayTs() to compile with vdr-1.7.x (TS-scanning to be done) +- checking only vdr-recordings (existing /recordingpath/001.vdr) +- add italien-translation text, thanks to Diego Pierotto + +2007-10-09: Version 0.2.4 + U.Hanke <egal@gmx.info> +- new transponder (TID) for premiere radio-channels (+ epg fixed) +- create/checks temp. data-dir /tmp/vdr-radio.xxxxxx if not specified, + thanks to Tobias Grimm & Thomas Günther +- cleanup for gcc-4.2.1 (some const char*) +- debug print cleanups -> dsyslog +- update for RT+Specification 2.1, RT+Classes changed +- some scripts added +- add french-translation text, thanks to Patrice Staudt + +2007-09-14: Version 0.2.3 + U.Hanke <egal@gmx.info> +- additional entity- & xhtml-unicode-dezimal conversion +- OSD-Info for Radiochannels on Unity Media Kabel: Song, Artist+Album, + thanks to gmewes@vdr-portal for testing & screenshots +- add french-translation text, thanks to pat@vdr-portal +- Additional songinfos now about external scripts/programs (like www-requests), + see ./config/scripts/LIESMICH.Scripts for details +- changes for vdr >= 1.5.8 (locales) +- Fix Makefile for all shells (== :unexpected operator), thanks to Matthias Schwarzott + +2007-08-14: Version 0.2.2 + U.Hanke <egal@gmx.info> +- changes for vdr >= 1.5.7 (locales: ../po, make i18n, aso) +- Transfermode for encrypted radio channels over command-option -e 1/--encrypted=1, + without Transfermode no background-image + no birate-item +- Auto-OSD called now @ background-thread, no more transfermode need for OSD +- OSD-Info for Radiochannels on Kabel Deutschland: Song, Artist, Album, Comp., + thanks to CafeDelMar@vdr-portal for testing & screenshots +- Workaround osdbugfixing 1.Textrow @ setup wihout titlerow +- StatusEvents for epg-info added +- Timefixing on epg-events (premiere) + +2007-08-03: Version 0.2.1 + U.Hanke <egal@gmx.info> +- OSD-Info for Premiere-Radio from EPG-PresentEvent: + Interpret, Titel/Werk, Album/Komponist, Jahr +- UseStillPicture-Device about Setup (disable for softdevice/dxr3) +- OSD-Info for RockAntenne about InetRequest (Setup-Option), + code 'rockantenne.h/rockantenne.c' taken from + rockantenne-plugin, thanks to Author Frank Bergmann +- align OSD-Title/Artist, freetype-fonts in vdr >= 1.5.3 +- first implementation of tmc-parser Alert-C coding + (start with --verbose=32 or greater and watch console-output) +- some changes like RDS-ODA IDs for RT+ & TMC_Alert-C +- add hungarian-translation text, thanks to Füley István +- add Skin-Themes: Soppalusikka-Blackberry/Citron, + Enigma-WineRed/AppleGreen/WomansLike/YellowSun, + Elchi_Plugin, EgalsTry~default/~blue +- <radio top40> sends RDS @ audio-stream, seperate PID cancled +- add RaSS-Gallery over OK button, + add RaSS-Image saving as jpeg with installed ffmpeg, + add RaSS-OSD keys for gallery, navigation, images +- add audio-bitrate to osd, taken from mpegheader +- changes for vdr >= 1.5.0 +- fix valgrind suggestion, thanks to Hulk@vdr-portal for providing the patch +- add french-translation text, thanks to pat@vdr-portal +- add finnisch-translation text, thanks to Rolf Ahrenberg + +2006-12-31: Version 0.2.0 + U.Hanke <egal@gmx.info> +- Add RaSS-Implementation 'RadioScreenShow' (workingname QDAr), + slideshow with mpeg-stills as backgroundimage & save datafiles, + archiv with OSD & Navigation +- Bugfix: now stopping correct rds-receiver on multiple tunerdevices, + thanks to Reinhard Nißl + +2006-08-14: Version 0.1.4 + U.Hanke <egal@gmx.info> +- add seperate RDS-Receiver for Data-PIDs, + on channels like Radio-FFH & co. +- RDS PS added, text in osd, if no RTplus available +- RDS PTYN added, shown if no PTY received + +2006-07-19: Version 0.1.3 + U.Hanke <egal@gmx.info> +- add Service/OSD-Symbol from audiorecorder for title-recording +- exchange localtime() with thread-safe localtime_r() +- add french-translation text, thanks to Michaël Nival + +2006-04-27: Version 0.1.2 + U.Hanke <egal@gmx.info> +- Bugfix in fopen for DataDir-files, thanks to Thomas Günther +- New command-options --live/--replay = mpegfile for default-mpegs @ live-/replaymode, + (mpegfile as absolute incl. Path), suggested by Tobias Grimm +- Add -fPIC to compiler-flags, thanks to Tobias Grimm + +- OSD-Timeout reactivated +- cPlugin::Active/cPlugin::MainThreadHook only if vdr >= 1.3.47 for better compatibility with patched vdr +- New svdrp-command 'RTTCLOSE' for temporarily closing OSD (2*Osd-Messagetimeout) + +2006-04-19: Version 0.1.0 + U.Hanke <egal@gmx.info> +- Changes for vdr >= 1.3.47 +- RDS-logo in osd added, ../symbols/rds.xpm can also be used in skin-menus +- StatusMsg for lcdproc&co independent from osd +- New command-option --data=dir for temp. datafiles +- Reorg plugin-call for automatic-osd +- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg +- Changes for vdr >= 1.3.45 +- Add skincolors for Radiotext-OSD, see setup-option 'Skincolor used' +- Add crc16 check (CCITT) for rds + qdar-files +- Makefile-Defines for vdr-patches +- RTplus-Memory with seperate OSDs added +- detecting radio in file @ replaymode, + thanks to Reinhard Nißl for providing the patch +- cleanup code, vdr < 1.3.43 no longer supported +- no more own tansferthread -> changing to audiothread, + radiotext @ replaymode now possible, + better handling of transfer-start, + thanks to Reinhard Nißl for providing all the patches + +2006-01-09: Version 0.0.9 + U.Hanke <egal@gmx.info> +- RDS-PTY OSD changed & no radio-action on Data/Service-channels, + thanks to Walter Koch for providing the patch +- Bugfix: Title-Starttime @ radiotext-service & StatusMsg (lcdproc&co.) +- Update/Changing to RTplus Version 2.0 (now we have titleend with item-runningbit ;) + +2005-11-02: Version 0.0.8e + U.Hanke <egal@gmx.info> +- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg +- RText: PlusTag ends, if 2x taglen=0, new seen @ 'Eins Live/Bremen Vier/SWR3', + PlusTag changing also without togglebit (seen on 'Bremen Vier'), + PlusTag change entitystr to corresponding char ("'" -> "'" a.s.o) + +2005-10-12: Version 0.0.8d + U.Hanke <egal@gmx.info> +- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg +- Fix for displaying the bg-image, thanks to Joachim Wilke for providing the patch +- RText: cStatus::MsgOsdProgramme/ItemText added (incl. setup) for lcdproc and other + display-plugins, thanks to Joachim Wilke for providing the initial-patch, +- RText: length-checking not strict '==', station NDR* sends false MEL +- RText: PlusTag-startmarker now beginning with '0' (only WDR sends it correct now) + +2005-09-12: Version 0.0.8c + U.Hanke <egal@gmx.info> +- Bugfix: closing own plugin-OSD on channelswitch by CHAN+/- or svdrp +- Background-checking, if radio-channels get video-Pid (new/temp.), suggested by Rolf Ahrenberg +- Changes for vdr >= 1.3.32, no more UserMacroKey needed for AutoOsd +- New extern svdrp-commands > plug radio 'RTINFO' and 'RTCLOSE' (vdr >= 1.3.31): + > RTINFO + > Print the radiotext information. + > RTCLOSE + > Close the radiotext-osd. + > Reopen can only be done over menu or channelswitch. + +2005-09-10: Version 0.0.8a/b + U.Hanke <egal@gmx.info> +- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg +- Bugfix: close RText-OSD at channelswitch (svdrp), if no radio-channel +- AutoOSD: no UserKey after player-end with <Back-Key>, + no more closing other plugin-osds + +2005-09-09: Version 0.0.8 + U.Hanke <egal@gmx.info> +- Update/Add finnisch-translation text, thanks to Rolf Ahrenberg +- Delayed OSD-redisplay after menus +- New OSD-timeout, timerval about setup (0=No, 1-1440 min.) +- Check textrepeatings in all OSD-Rows + +2005-08-31: Version 0.0.7f + U.Hanke <egal@gmx.info> +- RDS-PTY added, thanks to Walter Koch for providing the patch +- RDSText-Check @ pes audio-frames instead of ts-frames on vdr >= 1.3.31 +- Update ID "RadioTextService-1.0" service-call for other plugins: + struct RadioTextService_v1_0 { + int rds_info; // 0= No / 1= Text / 2= Text + RTplus-Tags (Item,Artist) + int rds_pty; // 0-31, Source http://www.ebu.ch/trev_255-beale.pdf for values + char *rds_text; + char *rds_title; // "---" if none @ moment + char *rds_artist; // "---" if none @ moment + struct tm *title_start; + }; +- Some modifications on RTplus-tags errors + +2005-08-27: Version 0.0.7e + U.Hanke <egal@gmx.info> +- Bugfix: prevent keys Channel+/- to switch twice @ AutoOsd +- Add char-translation 'additional display characters' for radiotext (see RBDS-Standard for more info) + +2005-08-24: Version 0.0.7d + U.Hanke <egal@gmx.info> +- Update finnisch-translation text, thanks to Rolf Ahrenberg +- RDS-Text: ignore textline-doublettes for OSD, +- Add ID "RadioTextService-1.0" service-call for other plugins: + struct RadioTextService_v1_0 { + int rds_info; // 0= No / 1= Text / 2= Text + RTplus-Tags (Item,Artist) + char *rds_text; + char *rds_title; + char *rds_artist; + struct tm *title_start; + }; + See vdr-1.3.30 for more info about 'cPluginName::Service' or + demo-plugin 'rtextdemo' on console-output, how it works + +2005-08-21: Version 0.0.7c + U.Hanke <egal@gmx.info> +- Additional finnisch-translation text, thanks to Rolf Ahrenberg +- RDS-Text: new osd-options 'OSD-Titlerow, OSD-Scrollmode, OSD-Taginfo', + itemtag-end about (no)repeating & min-timer, + rdstextcheck-revision since ARD-Radiotransponder sends (20050819) +- Update transfermode (cThread::Running()), see vdr-1.3.29 for details + +2005-08-05: Version 0.0.7b + U.Hanke <egal@gmx.info> +- Finnisch-translation text, thanks to Rolf Ahrenberg +- Commandline-option verboselevel for testing +- RTplus tags (Title/Artist) added, OSD-Option for RTplus tags +- Radiotextcheck optimized (TS-Header, bytestuffing + co.) + +2005-07-31: Version 0.0.7a + U.Hanke <egal@gmx.info> +- cleanup code, vdr<1.3.22 no longer supported +- RDS-Radiotext added, show about Mainmenuentry or Automatic +- Div. Setup-Options for radio/RDS-Radiotext +- Internationalization added, +- All AudioTracks now possible + +2005-03-19: Version 0.0.6 +- F.PECOURT: + modified functions calls for new Audio IDs and + radiotransfer for vdr 1.3.22. First dirty hacks + still one problem: blank image when switching + from one radio to an other. Clear missing! + +2004-11-10: Version 0.0.1 + +- Initial revision. diff --git a/LIESMICH.bitte b/LIESMICH.bitte new file mode 100644 index 0000000..150f3ce --- /dev/null +++ b/LIESMICH.bitte @@ -0,0 +1,82 @@ +Plugin radio for vdr >= 1.7.37 + +MPEG-Standbilder als Beispiele beigefügt (siehe SubDir ../config/mpgestill), +(überarbeitete Vorlage von kleo @ vdrportal); +zur Benutzung kopiere/installiere nach $VDRCONFIG/plugins/radio (-f <DIR>). + +Externe Scriptabfragen für Titel/Interpret-Infos unter ../config/scripts), +(für Funktion/Aufbau siehe ../config/scripts/LIESMICH.Scripts); +zur Benutzung kopiere/installiere nach $VDRCONFIG/plugins/radio (-f <DIR>). + + +---------------------------- +Grundsätzlich zur Bedienung: +---------------------------- +Wenn im OSD entweder der Radiotext/Info oder der RaSS-Archivhinweis aktiv ist, +kann mit der Taste 'Zurück' das OSD getoggelt werden, soll heißen: +RaSS-Hinweis/Radiotext -> kein OSD -> RaSS-Hinweis/Radiotext usw. + +----------------------------- +Bedienung/Tasten RTplus-Menu: +----------------------------- +Wenn im OSD der Radiotext/Info zu sehen ist, kann mit der Taste '0' +das zusätzliche RTplus-Menu + evtl. weitere aufgerufen werden. +Die Übersicht wird automatisch alle 60 Sekunden aktualisiert; +evtl. Untermenus ca. alle 20s, wenn aktiviert. + +Tasten in den Menus: + 0 = Aktualisieren + OK/Zurück = Schließen + 8 = RTplus-Infos speichern (nur im 1.Menu) + +----------------------------- +Bedienung/Tasten RaSS-Archiv: +----------------------------- +Wenn im OSD der Hinweis 'Archiv verfügbar' zu sehen ist, kann mit der Taste '0' +das zusätzliche RaSS-Archiv aufgerufen werden. + +Auf der linken Seite erscheint das Archiv-Menu mit den Bedienungstasten 0-9/OK, +dabei bedeuten folgende Symbole: + + |=| = Seiten vorhanden (0-9) + | | xx = Gallery, xx Anzahl Bilder (OK) + > = Standort + +Folgende zusätzliche Tasten stehen zur Verfügung: + + Auf/Ab = Scrollen innerhalb Archivmenu (0-9/OK) + Links/Rechts = Scrollen innerhalb der Subseiten/Gallery + Rot = Speichert angezeigte Seite als JPEG-Bild (1024x576) + Grün = Speichert alle Subseiten/Gallery als JPEG-Bilder (1024x576), + - Seitenname = RaSS_Sendername-Seitennr_MonatTagStundeMinute.jpg + - Gallerynamen = RaSS_Sendername-GallerySeitennr_MonatTag.jpg + Gelb = todo, was ? + Blau/Exit = Archiv verlassen + +Alle anderen Tasten schließen das RaSS-Archiv ebenso. + +Hinweis: Die JPEG-Speicherung/Wandlung erfolgt nur, wenn auf dem System + das Programm 'ffmpeg' installiert ist. + + +-------------- +SVDRP-Befehle: +-------------- + RTINFO = Ausgabe der Radiotext Information + RTCLOSE = Radiotext-OSD schließen. Erneutes Öffnen nur über Menü oder Kanalwechsel + RTTCLOSE = Radiotext-OSD zeitweise schließen. Wiederöffnen automatisch nach OSD-Timeout + +---------------- +Ausrufparameter: +---------------- + -f <DIR> --files=<DIR> Bilderverzeichnis (Standard: $VDRCONFIG/plugins/radio) + -d <DIR> --data=<DIR> Datenverzeichnis temporär (Standard: /tmp/vdr-radio.XXXXXX) + -l <DATEI> --live=<DATEI> benutze <DATEI> im Livemodus (Standard: $VDRCONFIG/plugins/radio/radio.mpg) + -r <DATEI> --replay=<DATE> benutze <DATEI> im Wiedergabemodus (Standard: $VDRCONFIG/plugins/radio/replay.mpg) + -e 1 --encrypted=1 benutze Transfermode auch bei verschlüsselten Sendern + -v <LEVEL> --verbose=<LEVEL> Console-Printouts: 0 keine Meldungen, 1 RDS-Text+Tags (Voreinstellung), 2 +RDS-Telegram/Debug, + 3 +RawData 0xfd, |=16 Rass-Info, |=32 TMC-Info + + +Viel Spaß... +Uwe <egal at egal-vdr dot de> diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..5a14a28 --- /dev/null +++ b/Makefile @@ -0,0 +1,122 @@ +# +# Makefile for a Video Disk Recorder plugin +# +# $Id$ + +# The official name of this plugin. +# This name will be used in the '-P...' option of VDR to load the plugin. +# By default the main source file also carries this name. + +PLUGIN = radio + +### The version number of this plugin (taken from the main source file): + +VERSION = $(shell grep 'static const char \*VERSION *=' $(PLUGIN).c | awk '{ print $$6 }' | sed -e 's/[";]//g') + +### The directory environment: + +# Use package data if installed...otherwise assume we're under the VDR source directory: +PKGCFG = $(if $(VDRDIR),$(shell pkg-config --variable=$(1) $(VDRDIR)/vdr.pc),$(shell pkg-config --variable=$(1) vdr || pkg-config --variable=$(1) ../../../vdr.pc)) +LIBDIR = $(call PKGCFG,libdir) +LOCDIR = $(call PKGCFG,locdir) +PLGCFG = $(call PKGCFG,plgcfg) +# +TMPDIR ?= /tmp + +### The compiler options: + +export CFLAGS = $(call PKGCFG,cflags) +export CXXFLAGS = $(call PKGCFG,cxxflags) + +### The version number of VDR's plugin API: + +APIVERSION = $(call PKGCFG,apiversion) + +### Allow user defined options to overwrite defaults: + +-include $(PLGCFG) + +### The name of the distribution archive: + +ARCHIVE = $(PLUGIN)-$(VERSION) +PACKAGE = vdr-$(ARCHIVE) + +### The name of the shared object file: + +SOFILE = libvdr-$(PLUGIN).so + +### Includes and Defines (add further entries here): + +INCLUDES += + +DEFINES += -DPLUGIN_NAME_I18N='"$(PLUGIN)"' + +### The object files (add further files here): + +OBJS = $(PLUGIN).o radioaudio.o radioskin.o radiotools.o radioepg.o inforx.o + +### The main target: + +all: $(SOFILE) i18n + +### Implicit rules: + +%.o: %.c + $(CXX) $(CXXFLAGS) -c $(DEFINES) $(INCLUDES) -o $@ $< + +### Dependencies: + +MAKEDEP = $(CXX) -MM -MG +DEPFILE = .dependencies +$(DEPFILE): Makefile + @$(MAKEDEP) $(CXXFLAGS) $(DEFINES) $(INCLUDES) $(OBJS:%.o=%.c) > $@ + +-include $(DEPFILE) + +### Internationalization (I18N): + +PODIR = po +I18Npo = $(wildcard $(PODIR)/*.po) +I18Nmo = $(addsuffix .mo, $(foreach file, $(I18Npo), $(basename $(file)))) +I18Nmsgs = $(addprefix $(DESTDIR)$(LOCDIR)/, $(addsuffix /LC_MESSAGES/vdr-$(PLUGIN).mo, $(notdir $(foreach file, $(I18Npo), $(basename $(file)))))) +I18Npot = $(PODIR)/$(PLUGIN).pot + +%.mo: %.po + msgfmt -c -o $@ $< + +$(I18Npot): $(wildcard *.c) + xgettext -C -cTRANSLATORS --no-wrap --no-location -k -ktr -ktrNOOP --package-name=vdr-$(PLUGIN) --package-version=$(VERSION) --msgid-bugs-address='<see README>' -o $@ `ls $^` + +%.po: $(I18Npot) + msgmerge -U --no-wrap --no-location --backup=none -q -N $@ $< + @touch $@ + +$(I18Nmsgs): $(DESTDIR)$(LOCDIR)/%/LC_MESSAGES/vdr-$(PLUGIN).mo: $(PODIR)/%.mo + install -D -m644 $< $@ + +.PHONY: i18n +i18n: $(I18Nmo) $(I18Npot) + +install-i18n: $(I18Nmsgs) + +### Targets: + +$(SOFILE): $(OBJS) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared $(OBJS) -o $@ + +install-lib: $(SOFILE) + install -D $^ $(DESTDIR)$(LIBDIR)/$^.$(APIVERSION) + +install: install-lib install-i18n + +dist: $(I18Npo) clean + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @mkdir $(TMPDIR)/$(ARCHIVE) + @cp -a * $(TMPDIR)/$(ARCHIVE) + @tar czf $(PACKAGE).tgz -C $(TMPDIR) $(ARCHIVE) + @-rm -rf $(TMPDIR)/$(ARCHIVE) + @echo Distribution package created as $(PACKAGE).tgz + +clean: + @-rm -f $(PODIR)/*.mo $(PODIR)/*.pot + @-rm -f $(OBJS) $(DEPFILE) *.so *.tgz core* *~ @@ -0,0 +1,64 @@ +This is a "plugin" for the Video Disk Recorder (VDR). + +Written by: Lars Tegeler <email@host.dom>, + Uwe Hanke <egal@egal-vdr.de> + +Project's homepage: www.math.uni-paderborn.de/~tegeler/vdr + www.egal-vdr.de/plugins + +Latest version available at: www.egal-vdr.de/plugins + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +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., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + +The complete text of the GNU General Public License can be found +in /usr/share/common-licenses/GPL on most Debian systems. + + +Description: + +This plugin display an background image while the vdr is switcht to radio channels. +Additionally it decode & show RDS (RadioDataSystem) information in the audiostream +(RDS UECP) like Radiotext(Plus) and Rass (RadioScreenShow). +Finally it receive & show external infos (scripts/programs) about title/interpret, +f.e. parsing websites of radiostations. + + +Install: + +1. Extract and copy the plugin: + cd /yourpath/VDR/PLUGINS/src + tar -xzf /yourpath/vdr-radio-x.y.z.tgz + +2. Make a link in /here is your vdr/PLUGINS/src: + ln -s radio-x.y.z radio + +3. cd /yourpath/VDR + make + make plugins + +4. Copy your background images to /yourpath/vdr/CONFIG/plugins/radio + (Default radio.mpg will be used or if exist <channelname>.mpg ) + Yeah, must be .mpg! + +4.1 If you dont wont to use the default directory you can use the -f option + to set an other one. + +5. Start your VDR with the option: + -P radio + +6. Have Fun! + + +For additional info/description see LIESMICH.bitte diff --git a/config/mpegstill/radio-OnAir1080.mpg b/config/mpegstill/radio-OnAir1080.mpg Binary files differnew file mode 100644 index 0000000..8fa6112 --- /dev/null +++ b/config/mpegstill/radio-OnAir1080.mpg diff --git a/config/mpegstill/radio-Red1080.mpg b/config/mpegstill/radio-Red1080.mpg Binary files differnew file mode 100644 index 0000000..03f0162 --- /dev/null +++ b/config/mpegstill/radio-Red1080.mpg diff --git a/config/mpegstill/radio-Tubes1080.mpg b/config/mpegstill/radio-Tubes1080.mpg Binary files differnew file mode 100644 index 0000000..e65cf16 --- /dev/null +++ b/config/mpegstill/radio-Tubes1080.mpg diff --git a/config/mpegstill/radio.mpg b/config/mpegstill/radio.mpg new file mode 120000 index 0000000..a9a53d4 --- /dev/null +++ b/config/mpegstill/radio.mpg @@ -0,0 +1 @@ +radio-Tubes1080.mpg
\ No newline at end of file diff --git a/config/mpegstill/replay.mpg b/config/mpegstill/replay.mpg new file mode 120000 index 0000000..b16393c --- /dev/null +++ b/config/mpegstill/replay.mpg @@ -0,0 +1 @@ +rtextUnten-kleo2-replay.mpg
\ No newline at end of file diff --git a/config/mpegstill/rtextOben-kleo2-live.mpg b/config/mpegstill/rtextOben-kleo2-live.mpg Binary files differnew file mode 100644 index 0000000..d60782c --- /dev/null +++ b/config/mpegstill/rtextOben-kleo2-live.mpg diff --git a/config/mpegstill/rtextOben-kleo2-replay.mpg b/config/mpegstill/rtextOben-kleo2-replay.mpg Binary files differnew file mode 100644 index 0000000..976483c --- /dev/null +++ b/config/mpegstill/rtextOben-kleo2-replay.mpg diff --git a/config/mpegstill/rtextOben-kleo2.mpg b/config/mpegstill/rtextOben-kleo2.mpg Binary files differnew file mode 100644 index 0000000..f310bc4 --- /dev/null +++ b/config/mpegstill/rtextOben-kleo2.mpg diff --git a/config/mpegstill/rtextUnten-kleo2-live.mpg b/config/mpegstill/rtextUnten-kleo2-live.mpg Binary files differnew file mode 100644 index 0000000..c63f214 --- /dev/null +++ b/config/mpegstill/rtextUnten-kleo2-live.mpg diff --git a/config/mpegstill/rtextUnten-kleo2-replay.mpg b/config/mpegstill/rtextUnten-kleo2-replay.mpg Binary files differnew file mode 100644 index 0000000..5ff4b40 --- /dev/null +++ b/config/mpegstill/rtextUnten-kleo2-replay.mpg diff --git a/config/mpegstill/rtextUnten-kleo2.mpg b/config/mpegstill/rtextUnten-kleo2.mpg Binary files differnew file mode 100644 index 0000000..5a62613 --- /dev/null +++ b/config/mpegstill/rtextUnten-kleo2.mpg diff --git a/config/scripts/LIESMICH.Scripts b/config/scripts/LIESMICH.Scripts new file mode 100644 index 0000000..8038518 --- /dev/null +++ b/config/scripts/LIESMICH.Scripts @@ -0,0 +1,62 @@ +vdr-radio plugin: externe script-files +-------------------------------------- + +Externe Script- oder Programm-Files haben die Funktion, falls im plugin-Setup +aktiviert (Externe Info-Abfrage = ja), fehlende Songinfos über externe Quellen +wie Internetabfragen zu holen. + +Das Script/Programm muß hierfür im Plugin-Config-Verzeichnis existieren +($VDRCONFIG/plugins/radio, beachte auch plugin-Startparameter '-f <DIR>'), +für den vdr ausführbar sein und die folgende Namenssyntax aufweisen: + + radioinfo-TID-APID + (wobei TID = channel-TID, APID = 1.AudioPid entspr. der vdr channels.conf) + +Das Script/Programm wird dann mit 1 Parameter = Dateiname Ausgabedatei im +Datenverzeichnis ($VDRCONFIG/plugins/radio, beachte auch plugin-Parameter -d <DIR>) +aufgerufen; die Ausgabedatei soll dann Textzeilen im folgendem Format enthalten: + + 1.Zeile = Senderkennung + 2.Zeile = Interpret + 3.Zeile = Titel + +Wenn die Sender zeitweise keine Songinfos anzeigen (z.B. Fritz) sollte +Interpret und/oder Titel solange mit z.B. "---" gesetzt werden, da sonst +bei leeren Informationen ein "Error, no Songinfo" im OSD angezeigt wird. + + +Folgende Script-Beispiele (www-Abfragen) werden mitgeliefert +(die Programme bash/wget/grep sowie teilw. tail/tac/iconv werden benötigt): + + [Astra 19.2] + - Rockantenne = radioinfo-7-304 + - sunshine live = radioinfo-7-336 + - Antenne Bayern = radioinfo-7-352 + - radio top40 = radioinfo-1113-353 + - ffn digital = radioinfo-1113-354 + - Hit Radio FFH = radioinfo-1113-1024 + - planet radio = radioinfo-1113-1030 + - harmony.fm = radioinfo-1113-1036 + - oe3 orf = radioinfo-1115-433 + - Truckradio = radioinfo-1115-442 + - MDR Jump = radioinfo-1093-541 + - SPUTNIK = radioinfo-1093-551 + - radioeins = radioinfo-1093-841 + - Fritz = radioinfo-1093-851 + [Hotbird 13.0] + - SRG-DRS 1 = radioinfo-8500-211 + - SRG-DRS 2 = radioinfo-8500-212 + - SRG-DRS 3 = radioinfo-8500-213 + - SRG-DRS Virus = radioinfo-8500-214 + - Radio Swiss Classic = radioinfo-8500-224 + - Radio Swiss Pop = radioinfo-8500-225 + - Radio Swiss Jazz = radioinfo-8500-226 + [Astra 23.5] + - Truckradio = radioinfo-15027-5120 + + +Weitere erfolgreich getestete Scripte werden gerne übernommen :-) + + +Viel Spaß... +Uwe <egal at egal-vdr dot de> diff --git a/config/scripts/radioinfo-1093-541 b/config/scripts/radioinfo-1093-541 new file mode 100755 index 0000000..bbac81c --- /dev/null +++ b/config/scripts/radioinfo-1093-541 @@ -0,0 +1,27 @@ +#!/bin/bash +# MDR Jump-Playlist +# $1 = outfile + +### Variabel +Name="MDR Jump [www.jumpradio.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.jumpradio.de/scripts/musik/wsx_vote_recher.cfm?&titelsuche=zeit" + +# Artist/Title +artist=`grep -B30 '<h2>Suche nach Datum und Uhrzeit' /tmp/playlist | tac` +artist=${artist/*$'">'/}; artist=${artist/$'<'\/'h2>'*/} +title=`grep -B29 '<h2>Suche nach Datum und Uhrzeit' /tmp/playlist | tac` +title=${title/*$'">"'/}; title=${title/$'"<'\/'p>'*/} +# temp. no Info +artist=${artist:='---'}; titel=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1093-551 b/config/scripts/radioinfo-1093-551 new file mode 100755 index 0000000..5fbbde2 --- /dev/null +++ b/config/scripts/radioinfo-1093-551 @@ -0,0 +1,31 @@ +#!/bin/bash +# SPUTNIK-Playlist +# $1 = outfile + +### Variabel +Name="SPUTNIK [www.sputnik.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.sputnik.de" +iconv -s -c -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist + +# Artist/Title +present=`grep -A7 'class="current_song"' /tmp/playlist | grep -c 'nicht zu ermitteln'` +if [ $present = 0 ]; then + artist=`grep -A7 'class="current_song"*' /tmp/playlist` + artist=${artist/*$'"name">'/}; artist=${artist/$'<'\/'p>'*/} + title=`grep -A8 'class="current_song"*' /tmp/playlist` + title=${title/*$'"title">'/}; title=${title/$'<'\/'p>'*/} +fi +# temp. no Info +artist=${artist:='---'}; titel=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1093-551.utf8 b/config/scripts/radioinfo-1093-551.utf8 new file mode 100755 index 0000000..420685b --- /dev/null +++ b/config/scripts/radioinfo-1093-551.utf8 @@ -0,0 +1,30 @@ +#!/bin/bash +# SPUTNIK-Playlist +# $1 = outfile + +### Variabel +Name="SPUTNIK [www.sputnik.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.sputnik.de" + +# Artist/Title +present=`grep -A7 'class="current_song"' /tmp/playlist | grep -c 'nicht zu ermitteln'` +if [ $present = 0 ]; then + artist=`grep -A7 'class="current_song"*' /tmp/playlist` + artist=${artist/*$'"name">'/}; artist=${artist/$'<'\/'p>'*/} + title=`grep -A8 'class="current_song"*' /tmp/playlist` + title=${title/*$'"title">'/}; title=${title/$'<'\/'p>'*/} +fi +# temp. no Info +artist=${artist:='---'}; titel=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1093-841 b/config/scripts/radioinfo-1093-841 new file mode 100755 index 0000000..6f0b9a0 --- /dev/null +++ b/config/scripts/radioinfo-1093-841 @@ -0,0 +1,25 @@ +#!/bin/bash +# radioeins-Playlist +# $1 = outfile + +### Variabel +Name="radioeins [radioeins.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://radioeins.funtip.de/playList.do" + +# Artist/Title +artist=`grep -A17 'summary="Liste der radioeins Musiktitel"*' /tmp/playlist` +artist=${artist/*$'<td>'/}; artist=${artist/$'<'\/'td>'*/} +title=`grep -A18 'summary="Liste der radioeins Musiktitel"*' /tmp/playlist` +title=${title/*$'<td>'/}; title=${title/$'<'\/'td>'*/} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1093-851 b/config/scripts/radioinfo-1093-851 new file mode 100755 index 0000000..0b74297 --- /dev/null +++ b/config/scripts/radioinfo-1093-851 @@ -0,0 +1,26 @@ +#!/bin/bash +# Fritz-Playlist +# $1 = outfile + +### Variabel +Name="Fritz [www.fritz.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.fritz.de/ds/ds.html" + +# Artist/Title +all=`grep -A0 'on air Titel:' /tmp/playlist` +artist=${all/*$'<span class='\"'titelanzeige'\"'>'/}; artist=${artist/$' - '*/} +title=${all//*$' - '/}; title=${title/$'<'\/'span>'*/} +# temp. no Info +artist=${artist:='...'}; titel=${title:='...'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1113-1024 b/config/scripts/radioinfo-1113-1024 new file mode 100755 index 0000000..52e4b0f --- /dev/null +++ b/config/scripts/radioinfo-1113-1024 @@ -0,0 +1,26 @@ +#!/bin/bash +# Hit Radio FFH-Playlist +# $1 = outfile + +### Variabel +Name="Hit Radio FFH [www.ffh.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.ffh.de/webradio/hitfinder_index.php" +iconv -c -s -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist + +# Artist/Title +artist=`grep -A15 '>Datum/Zeit<*' /tmp/playlist` +artist=${artist//*$'<td>'/}; artist=${artist//$'<'\/'td>'*/} +title=`grep -A14 '>Datum/Zeit<*' /tmp/playlist` +title=${title//*$'<td>'/}; title=${title//$'<'\/'td>'*/} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1113-1024.utf8 b/config/scripts/radioinfo-1113-1024.utf8 new file mode 100755 index 0000000..6a7c2b6 --- /dev/null +++ b/config/scripts/radioinfo-1113-1024.utf8 @@ -0,0 +1,25 @@ +#!/bin/bash +# Hit Radio FFH-Playlist +# $1 = outfile + +### Variabel +Name="Hit Radio FFH [www.ffh.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.ffh.de/webradio/hitfinder_index.php" + +# Artist/Title +artist=`grep -A15 '>Datum/Zeit<*' /tmp/playlist` +artist=${artist//*$'<td>'/}; artist=${artist//$'<'\/'td>'*/} +title=`grep -A14 '>Datum/Zeit<*' /tmp/playlist` +title=${title//*$'<td>'/}; title=${title//$'<'\/'td>'*/} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1113-1030 b/config/scripts/radioinfo-1113-1030 new file mode 100755 index 0000000..25e5de5 --- /dev/null +++ b/config/scripts/radioinfo-1113-1030 @@ -0,0 +1,24 @@ +#!/bin/bash +# PlanetRadio-Playlist +# $1 = outfile + +### Variabel +Name="planet radio [www.planetradio.de]" +### + +# get... +wget -q --tries=1 --timeout=10 -O /tmp/playlist "http://www.planetradio.de/p_mt.php" + +# Artist/Title +all=`grep -A1 'die letzten 3 tracks' /tmp/playlist` +title=${all/*$'<table><tr><td>'????????????????????/}; title=${title/$'<'\/'td>'*/} +artist=${all//*$'td><td>'/}; artist=${artist/$'<'\/'td>'*/} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1113-1036 b/config/scripts/radioinfo-1113-1036 new file mode 100755 index 0000000..d58eccd --- /dev/null +++ b/config/scripts/radioinfo-1113-1036 @@ -0,0 +1,25 @@ +#!/bin/bash +# harmony.fm-Playlist +# $1 = outfile + +### Variabel +Name="harmony.fm [www.harmonyfm.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.harmonyfm.de/index.php" +iconv -c -s -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist + +# Artist/Title +all=`grep -A6 'id="channelOnAir"' /tmp/playlist` +artist=${all//*$'<p>'/}; artist=${artist/$' mit '*/} +title=${all//*$' mit '/}; title=${title/$'<'\/'p>'*/} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1113-1036.utf8 b/config/scripts/radioinfo-1113-1036.utf8 new file mode 100755 index 0000000..20a81ac --- /dev/null +++ b/config/scripts/radioinfo-1113-1036.utf8 @@ -0,0 +1,24 @@ +#!/bin/bash +# harmony.fm-Playlist +# $1 = outfile + +### Variabel +Name="harmony.fm [www.harmonyfm.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.harmonyfm.de/index.php" + +# Artist/Title +all=`grep -A6 'id="channelOnAir"' /tmp/playlist` +artist=${all//*$'<p>'/}; artist=${artist/$' mit '*/} +title=${all//*$' mit '/}; title=${title/$'<'\/'p>'*/} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1113-353 b/config/scripts/radioinfo-1113-353 new file mode 100755 index 0000000..7957b1e --- /dev/null +++ b/config/scripts/radioinfo-1113-353 @@ -0,0 +1,27 @@ +#!/bin/bash +# radio top40-Playlist +# $1 = outfile + +### Variabel +Name="radio top40 [www.radiotop40.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.radiotop40.de/titel.php" + +# Artist/Title +artist=`grep -A6 '<body' /tmp/playlist` +artist=${artist/*$'">'/}; artist=${artist/$' - '*/} +title=`grep -A6 '<body' /tmp/playlist` +title=${title/*$' - '/}; title=${title/$'<'\/'td>'*/} +# temp. no Info +artist=${artist:='---'}; titel=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1113-354 b/config/scripts/radioinfo-1113-354 new file mode 100755 index 0000000..068aeeb --- /dev/null +++ b/config/scripts/radioinfo-1113-354 @@ -0,0 +1,29 @@ +#!/bin/bash +# ffn digital-Playlist +# $1 = outfile + +### Variabel +Name="ffn digital [www.ffn.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.ffn.de/musik/playlist.html" +iconv -c -s -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist + +# grep actual song +all=`grep -A6 'wird gerade gespielt' /tmp/playlist` + +# Artist/Title +artist=${all//*$'"artist">'/}; artist=${artist//$'</h3>'*/} +title=${all//*$'"title">'/}; title=${title//$'</h3>'*/} +# temp. no Info +artist=${artist:='---'}; titel=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1113-354.utf8 b/config/scripts/radioinfo-1113-354.utf8 new file mode 100755 index 0000000..00a214b --- /dev/null +++ b/config/scripts/radioinfo-1113-354.utf8 @@ -0,0 +1,27 @@ +#!/bin/bash +# ffn digital-Playlist +# $1 = outfile + +### Variabel +Name="ffn digital [www.ffn.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.ffn.de/musik/playlist.html" +# grep actual song +all=`grep -A6 'wird gerade gespielt' /tmp/playlist` + +# Artist/Title +artist=${all//*$'"artist">'/}; artist=${artist//$'</h3>'*/} +title=${all//*$'"title">'/}; title=${title//$'</h3>'*/} +# temp. no Info +artist=${artist:='---'}; titel=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-1115-433 b/config/scripts/radioinfo-1115-433 new file mode 100755 index 0000000..952cd51 --- /dev/null +++ b/config/scripts/radioinfo-1115-433 @@ -0,0 +1,27 @@ +#!/bin/bash +# OE3-Playlist +# $1 = outfile + +### Variabel +Name="OE3 [oe3.ORF.at]" +### + +# get... +wget -q --tries=1 --timeout=10 -O /tmp/playlist "http://solutions.orf.at/orf/hitservice/index.cgi?view=tracklist" + +# Artist/Title +title=`grep -A2 'class="playlisttop"' /tmp/playlist` +title=${title/*$'<b>'/}; title=${title/$'<'\/'b>'*/} +artist=`grep -A4 'class="playlisttop"' /tmp/playlist` +artist=${artist/*$' '/} +# temp. no Info +artist=${artist:='...'}; titel=${title:='...'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-15027-5120 b/config/scripts/radioinfo-15027-5120 new file mode 100755 index 0000000..bac3bb2 --- /dev/null +++ b/config/scripts/radioinfo-15027-5120 @@ -0,0 +1,27 @@ +#!/bin/bash +# Truckradio-Playlist +# $1 = outfile + +### Variabel +Name="Truckradio [truckradio.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://truckradio.de/truckradio.php" + +# Artist/Title +artist=`grep -A1 '>Was läuft gerade:' /tmp/playlist` +artist=${artist/*$'<strong>'/}; artist=${artist/$'<BR>'*/} +title=`grep -A1 '>Was läuft gerade:' /tmp/playlist` +title=${title/*$'<BR>'/}; title=${title/$'<'\/'strong>'*/} +# temp. no Info +artist=${artist:='---'}; titel=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-7-304 b/config/scripts/radioinfo-7-304 new file mode 100755 index 0000000..db123ae --- /dev/null +++ b/config/scripts/radioinfo-7-304 @@ -0,0 +1,27 @@ +#!/bin/bash +# Rockantenne-Playlist +# $1 = outfile + +### Variabel +Name="Rockantenne [www.rockantenne.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist.utf8 "http://www.rockantenne.de/webplayer/#playlist" +iconv -c -s -f UTF8 -t ISO8859-1 /tmp/playlist.utf8 -o /tmp/playlist + +# last Artist/Title +all=`grep -m1 -A4 'Rock Nonstop' /tmp/playlist` +all=${all//*$'class="artist">'/}; artist=${all/$'</span>'*/} +title=${all/*$'class="title">'/}; title=${title/$'</span>'*/} +# temp. no Info +artist=${artist:='---'}; title=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-7-304.utf8 b/config/scripts/radioinfo-7-304.utf8 new file mode 100755 index 0000000..a92422e --- /dev/null +++ b/config/scripts/radioinfo-7-304.utf8 @@ -0,0 +1,26 @@ +#!/bin/bash +# Rockantenne-Playlist +# $1 = outfile + +### Variabel +Name="Rockantenne [www.rockantenne.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.rockantenne.de/webplayer/#playlist" + +# last Artist/Title +all=`grep -m1 -A4 'Rock Nonstop' /tmp/playlist` +all=${all//*$'class="artist">'/}; artist=${all/$'</span>'*/} +title=${all/*$'class="title">'/}; title=${title/$'</span>'*/} +# temp. no Info +artist=${artist:='---'}; title=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-7-336 b/config/scripts/radioinfo-7-336 new file mode 100755 index 0000000..3128161 --- /dev/null +++ b/config/scripts/radioinfo-7-336 @@ -0,0 +1,27 @@ +#!/bin/bash +# sunshione live Playlist +# $1 = outfile + +### Variabel +Name="sunshine live [www.sunshine-live.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.sunshine-live.de/index.php?id=15" + +# Artist/Title +artist=`grep -A19 'sunshine live - playlist' /tmp/playlist` +artist=${artist/*$'class="artist">'/}; artist=${artist/$'<'\/'td>'*/} +title=`grep -A18 'sunshine live - playlist' /tmp/playlist` +title=${title/*$'class="title">'/}; title=${title/$'<'\/'td>'*/} +# temp. no Info +artist=${artist:='---'}; titel=${title:='---'} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-7-352 b/config/scripts/radioinfo-7-352 new file mode 100755 index 0000000..7b8eeaa --- /dev/null +++ b/config/scripts/radioinfo-7-352 @@ -0,0 +1,24 @@ +#!/bin/bash +# AntenneBayern-Playlist +# $1 = outfile + +### Variabel +Name="Antenne Bayern [www.antenne.de]" +### + +# get... +wget -q --tries=2 --timeout=5 -O /tmp/playlist "http://www.antenne.de/antenne/mediathek/c_titelinfos/aby-big.php" + +# Artist/Title +all=`tail -n 6 /tmp/playlist | tac` +artist=${all/*$';">'/}; artist=${artist/$'<br>'*/} +title=${all/*$'<br>'/}; title=${title/$'<'\/'div>'*/} + +# write... +if [ $1 ]; then + echo $Name > $1 + echo $artist >> $1 + echo $title >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/config/scripts/radioinfo-8500-214 b/config/scripts/radioinfo-8500-214 new file mode 100755 index 0000000..87a11c8 --- /dev/null +++ b/config/scripts/radioinfo-8500-214 @@ -0,0 +1,24 @@ +#!/bin/bash +# SRG-DRS Virus-Playlist +# $1 = outfile + +### Variabel +Name="SRG-DRS Virus [virus.ch]" +### + +# get.., schnapp dir den neusten Eintrag aus der Liste; schneide ihn zu auf "titel von artist" +all="`wget --quiet --tries=2 --timeout=5 -O - http://virus.ch/virus/ticker | grep -m1 date | cut -d '>' -f5 | cut -d '<' -f1`" + +# Titel, Artist +title=${all/$' von '*/} +artist=${all/*$' von '/} +# temp. no Info +artist=${artist:='---'}; title=${title:='---'} + +# write... +if [ $1 ]; then + echo "$Name" > $1 + echo "$Song" >> $1 +else + echo "$Name: Interpret/Titel = $artist / $title" +fi diff --git a/inforx.c b/inforx.c new file mode 100644 index 0000000..ea0f492 --- /dev/null +++ b/inforx.c @@ -0,0 +1,162 @@ +/* + * inetrx.c - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include <fstream> +#include "inforx.h" + + +void fill_rtpbuffer(char *text1, char *text2) { + + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%s", text1); + snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%s", text2); + snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + + if (++rtp_content.item_Index >= MAX_RTPC) + rtp_content.item_Index = 0; + if (rtp_content.item_Index >= 0) { + rtp_content.item_Start[rtp_content.item_Index] = RTP_Starttime; + asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", RTP_Artist); + asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", RTP_Title); + } + + if ((S_Verbose & 0x0f) >= 1) + printf("radio-inforx: %s / %s\n", RTP_Artist, RTP_Title); +} + +int info_request(int chantid, int chanapid) { + + char ident[80]; + char artist[RT_MEL], titel[RT_MEL]; + struct tm tm_store; + static int repeat = 0; + char temp[2][2*RT_MEL]; + + char *command, *tempfile; + asprintf(&command, "%s/radioinfo-%d-%d", ConfigDir, chantid, chanapid); + asprintf(&tempfile, "%s/%s", DataDir, RadioInfofile); + dsyslog("radio: inforxcall '%s'\n", command); + + DoInfoReq = false; + if (file_exists(command)) { + if (file_exists(tempfile)) { // delete tempfile + char *delcmd; + asprintf(&delcmd, "rm -f \"%s\"", tempfile); + system(delcmd); + free(delcmd); + } + asprintf(&command, "%s \"%s\"", command, tempfile); + if (!system(command)) { // execute script && read tempfile + if (file_exists(tempfile)) { + std::ifstream infile(tempfile); + if (infile.is_open()) { + infile.getline(ident, 80); + infile.getline(artist, RT_MEL); + infile.getline(titel, RT_MEL); + } + infile.close(); + DoInfoReq = true; + } + else + esyslog("radio: ERROR inforx tempfile = %s\n", command); + } + else + esyslog("radio: ERROR inforx command = %s\n", command); + } + free(command); + free(tempfile); + + if (!DoInfoReq) { + dsyslog("radio: inforxcall cancled !\n"); + return -1; + } + + // Info empty? + if (strcmp(artist, "") == 0 && strcmp(titel, "") == 0) { + if (repeat < 700) { // ~ 6x switch off + repeat += 120; + sprintf(RTP_Artist, "---"); + sprintf(RTP_Title, "---"); + RTP_Starttime = time(NULL); + sprintf(temp[0], "%s Error :-(", ident); + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + sprintf(temp[1], "%02d:%02d no Songinfo received !", ts->tm_hour, ts->tm_min); + fill_rtpbuffer(temp[0], temp[1]); + RT_MsgShow = true; + RT_PlusShow = false; + (RT_Info > 0) ? : RT_Info = 1; + radioStatusMsg(); + return 120; + } + else { + RTP_Starttime = time(NULL); + sprintf(temp[0], "%s Error :-(", ident); + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + sprintf(temp[1], "%02d:%02d no Songinfo received, switching off !", ts->tm_hour, ts->tm_min); + asprintf(&rtp_content.info_Url, "%02d:%02d no Songinfo, switched off!", ts->tm_hour, ts->tm_min); + fill_rtpbuffer(temp[0], temp[1]); + RT_MsgShow = true; + RT_PlusShow = false; + (RT_Info > 0) ? : RT_Info = 1; + radioStatusMsg(); + DoInfoReq = false; + return 60; + } + } + + // Info + xhtml2text(artist); + xhtml2text(titel); + if (strcmp(RTP_Artist, artist) != 0 || strcmp(RTP_Title, titel) != 0) { + snprintf(RTP_Artist, RT_MEL, "%s", artist); + snprintf(RTP_Title, RT_MEL, "%s", titel); + RTP_Starttime = time(NULL); + sprintf(temp[0], "%s ok :-)", ident); + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + snprintf(temp[1], 2*RT_MEL, "%02d:%02d %s: %s", ts->tm_hour, ts->tm_min, RTP_Artist, RTP_Title); + fill_rtpbuffer(temp[0], temp[1]); + RT_MsgShow = RT_PlusShow = true; + (RT_Info > 0) ? : RT_Info = 2; + radioStatusMsg(); + repeat = 0; + return 90; + } + else { + if (repeat < 1200) { // ~20 Min. timeout + repeat += 10; + return 10; + } + else { + sprintf(RTP_Artist, "---"); + sprintf(RTP_Title, "---"); + RTP_Starttime = time(NULL); + sprintf(temp[0], "%s Error :-(", ident); + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + sprintf(temp[1], "%02d:%02d no more different Songinfo received, switching off !", ts->tm_hour, ts->tm_min); + asprintf(&rtp_content.info_Url, "%02d:%02d no more Songinfo, switched off!", ts->tm_hour, ts->tm_min); + fill_rtpbuffer(temp[0], temp[1]); + RT_MsgShow = true; + RT_PlusShow = false; + (RT_Info > 0) ? : RT_Info = 1; + radioStatusMsg(); + DoInfoReq = false; + return 60; + } + } + + return 10; +} + + +// end diff --git a/inforx.h b/inforx.h new file mode 100644 index 0000000..4fb457e --- /dev/null +++ b/inforx.h @@ -0,0 +1,24 @@ +/* + * inforx.h - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef _INFORX__H +#define _INFORX__H + +#include "radioaudio.h" +#include "radiotools.h" + + +extern bool RT_MsgShow, RT_PlusShow; +extern rtp_classes rtp_content; +extern bool DoInfoReq; + +#define RadioInfofile "radioinfo.dat" + +int info_request(int chantid, int chanpid); + + +#endif diff --git a/po/de_DE.po b/po/de_DE.po new file mode 100644 index 0000000..5ad188f --- /dev/null +++ b/po/de_DE.po @@ -0,0 +1,350 @@ +# VDR plugin language source file. +# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> +# This file is distributed under the same license as the VDR package. +# Klaus Schmidinger <kls@cadsoft.de>, 2000 +# +msgid "" +msgstr "" +"Project-Id-Version: VDR 1.5.7\n" +"Report-Msgid-Bugs-To: <see README>\n" +"POT-Creation-Date: 2013-05-31 20:15+0200\n" +"PO-Revision-Date: 2007-09-20 15:30+0200\n" +"Last-Translator: Uwe Hanke <egal@egal-vdr.de>\n" +"Language-Team: <vdr@linuxtv.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "unknown program type" +msgstr "Unbekannte Programmart" + +msgid "News" +msgstr "Nachrichten" + +msgid "Current affairs" +msgstr "Aktuelles" + +msgid "Information" +msgstr "Info" + +msgid "Sport" +msgstr "Sport" + +msgid "Education" +msgstr "Bildung" + +msgid "Drama" +msgstr "Hörspiel" + +msgid "Culture" +msgstr "Kultur" + +msgid "Science" +msgstr "Wissenschaft" + +msgid "Varied" +msgstr "Diverses" + +msgid "Pop music" +msgstr "Popmusik" + +msgid "Rock music" +msgstr "Rockmusik" + +msgid "M.O.R. music" +msgstr "Easy Listening u.ä." + +msgid "Light classical" +msgstr "Leichte Klassik" + +msgid "Serious classical" +msgstr "Ernste Klassik" + +msgid "Other music" +msgstr "Sonstige Musik" + +msgid "Alarm" +msgstr "Alarm (!)" + +msgid "ext. Info" +msgstr "zus. Info" + +msgid "RTplus" +msgstr "RTplus" + +msgid "Radiotext" +msgstr "Radiotext" + +msgid " [waiting ...]" +msgstr " [warte ...]" + +msgid "Title :" +msgstr "Titel :" + +msgid "Artist :" +msgstr "Interpret :" + +msgid "Records" +msgstr "Archiv" + +msgid "Rass-Image(s) saved from Archiv " +msgstr "Rass-Bild(er)speicherung von Archiv " + +msgid "Rass-Image(s) saved from Gallery" +msgstr "Rass-Bild(er) der Gallery gespeichert" + +msgid "Rass-Image saved" +msgstr "Rass-Bildspeich." + +msgid "Rass-Image failed" +msgstr "Rass-Bildspeicherfehler" + +msgid "Playlist" +msgstr "Titelliste" + +msgid "Sports" +msgstr "Sport" + +msgid "Lottery" +msgstr "Lotterie" + +msgid "Weather" +msgstr "Wetter" + +msgid "Stockmarket" +msgstr "Bösenkurse" + +msgid "Other" +msgstr "Sonstiges" + +msgid "extra Info since" +msgstr "zusätzl. Info seit" + +msgid "RTplus Memory since" +msgstr "RTplus Speicher seit" + +msgid "Programme" +msgstr "Pogramminfo" + +msgid "Stat.Short" +msgstr "Sender kurz" + +msgid "Station" +msgstr "Sendername" + +msgid "Now" +msgstr "Jetzt" + +msgid "...Part" +msgstr "...Detail" + +msgid "Next" +msgstr "Demnächst" + +msgid "Host" +msgstr "Moderator" + +msgid "Edit.Staff" +msgstr "Person(en)" + +msgid "Homepage" +msgstr "Homepage" + +msgid "Interactivity" +msgstr "Interaktiv (tu' was :)" + +msgid "Phone-Hotline" +msgstr "Tel.-Hotline" + +msgid "Phone-Studio" +msgstr "Tel.-Studio" + +msgid "SMS-Studio" +msgstr "SMS-Studio" + +msgid "Email-Hotline" +msgstr "EMail-Hotline" + +msgid "Email-Studio" +msgstr "EMail-Studio" + +msgid "Info" +msgstr "weitere Information" + +msgid "NewsLocal" +msgstr "Nachricht.Lokal" + +msgid "DateTime" +msgstr "Datum-Zeit" + +msgid "Traffic" +msgstr "Verkehr" + +msgid "Advertising" +msgstr "Hinweis/Reklame" + +msgid "Url" +msgstr "Url/Webseite" + +msgid "Exit" +msgstr "Beenden" + +msgid "Info-File saved" +msgstr "Info-Datei gespeichert" + +msgid "RTplus-File saved" +msgstr "RTplus-Datei gespeichert" + +msgid "last seen Radiotext" +msgstr "die letzten Radiotexte" + +msgid "Time" +msgstr "Zeit" + +msgid "Title" +msgstr "Titel" + +msgid "Artist" +msgstr "Interpret" + +msgid "Refresh Off" +msgstr "Aktualis. Aus" + +msgid "Refresh On" +msgstr "Aktualis. Ein" + +msgid "Back" +msgstr "Zurück" + +msgid "Radio Background-Image/RDS-Text" +msgstr "Hintergr.Bilder/RDS-Text für Radiosender" + +msgid "Show RDS-Radiotext" +msgstr "Zeige RDS-Radiotext" + +msgid "Off" +msgstr "Aus" + +msgid "only Text" +msgstr "nur Text" + +msgid "Text+TagInfo" +msgstr "Text+TagInfos" + +msgid "only, if some" +msgstr "nur, wenn vorhanden" + +msgid "always" +msgstr "immer" + +msgid "Top" +msgstr "Oben" + +msgid "Bottom" +msgstr "Unten" + +msgid "latest at Top" +msgstr "aktuelle Oben" + +msgid "latest at Bottom" +msgstr "aktuelle Unten" + +msgid "Black" +msgstr "Schwarz" + +msgid "White" +msgstr "Weiss" + +msgid "Red" +msgstr "Rot" + +msgid "Green" +msgstr "Grün" + +msgid "Yellow" +msgstr "Gelb" + +msgid "Magenta" +msgstr "Magenta" + +msgid "Blue" +msgstr "Blau" + +msgid "Cyan" +msgstr "Cyan" + +msgid "Transparent" +msgstr "Transparent" + +msgid "about MainMenu" +msgstr "über Hauptmenü" + +msgid "Automatic" +msgstr "Automatisch" + +msgid "only Taginfo" +msgstr "nur TagInfos" + +msgid "Rass only" +msgstr "Rass alleine" + +msgid "Rass+Text mixed" +msgstr "Text über Rass" + +msgid "Activate" +msgstr "Aktivieren" + +msgid "Use StillPicture-Function" +msgstr "Standbild-Funktion aktiv" + +msgid "Hide MainMenuEntry" +msgstr "Verstecke Hauptmenu-Eintrag" + +msgid "RDSText Function" +msgstr "RDSText Funktion" + +msgid "RDSText OSD-Position" +msgstr "RDSText OSD-Position" + +msgid "RDSText OSD-Titlerow" +msgstr "RDSText OSD-Titelzeile" + +msgid "RDSText OSD-Rows (1-5)" +msgstr "RDSText OSD-Zeilen (1-5)" + +msgid "RDSText OSD-Scrollmode" +msgstr "RDSText OSD-Scrollmodus" + +msgid "RDSText OSD-Taginfo" +msgstr "RDSText OSD-Taginformation" + +msgid "RDSText OSD-Skincolors used" +msgstr "RDSText OSD-Skinfarben benutzen" + +msgid "RDSText OSD-Backgr.Color" +msgstr "RDSText OSD-Hintergrundfarbe" + +msgid "RDSText OSD-Backgr.Transp." +msgstr "RDSText OSD-Hintergr.Transparenz" + +msgid "RDSText OSD-Foregr.Color" +msgstr "RDSText OSD-Textfarbe" + +msgid "RDSText OSD-Timeout (0-1440 min)" +msgstr "RDSText OSD-Timeout (0-1440 min)" + +msgid "RDSText OSD-Display" +msgstr "RDSText OSD-Anzeige" + +msgid "RDSText StatusMsg (lcdproc & co)" +msgstr "RDSText StatusMeld. (lcdproc & co)" + +msgid "RDSText Rass-Function" +msgstr "RDSText Rass-Funktion" + +msgid "External Info-Request" +msgstr "Externe Info-Abfrage" + +#~ msgid "with <0>" +#~ msgstr "mit <0>" diff --git a/po/fi_FI.po b/po/fi_FI.po new file mode 100644 index 0000000..7c84cde --- /dev/null +++ b/po/fi_FI.po @@ -0,0 +1,351 @@ +# VDR plugin language source file. +# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> +# This file is distributed under the same license as the VDR package. +# Rolf Ahrenberg <rahrenbe@cc.hut.fi>, 2003 +# +msgid "" +msgstr "" +"Project-Id-Version: VDR 1.5.7\n" +"Report-Msgid-Bugs-To: <see README>\n" +"POT-Creation-Date: 2013-05-31 20:15+0200\n" +"PO-Revision-Date: 2007-08-13 19:21+0200\n" +"Last-Translator: Rolf Ahrenberg <rahrenbe@cc.hut.fi>\n" +"Language-Team: <vdr@linuxtv.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "unknown program type" +msgstr "tuntematon ohjelmatyyppi" + +msgid "News" +msgstr "Uutiset" + +msgid "Current affairs" +msgstr "ajankohtaista" + +msgid "Information" +msgstr "tiedote" + +msgid "Sport" +msgstr "urheilua" + +msgid "Education" +msgstr "opetusohjelmaa" + +msgid "Drama" +msgstr "draamaa" + +msgid "Culture" +msgstr "kulttuuria" + +msgid "Science" +msgstr "tiedeohjelma" + +msgid "Varied" +msgstr "sekalaista" + +msgid "Pop music" +msgstr "pop-musiikkia" + +msgid "Rock music" +msgstr "rock-musiikkia" + +msgid "M.O.R. music" +msgstr "taukomusiikkia" + +msgid "Light classical" +msgstr "kevyttä klassista" + +msgid "Serious classical" +msgstr "klassista" + +msgid "Other music" +msgstr "musiikkia" + +msgid "Alarm" +msgstr "Hälytys" + +msgid "ext. Info" +msgstr "" + +msgid "RTplus" +msgstr "RTplus" + +msgid "Radiotext" +msgstr "Radioteksti" + +msgid " [waiting ...]" +msgstr " [odota ...]" + +msgid "Title :" +msgstr "Kappale :" + +msgid "Artist :" +msgstr "Esittäjä :" + +msgid "Records" +msgstr "Rass-tallenteet" + +msgid "Rass-Image(s) saved from Archiv " +msgstr "" + +msgid "Rass-Image(s) saved from Gallery" +msgstr "" + +msgid "Rass-Image saved" +msgstr "" + +msgid "Rass-Image failed" +msgstr "" + +msgid "Playlist" +msgstr "Soittolista" + +msgid "Sports" +msgstr "Urheilu" + +msgid "Lottery" +msgstr "Arvonta" + +msgid "Weather" +msgstr "Sää" + +msgid "Stockmarket" +msgstr "Pörssikurssit" + +msgid "Other" +msgstr "Sekalaiset" + +msgid "extra Info since" +msgstr "" + +msgid "RTplus Memory since" +msgstr "RTplus-muisti alkaen" + +msgid "Programme" +msgstr "Ohjelma" + +msgid "Stat.Short" +msgstr "" + +msgid "Station" +msgstr "Asema" + +msgid "Now" +msgstr "Nyt" + +msgid "...Part" +msgstr "...osa" + +msgid "Next" +msgstr "Seuraavaksi" + +msgid "Host" +msgstr "Juontaja" + +msgid "Edit.Staff" +msgstr "Henkilökunta" + +msgid "Homepage" +msgstr "Kotisivu" + +msgid "Interactivity" +msgstr "Interaktiivinen" + +msgid "Phone-Hotline" +msgstr "Suoralinja puhelimelle" + +msgid "Phone-Studio" +msgstr "Puhelin studioon" + +#, fuzzy +msgid "SMS-Studio" +msgstr "Puhelin studioon" + +msgid "Email-Hotline" +msgstr "Suoralinja sähköpostille" + +msgid "Email-Studio" +msgstr "Sähköposti studioon" + +msgid "Info" +msgstr "Lisätiedot" + +msgid "NewsLocal" +msgstr "Paikallisuutiset" + +msgid "DateTime" +msgstr "Ajankohtaista" + +msgid "Traffic" +msgstr "Liikenne" + +msgid "Advertising" +msgstr "Mainos" + +msgid "Url" +msgstr "Linkki" + +msgid "Exit" +msgstr "Lopeta" + +msgid "Info-File saved" +msgstr "" + +msgid "RTplus-File saved" +msgstr "RTplus-tiedosto tallennettu" + +msgid "last seen Radiotext" +msgstr "viimeksi nähty radioteksti" + +msgid "Time" +msgstr "Kellonaika" + +msgid "Title" +msgstr "Kappale" + +msgid "Artist" +msgstr "Esittäjä" + +msgid "Refresh Off" +msgstr "Älä päivitä" + +msgid "Refresh On" +msgstr "Päivitä" + +msgid "Back" +msgstr "Takaisin" + +msgid "Radio Background-Image/RDS-Text" +msgstr "Taustakuva ja RDS-teksti radiokanaville" + +msgid "Show RDS-Radiotext" +msgstr "Näytä RDS-teksti" + +msgid "Off" +msgstr "pois" + +msgid "only Text" +msgstr "vain teksti" + +msgid "Text+TagInfo" +msgstr "teksti+tunniste" + +msgid "only, if some" +msgstr "jos saatavilla" + +msgid "always" +msgstr "aina" + +msgid "Top" +msgstr "yläreuna" + +msgid "Bottom" +msgstr "alareuna" + +msgid "latest at Top" +msgstr "ylöspäin" + +msgid "latest at Bottom" +msgstr "alaspäin" + +msgid "Black" +msgstr "musta" + +msgid "White" +msgstr "valkoinen" + +msgid "Red" +msgstr "punainen" + +msgid "Green" +msgstr "vihreä" + +msgid "Yellow" +msgstr "keltainen" + +msgid "Magenta" +msgstr "magenta" + +msgid "Blue" +msgstr "sininen" + +msgid "Cyan" +msgstr "syaani" + +msgid "Transparent" +msgstr "läpinäkyvä" + +msgid "about MainMenu" +msgstr "päävalikosta" + +msgid "Automatic" +msgstr "automaattisesti" + +msgid "only Taginfo" +msgstr "vain tunniste" + +msgid "Rass only" +msgstr "vain Rass" + +msgid "Rass+Text mixed" +msgstr "Teksti ja Rass" + +msgid "Activate" +msgstr "Aktiivinen" + +msgid "Use StillPicture-Function" +msgstr "" + +msgid "Hide MainMenuEntry" +msgstr "Piilota valinta päävalikosta" + +msgid "RDSText Function" +msgstr "RDS-tekstin toiminto" + +msgid "RDSText OSD-Position" +msgstr "RDS-tekstin sijainti" + +msgid "RDSText OSD-Titlerow" +msgstr "RDS-tekstin kappale" + +msgid "RDSText OSD-Rows (1-5)" +msgstr "RDS-tekstin rivimäärä" + +msgid "RDSText OSD-Scrollmode" +msgstr "RDS-tekstin vieritystapa" + +msgid "RDSText OSD-Taginfo" +msgstr "RDS-tekstin tunnistetiedot" + +msgid "RDSText OSD-Skincolors used" +msgstr "Käytä RDS-tekstille ulkoasun värejä" + +msgid "RDSText OSD-Backgr.Color" +msgstr "RDS-tekstin taustaväri" + +msgid "RDSText OSD-Backgr.Transp." +msgstr "RDS-tekstin taustan läpinäkyvyys" + +msgid "RDSText OSD-Foregr.Color" +msgstr "RDS-tekstin väri" + +msgid "RDSText OSD-Timeout (0-1440 min)" +msgstr "RDS-tekstin odotusaika (0-1440min)" + +msgid "RDSText OSD-Display" +msgstr "RDS-tekstin esitys" + +msgid "RDSText StatusMsg (lcdproc & co)" +msgstr "RDS-tekstin toiminto laajennoksille" + +msgid "RDSText Rass-Function" +msgstr "Käytä RDS-tekstin Rass-toimintoa" + +msgid "External Info-Request" +msgstr "" + +#~ msgid "with <0>" +#~ msgstr "'0'-näppäimellä" diff --git a/po/fr_FR.po b/po/fr_FR.po new file mode 100644 index 0000000..e8e6493 --- /dev/null +++ b/po/fr_FR.po @@ -0,0 +1,350 @@ +# VDR plugin language source file. +# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> +# This file is distributed under the same license as the VDR package. +# +msgid "" +msgstr "" +"Project-Id-Version: VDR 1.5.7\n" +"Report-Msgid-Bugs-To: <see README>\n" +"POT-Creation-Date: 2013-05-31 20:15+0200\n" +"PO-Revision-Date: 2007-09-14 16:12+0200\n" +"Last-Translator: Michaël Nival, Patrice Staudt\n" +"Language-Team: <vdr@linuxtv.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-1\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "unknown program type" +msgstr "Type de programme inconnu" + +msgid "News" +msgstr "Informations" + +msgid "Current affairs" +msgstr "Affaires courantes" + +msgid "Information" +msgstr "Information" + +msgid "Sport" +msgstr "Sport" + +msgid "Education" +msgstr "Education" + +msgid "Drama" +msgstr "Drame" + +msgid "Culture" +msgstr "Culture" + +msgid "Science" +msgstr "Science" + +msgid "Varied" +msgstr "Divers" + +msgid "Pop music" +msgstr "Musique Pop" + +msgid "Rock music" +msgstr "Musique Rock" + +msgid "M.O.R. music" +msgstr "Musique M.O.R." + +msgid "Light classical" +msgstr "Classique facile" + +msgid "Serious classical" +msgstr "Classique sérieux" + +msgid "Other music" +msgstr "Autre musique" + +msgid "Alarm" +msgstr "Alarme" + +msgid "ext. Info" +msgstr "Infos externe" + +msgid "RTplus" +msgstr "RTplus" + +msgid "Radiotext" +msgstr "Radio Texte" + +msgid " [waiting ...]" +msgstr " [attente ...]" + +msgid "Title :" +msgstr "Titre :" + +msgid "Artist :" +msgstr "Artiste :" + +msgid "Records" +msgstr "Archive" + +msgid "Rass-Image(s) saved from Archiv " +msgstr "Rass-image(2) saugarde de l'archive" + +msgid "Rass-Image(s) saved from Gallery" +msgstr "Rass-image(2) saugarde de la gallerie" + +msgid "Rass-Image saved" +msgstr "Rass-Image sauvegarder" + +msgid "Rass-Image failed" +msgstr "Rass-Image erreur" + +msgid "Playlist" +msgstr "Playlist" + +msgid "Sports" +msgstr "Sports" + +msgid "Lottery" +msgstr "Loterie" + +msgid "Weather" +msgstr "Météo" + +msgid "Stockmarket" +msgstr "Bourse" + +msgid "Other" +msgstr "Autre" + +msgid "extra Info since" +msgstr "Info extern depuis" + +msgid "RTplus Memory since" +msgstr "Mémoire de RTplus depuis" + +msgid "Programme" +msgstr "Programme" + +msgid "Stat.Short" +msgstr "" + +msgid "Station" +msgstr "Station" + +msgid "Now" +msgstr "Maintenant" + +msgid "...Part" +msgstr "...Détail" + +msgid "Next" +msgstr "Suivant" + +msgid "Host" +msgstr "Animateur" + +msgid "Edit.Staff" +msgstr "Personne" + +msgid "Homepage" +msgstr "Page d'accueil" + +msgid "Interactivity" +msgstr "Interactivité" + +msgid "Phone-Hotline" +msgstr "Téléphone hotline" + +msgid "Phone-Studio" +msgstr "Téléphone studio" + +#, fuzzy +msgid "SMS-Studio" +msgstr "Téléphone studio" + +msgid "Email-Hotline" +msgstr "E-mail hotline" + +msgid "Email-Studio" +msgstr "E-mail studio" + +msgid "Info" +msgstr "D'autres informations" + +msgid "NewsLocal" +msgstr "Information local" + +msgid "DateTime" +msgstr "Date-Heure" + +msgid "Traffic" +msgstr "Traffic" + +msgid "Advertising" +msgstr "Publicité" + +msgid "Url" +msgstr "Url" + +msgid "Exit" +msgstr "Sortir" + +msgid "Info-File saved" +msgstr "Sauvegarde du fichier inf" + +msgid "RTplus-File saved" +msgstr "Sauvé fichier TTplus" + +msgid "last seen Radiotext" +msgstr "Dernier Radio-texte" + +msgid "Time" +msgstr "Temps" + +msgid "Title" +msgstr "Titre" + +msgid "Artist" +msgstr "Artiste" + +msgid "Refresh Off" +msgstr "Arrêter actualisation" + +msgid "Refresh On" +msgstr "Démarrer actualisation" + +msgid "Back" +msgstr "Retour" + +msgid "Radio Background-Image/RDS-Text" +msgstr "Image de fond pour les radio/RDS-Texte" + +msgid "Show RDS-Radiotext" +msgstr "Afficher RDS" + +msgid "Off" +msgstr "Off" + +msgid "only Text" +msgstr "Seulement le texte" + +msgid "Text+TagInfo" +msgstr "Texte+Tag d'info" + +msgid "only, if some" +msgstr "Seulement, si disponible" + +msgid "always" +msgstr "Toujours" + +msgid "Top" +msgstr "Haut" + +msgid "Bottom" +msgstr "Bas" + +msgid "latest at Top" +msgstr "En haut" + +msgid "latest at Bottom" +msgstr "En bas" + +msgid "Black" +msgstr "Noir" + +msgid "White" +msgstr "Blanc" + +msgid "Red" +msgstr "Rouge" + +msgid "Green" +msgstr "Vert" + +msgid "Yellow" +msgstr "Jaune" + +msgid "Magenta" +msgstr "Magenta" + +msgid "Blue" +msgstr "Bleu" + +msgid "Cyan" +msgstr "Cyan" + +msgid "Transparent" +msgstr "Transparent" + +msgid "about MainMenu" +msgstr "A propos de menu principal" + +msgid "Automatic" +msgstr "Automatique" + +msgid "only Taginfo" +msgstr "Seulement Tag Info" + +msgid "Rass only" +msgstr "Rass seulement" + +msgid "Rass+Text mixed" +msgstr "Texte par dessus Rass" + +msgid "Activate" +msgstr "Activer" + +msgid "Use StillPicture-Function" +msgstr "Utiliser fonction image de font" + +msgid "Hide MainMenuEntry" +msgstr "Cacher l'entrée dans le menu principal" + +msgid "RDSText Function" +msgstr "Fonction de RDS-Texte" + +msgid "RDSText OSD-Position" +msgstr "Position OSD de RDS-Texte" + +msgid "RDSText OSD-Titlerow" +msgstr "Titre OSD de RDS-Texte" + +msgid "RDSText OSD-Rows (1-5)" +msgstr "Ligne OSD de RDS-Texte (1-5)" + +msgid "RDSText OSD-Scrollmode" +msgstr "Mode Scroll OSD de RDS-Texte " + +msgid "RDSText OSD-Taginfo" +msgstr "Tag info OSD de RDS-Texte" + +msgid "RDSText OSD-Skincolors used" +msgstr "Couleur du skin utilisé de RDS-texte" + +msgid "RDSText OSD-Backgr.Color" +msgstr "Couleur de fond OSD de RDS-Texte" + +msgid "RDSText OSD-Backgr.Transp." +msgstr "Fond transparent OSD de RDS-Texte" + +msgid "RDSText OSD-Foregr.Color" +msgstr "Couleur du texte OSD de RDS-Texte" + +msgid "RDSText OSD-Timeout (0-1440 min)" +msgstr "Timeout OSD de RDS-Texte (0-1440 min)" + +msgid "RDSText OSD-Display" +msgstr "Affichage OSD de RDS-Texte" + +msgid "RDSText StatusMsg (lcdproc & co)" +msgstr "Statut message de RDS-Texte (lcdproc & co)" + +msgid "RDSText Rass-Function" +msgstr "Fonction Rass de RDSTexte" + +msgid "External Info-Request" +msgstr "Demande d'infos externe" + +#~ msgid "with <0>" +#~ msgstr "avec <0>" diff --git a/po/hu_HU.po b/po/hu_HU.po new file mode 100644 index 0000000..5cf5fce --- /dev/null +++ b/po/hu_HU.po @@ -0,0 +1,350 @@ +# VDR plugin language source file. +# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> +# This file is distributed under the same license as the VDR package. +# +msgid "" +msgstr "" +"Project-Id-Version: VDR 1.5.7\n" +"Report-Msgid-Bugs-To: <see README>\n" +"POT-Creation-Date: 2013-05-31 20:15+0200\n" +"PO-Revision-Date: 2007-08-13 19:21+0200\n" +"Last-Translator: Füley István\n" +"Language-Team: <vdr@linuxtv.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-2\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "unknown program type" +msgstr "ismeretlen adástipus" + +msgid "News" +msgstr "Hírek" + +msgid "Current affairs" +msgstr "aktuális" + +msgid "Information" +msgstr "információ" + +msgid "Sport" +msgstr "sport" + +msgid "Education" +msgstr "nevelés" + +msgid "Drama" +msgstr "rádiójáték" + +msgid "Culture" +msgstr "kultúra" + +msgid "Science" +msgstr "tudomány" + +msgid "Varied" +msgstr "vegyes" + +msgid "Pop music" +msgstr "pop zene" + +msgid "Rock music" +msgstr "rock zene" + +msgid "M.O.R. music" +msgstr "könnyûzene" + +msgid "Light classical" +msgstr "könnyû klasszikus" + +msgid "Serious classical" +msgstr "komolyzene" + +msgid "Other music" +msgstr "egyéb zene" + +msgid "Alarm" +msgstr "Riasztó" + +msgid "ext. Info" +msgstr "" + +msgid "RTplus" +msgstr "RTplus" + +msgid "Radiotext" +msgstr "Rádiótext" + +msgid " [waiting ...]" +msgstr "[várakozás...]" + +msgid "Title :" +msgstr "Cím :" + +msgid "Artist :" +msgstr "Elõadó :" + +msgid "Records" +msgstr "Archívum" + +msgid "Rass-Image(s) saved from Archiv " +msgstr "Rass-kép(ek) elmentve az archívumból" + +msgid "Rass-Image(s) saved from Gallery" +msgstr "Rass-kép(ek) elmentve a galériából" + +msgid "Rass-Image saved" +msgstr "Rass-Kép elmentve." + +msgid "Rass-Image failed" +msgstr "Sikertelen Rass-Kép mentés" + +msgid "Playlist" +msgstr "Playlist" + +msgid "Sports" +msgstr "Sport" + +msgid "Lottery" +msgstr "Lottó" + +msgid "Weather" +msgstr "Idõjárás" + +msgid "Stockmarket" +msgstr "Börze" + +msgid "Other" +msgstr "Egyéb" + +msgid "extra Info since" +msgstr "" + +msgid "RTplus Memory since" +msgstr "RTplus innen kezdve" + +msgid "Programme" +msgstr "Programinfó" + +msgid "Stat.Short" +msgstr "" + +msgid "Station" +msgstr "Rádióadó" + +msgid "Now" +msgstr "Most" + +msgid "...Part" +msgstr "...rész" + +msgid "Next" +msgstr "Következõ" + +msgid "Host" +msgstr "Müsorvezetõ" + +msgid "Edit.Staff" +msgstr "Stáb" + +msgid "Homepage" +msgstr "Honlap" + +msgid "Interactivity" +msgstr "Interaktivitás" + +msgid "Phone-Hotline" +msgstr "Telefonos forródrót" + +msgid "Phone-Studio" +msgstr "Telefon studió" + +#, fuzzy +msgid "SMS-Studio" +msgstr "Telefon studió" + +msgid "Email-Hotline" +msgstr "E-mail forródrót" + +msgid "Email-Studio" +msgstr "E-mail studió" + +msgid "Info" +msgstr "Egyéb információ" + +msgid "NewsLocal" +msgstr "Helyi hírek" + +msgid "DateTime" +msgstr "Dátum-óra" + +msgid "Traffic" +msgstr "Forgalom" + +msgid "Advertising" +msgstr "Reklám" + +msgid "Url" +msgstr "Weblink" + +msgid "Exit" +msgstr "Kilépés" + +msgid "Info-File saved" +msgstr "" + +msgid "RTplus-File saved" +msgstr "RTplus-file elmentve" + +msgid "last seen Radiotext" +msgstr "utoljára vett rádiótext" + +msgid "Time" +msgstr "Idõ" + +msgid "Title" +msgstr "Cím" + +msgid "Artist" +msgstr "Elõadó" + +msgid "Refresh Off" +msgstr "Frissítés ki" + +msgid "Refresh On" +msgstr "Frissítés be" + +msgid "Back" +msgstr "Vissza" + +msgid "Radio Background-Image/RDS-Text" +msgstr "Rádió háttérkép/RDS-Text" + +msgid "Show RDS-Radiotext" +msgstr "RDS-Text megjelenítése" + +msgid "Off" +msgstr "ki" + +msgid "only Text" +msgstr "csak Text" + +msgid "Text+TagInfo" +msgstr "Text és Taginfo" + +msgid "only, if some" +msgstr "csak, ha létezik" + +msgid "always" +msgstr "mindig" + +msgid "Top" +msgstr "fenn" + +msgid "Bottom" +msgstr "lenn" + +msgid "latest at Top" +msgstr "legfrisebbet felülre" + +msgid "latest at Bottom" +msgstr "legfrisebbet alulra" + +msgid "Black" +msgstr "fekete" + +msgid "White" +msgstr "fehér" + +msgid "Red" +msgstr "vörös" + +msgid "Green" +msgstr "zöld" + +msgid "Yellow" +msgstr "sárga" + +msgid "Magenta" +msgstr "bíbor" + +msgid "Blue" +msgstr "kék" + +msgid "Cyan" +msgstr "cián" + +msgid "Transparent" +msgstr "átlátszó" + +msgid "about MainMenu" +msgstr "mint a fõmenüben" + +msgid "Automatic" +msgstr "automatikus" + +msgid "only Taginfo" +msgstr "csak Taginfo" + +msgid "Rass only" +msgstr "csak Rass" + +msgid "Rass+Text mixed" +msgstr "Text és Rass" + +msgid "Activate" +msgstr "Aktív" + +msgid "Use StillPicture-Function" +msgstr "" + +msgid "Hide MainMenuEntry" +msgstr "Elrejtés a fõmenüben" + +msgid "RDSText Function" +msgstr "RDS-Text funkció " + +msgid "RDSText OSD-Position" +msgstr "Az RDS-Text OSD pozicíója" + +msgid "RDSText OSD-Titlerow" +msgstr "RDS-Text OSD fejléc" + +msgid "RDSText OSD-Rows (1-5)" +msgstr "RDS-Text OSD sorok száma (1-5)" + +msgid "RDSText OSD-Scrollmode" +msgstr "RDS-Text OSD görgetésének módja" + +msgid "RDSText OSD-Taginfo" +msgstr "RDS-Text OSD-Taginfo" + +msgid "RDSText OSD-Skincolors used" +msgstr "Felhasznált RDS-Text színek" + +msgid "RDSText OSD-Backgr.Color" +msgstr "RDS-Text háttérszín" + +msgid "RDSText OSD-Backgr.Transp." +msgstr "RDS-Text háttér átlátszósága" + +msgid "RDSText OSD-Foregr.Color" +msgstr "RDS-Text fontszín" + +msgid "RDSText OSD-Timeout (0-1440 min)" +msgstr "RDS-Text idõtúllépés (0-1440 perc)" + +msgid "RDSText OSD-Display" +msgstr "RDS-Text megjelenítés" + +msgid "RDSText StatusMsg (lcdproc & co)" +msgstr "RDS-Text állapotüzenet (lcdproc, stb)" + +msgid "RDSText Rass-Function" +msgstr "RDS Rass funkció" + +msgid "External Info-Request" +msgstr "" + +#~ msgid "with <0>" +#~ msgstr "<0> bill." diff --git a/po/it_IT.po b/po/it_IT.po new file mode 100644 index 0000000..eab61d8 --- /dev/null +++ b/po/it_IT.po @@ -0,0 +1,350 @@ +# VDR plugin language source file. +# Copyright (C) 2007 Klaus Schmidinger <kls@cadsoft.de> +# This file is distributed under the same license as the VDR package. +# Klaus Schmidinger <kls@cadsoft.de>, 2000 +# +msgid "" +msgstr "" +"Project-Id-Version: VDR 1.5.7\n" +"Report-Msgid-Bugs-To: <see README>\n" +"POT-Creation-Date: 2013-05-31 20:15+0200\n" +"PO-Revision-Date: 2008-06-15 22:39+0100\n" +"Last-Translator: Diego Pierotto <vdr-italian@tiscali.it>\n" +"Language-Team: <vdr@linuxtv.org>\n" +"Language: \n" +"MIME-Version: 1.0\n" +"Content-Type: text/plain; charset=ISO-8859-15\n" +"Content-Transfer-Encoding: 8bit\n" + +msgid "unknown program type" +msgstr "tipo programma sconosciuto" + +msgid "News" +msgstr "Notizie" + +msgid "Current affairs" +msgstr "Attualità" + +msgid "Information" +msgstr "Informazione" + +msgid "Sport" +msgstr "Sport" + +msgid "Education" +msgstr "Istruzione" + +msgid "Drama" +msgstr "Dramma" + +msgid "Culture" +msgstr "Cultura" + +msgid "Science" +msgstr "Scienza" + +msgid "Varied" +msgstr "Altro" + +msgid "Pop music" +msgstr "Musica Pop" + +msgid "Rock music" +msgstr "Musica Rock" + +msgid "M.O.R. music" +msgstr "Musica M.O.R." + +msgid "Light classical" +msgstr "Classica leggera" + +msgid "Serious classical" +msgstr "Classica seria" + +msgid "Other music" +msgstr "Altra musica" + +msgid "Alarm" +msgstr "Allarme" + +msgid "ext. Info" +msgstr "Info esterne" + +msgid "RTplus" +msgstr "RTplus" + +msgid "Radiotext" +msgstr "Radio testo" + +msgid " [waiting ...]" +msgstr " [attendere ...]" + +msgid "Title :" +msgstr "Titolo :" + +msgid "Artist :" +msgstr "Artista :" + +msgid "Records" +msgstr "Archivio" + +msgid "Rass-Image(s) saved from Archiv " +msgstr "Immagini Rass salvate dall'Archivio" + +msgid "Rass-Image(s) saved from Gallery" +msgstr "Immagini Rass salvate dalla Galleria" + +msgid "Rass-Image saved" +msgstr "Immagine Rass salvata" + +msgid "Rass-Image failed" +msgstr "Immagine Rass fallita" + +msgid "Playlist" +msgstr "Lista esecuzione" + +msgid "Sports" +msgstr "Sport" + +msgid "Lottery" +msgstr "Lotteria" + +msgid "Weather" +msgstr "Meteo" + +msgid "Stockmarket" +msgstr "Borse" + +msgid "Other" +msgstr "Altro" + +msgid "extra Info since" +msgstr "Info extra da" + +msgid "RTplus Memory since" +msgstr "Memoria RTplus da" + +msgid "Programme" +msgstr "Programma" + +msgid "Stat.Short" +msgstr "Brevi statistiche" + +msgid "Station" +msgstr "Stazione" + +msgid "Now" +msgstr "Adesso" + +msgid "...Part" +msgstr "...Dettaglio" + +msgid "Next" +msgstr "Prossimo" + +msgid "Host" +msgstr "Animatore" + +msgid "Edit.Staff" +msgstr "Staff" + +msgid "Homepage" +msgstr "Pagina princ." + +msgid "Interactivity" +msgstr "Interattività" + +msgid "Phone-Hotline" +msgstr "Telefono assistenza" + +msgid "Phone-Studio" +msgstr "Telefono studio" + +msgid "SMS-Studio" +msgstr "SMS studio" + +msgid "Email-Hotline" +msgstr "Email assistenza" + +msgid "Email-Studio" +msgstr "Email studio" + +msgid "Info" +msgstr "Informazioni" + +msgid "NewsLocal" +msgstr "Notizie locali" + +msgid "DateTime" +msgstr "Data-Ora" + +msgid "Traffic" +msgstr "Traffico" + +msgid "Advertising" +msgstr "Pubblicità" + +msgid "Url" +msgstr "Sito web" + +msgid "Exit" +msgstr "Esci" + +msgid "Info-File saved" +msgstr "Info file salvate" + +msgid "RTplus-File saved" +msgstr "File RTplus salvato" + +msgid "last seen Radiotext" +msgstr "ultimo radio testo letto" + +msgid "Time" +msgstr "Ora" + +msgid "Title" +msgstr "Titolo" + +msgid "Artist" +msgstr "Artista" + +msgid "Refresh Off" +msgstr "Disattiva aggiornamenti" + +msgid "Refresh On" +msgstr "Attiva aggiornamenti" + +msgid "Back" +msgstr "Indietro" + +msgid "Radio Background-Image/RDS-Text" +msgstr "Immagine sfondo per Radio/Testo RDS" + +msgid "Show RDS-Radiotext" +msgstr "Mostra testi RDS" + +msgid "Off" +msgstr "Disattivo" + +msgid "only Text" +msgstr "solo testo" + +msgid "Text+TagInfo" +msgstr "Testo+Scheda info" + +msgid "only, if some" +msgstr "solo, se disp." + +msgid "always" +msgstr "sempre" + +msgid "Top" +msgstr "Alto" + +msgid "Bottom" +msgstr "Basso" + +msgid "latest at Top" +msgstr "ultimo in alto" + +msgid "latest at Bottom" +msgstr "ultimo in basso" + +msgid "Black" +msgstr "Nero" + +msgid "White" +msgstr "Bianco" + +msgid "Red" +msgstr "Rosso" + +msgid "Green" +msgstr "Verde" + +msgid "Yellow" +msgstr "Giallo" + +msgid "Magenta" +msgstr "Magenta" + +msgid "Blue" +msgstr "Blu" + +msgid "Cyan" +msgstr "Ciano" + +msgid "Transparent" +msgstr "Trasparente" + +msgid "about MainMenu" +msgstr "info menu princ." + +msgid "Automatic" +msgstr "Automatica" + +msgid "only Taginfo" +msgstr "solo scheda info" + +msgid "Rass only" +msgstr "Solo Rass" + +msgid "Rass+Text mixed" +msgstr "Rass+testo misto" + +msgid "Activate" +msgstr "Attiva" + +msgid "Use StillPicture-Function" +msgstr "Utilizza funz. immagine princ." + +msgid "Hide MainMenuEntry" +msgstr "Nascondi voce menu principale" + +msgid "RDSText Function" +msgstr "Funzione testo RDS" + +msgid "RDSText OSD-Position" +msgstr "Posizione OSD testo RDS" + +msgid "RDSText OSD-Titlerow" +msgstr "Riga titolo OSD testo RDS" + +msgid "RDSText OSD-Rows (1-5)" +msgstr "Righe OSD testo RDS (1-5)" + +msgid "RDSText OSD-Scrollmode" +msgstr "Mod. scorr. OSD testo RDS" + +msgid "RDSText OSD-Taginfo" +msgstr "Campo info OSD testo RDS" + +msgid "RDSText OSD-Skincolors used" +msgstr "Colori interf. OSD testo RDS" + +msgid "RDSText OSD-Backgr.Color" +msgstr "Colore sfondo OSD testo RDS" + +msgid "RDSText OSD-Backgr.Transp." +msgstr "Trasp. sfondo OSD testo RDS" + +msgid "RDSText OSD-Foregr.Color" +msgstr "Colore car. OSD testo RDS" + +msgid "RDSText OSD-Timeout (0-1440 min)" +msgstr "Scad. testo RDS (0-1440 min)" + +msgid "RDSText OSD-Display" +msgstr "Visualizz. OSD testo RDS" + +msgid "RDSText StatusMsg (lcdproc & co)" +msgstr "Mess. stato testo RDS (lcdproc & co)" + +msgid "RDSText Rass-Function" +msgstr "Funzione Rass testo RDS" + +msgid "External Info-Request" +msgstr "Richiesta info esterna" + +#~ msgid "with <0>" +#~ msgstr "con <0>" @@ -0,0 +1,731 @@ +/* + * radio.c: A plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include <vdr/plugin.h> +#include <vdr/status.h> +#include <vdr/config.h> +#include <vdr/interface.h> +#include <vdr/transfer.h> +#include "getopt.h" +#include "radioaudio.h" +#include "radiotools.h" +#include "radioepg.h" +#include "inforx.h" + +#if VDRVERSNUM < 10737 + #error This version of radio-plugin requires vdr >= 1.7.37 +#endif + +static const char *VERSION = "1.0.0"; +static const char *DESCRIPTION = trNOOP("Radio Background-Image/RDS-Text"); +static const char *MAINMENUENTRY = trNOOP("Show RDS-Radiotext"); +char *ConfigDir; +char *DataDir; +char *LiveFile; +char *ReplayFile; + +// Setup-Params +int S_Activate = false; +int S_StillPic = 1; +int S_HMEntry = false; +int S_RtFunc = 1; +int S_RtOsdTitle = 1; +int S_RtOsdTags = 2; +int S_RtOsdPos = 1; +int S_RtOsdRows = 2; +int S_RtOsdLoop = 0; +int S_RtOsdTO = 60; +int S_RtSkinColor = 1; +int S_RtBgCol = 0; +int S_RtBgTra = 0xA0; +int S_RtFgCol = 1; +int S_RtDispl = 1; +int S_RtMsgItems = 0; +//int S_RtpMemNo = 25; +int S_RassText = 1; +int S_ExtInfo = 0; +uint32_t rt_color[9]; +int S_Verbose = 1; +int S_Encrypted = 0; +// Radiotext +char RT_Text[5][RT_MEL]; +char RTP_Artist[RT_MEL], RTP_Title[RT_MEL]; +int RT_Info, RT_Index, RT_PTY; +time_t RTP_Starttime; +bool RT_OsdTO = false, RTplus_Osd = false, RT_ReOpen = false; +int RT_OsdTOTemp = 0, Radio_CA = 0; +int RT_Charset = 0; // 0= ISO-8859-1, 1= UTF8, 2= .. +// RadioCheck +const cChannel *chan; +int IsRadioOrReplay; +// Info +bool DoInfoReq = false, InfoRequest = false; +int InfoTimeout = 3; + +struct RadioTextService_v1_0 { + int rds_info; // 0= no / 1= Text / 2= Text + RTplus-Tags (Item,Artist) + int rds_pty; // 0-31 + char *rds_text; + char *rds_title; + char *rds_artist; + struct tm *title_start; +}; + + +// --- cRadioCheck ------------------------------------------------------- + +class cRadioCheck: public cThread { +private: + static cRadioCheck *RadioCheck; +protected: + virtual void Action(void); + void Stop(void); +public: + cRadioCheck(void); + virtual ~cRadioCheck(); + static void Init(void); + static void Exit(void); +}; + +cRadioCheck *cRadioCheck::RadioCheck = NULL; + +cRadioCheck::cRadioCheck(void) +: cThread("radiocheck") +{ + IsRadioOrReplay = 0; +} + +cRadioCheck::~cRadioCheck() { + if (Running()) + Stop(); +} + +void cRadioCheck::Init(void) { + if (RadioCheck == NULL) { + RadioCheck = new cRadioCheck; + RadioCheck->Start(); + } +} + +void cRadioCheck::Exit(void) { + if (RadioCheck != NULL) { + RadioCheck->Stop(); + DELETENULL(RadioCheck); + } +} + +void cRadioCheck::Stop(void) { + Cancel(10); +} + +void cRadioCheck::Action(void) +{ + + if ((S_Verbose && 0x0f) >= 2) + printf("vdr-radio: background-checking starts\n"); + + while (Running()) { + cCondWait::SleepMs(2000); + + // check Live-Radio + if (IsRadioOrReplay == 1 && chan != NULL) { + if (chan->Vpid()) { + isyslog("radio: channnel '%s' got Vpid= %d", chan->Name(), chan->Vpid()); + IsRadioOrReplay = 0; + Channels.SwitchTo(cDevice::CurrentChannel()); + //cDevice::PrimaryDevice()->SwitchChannel(chan, true); + } + else { + if ((InfoTimeout-=2) <= 0) { + InfoTimeout = 20; + int chtid = chan->Tid(); + // Kanal-EPG PresentEvent + if (chan->Apid(0) > 0 && (chtid == PREMIERERADIO_TID || chtid == KDRADIO_TID + || chtid == UMRADIO_TID1 || chtid == UMRADIO_TID2 || chtid == UMRADIO_TID3 || chtid == UMRADIO_TID4 || chtid == UMRADIO_TID5)) { + cSchedulesLock schedLock; + const cSchedules *scheds = cSchedules::Schedules(schedLock); + if (scheds != NULL) { + const cSchedule *sched = scheds->GetSchedule(chan->GetChannelID()); + if (sched != NULL) { + const cEvent *present = sched->GetPresentEvent(); + if (present != NULL) { + if (chtid == PREMIERERADIO_TID) // Premiere + InfoTimeout = epg_premiere(present->Title(), present->Description(), present->StartTime(), present->EndTime()); + else if (chtid == KDRADIO_TID) // Kabel Deutschland + InfoTimeout = epg_kdg(present->Description(), present->StartTime(), present->EndTime()); + else // Unity Media Kabel + InfoTimeout = epg_unitymedia(present->Description(), present->StartTime(), present->EndTime()); + InfoRequest = true; + } + else + dsyslog("radio: no event.present (Tid= %d, Apid= %d)", chtid, chan->Apid(0)); + } + else + dsyslog("radio: no schedule (Tid= %d, Apid= %d)", chtid, chan->Apid(0)); + } + } + // Artist/Title with external script? + else if (chan->Apid(0) > 0 && DoInfoReq) { + InfoTimeout = info_request(chtid, chan->Apid(0)); + InfoRequest = (InfoTimeout > 0); + } + } + } + } + + // temp. OSD-CloseTimeout + (RT_OsdTOTemp > 0) ? RT_OsdTOTemp -= 2 : RT_OsdTOTemp = 0; // in sec like this cycletime + + // Radiotext-Autodisplay + if ((S_RtDispl == 2) && (RT_Info >= 0) && !RT_OsdTO && (RT_OsdTOTemp == 0) && RT_ReOpen && !Skins.IsOpen() && !cOsd::IsOpen()) + cRemote::CallPlugin("radio"); + } + + if ((S_Verbose && 0x0f) >= 2) + printf("vdr-radio: background-checking ends\n"); +} + + +// --- cMenuSetupRadio ------------------------------------------------------- + +class cMenuSetupRadio : public cMenuSetupPage { +private: + int newS_Activate; + int newS_StillPic; + int newS_HMEntry; + int newS_RtFunc; + int newS_RtOsdTitle; + int newS_RtOsdTags; + int newS_RtOsdPos; + int newS_RtOsdRows; + int newS_RtOsdLoop; + int newS_RtOsdTO; + int newS_RtSkinColor; + int newS_RtBgCol; + int newS_RtBgTra; + int newS_RtFgCol; + int newS_RtDispl; + int newS_RtMsgItems; + //int newS_RtpMemNo; + int newS_RassText; + int newS_ExtInfo; + const char *T_RtFunc[3]; + const char *T_RtOsdTags[3]; + const char *T_RtOsdPos[2]; + const char *T_RtOsdLoop[2]; + const char *T_RtBgColor[9]; + const char *T_RtFgColor[9]; + const char *T_RtDisplay[3]; + const char *T_RtMsgItems[4]; + const char *T_RassText[3]; +protected: + virtual void Store(void); +public: + cMenuSetupRadio(void); +}; + +cMenuSetupRadio::cMenuSetupRadio(void) +{ + T_RtFunc[0] = tr("Off"); + T_RtFunc[1] = tr("only Text"); + T_RtFunc[2] = tr("Text+TagInfo"); + T_RtOsdTags[0] = tr("Off"); + T_RtOsdTags[1] = tr("only, if some"); + T_RtOsdTags[2] = tr("always"); + T_RtOsdPos[0] = tr("Top"); + T_RtOsdPos[1] = tr("Bottom"); + T_RtOsdLoop[0] = tr("latest at Top"); + T_RtOsdLoop[1] = tr("latest at Bottom"); + T_RtBgColor[0] = T_RtFgColor[0] = tr ("Black"); + T_RtBgColor[1] = T_RtFgColor[1] = tr ("White"); + T_RtBgColor[2] = T_RtFgColor[2] = tr ("Red"); + T_RtBgColor[3] = T_RtFgColor[3] = tr ("Green"); + T_RtBgColor[4] = T_RtFgColor[4] = tr ("Yellow"); + T_RtBgColor[5] = T_RtFgColor[5] = tr ("Magenta"); + T_RtBgColor[6] = T_RtFgColor[6] = tr ("Blue"); + T_RtBgColor[7] = T_RtFgColor[7] = tr ("Cyan"); + T_RtBgColor[8] = T_RtFgColor[8] = tr ("Transparent"); + T_RtDisplay[0] = tr("Off"); + T_RtDisplay[1] = tr("about MainMenu"); + T_RtDisplay[2] = tr("Automatic"); + T_RtMsgItems[0] = tr("Off"); + T_RtMsgItems[1] = tr("only Taginfo"); + T_RtMsgItems[2] = tr("only Text"); + T_RtMsgItems[3] = tr("Text+TagInfo"); + T_RassText[0] = tr("Off"); + T_RassText[1] = tr("Rass only"); + T_RassText[2] = tr("Rass+Text mixed"); + + newS_Activate = S_Activate; + newS_StillPic = S_StillPic; + newS_Activate = S_Activate; + newS_RtFunc = S_RtFunc; + newS_RtOsdTitle = S_RtOsdTitle; + newS_RtOsdTags = S_RtOsdTags; + newS_RtOsdPos = S_RtOsdPos; + newS_RtOsdRows = S_RtOsdRows; + newS_RtOsdLoop = S_RtOsdLoop; + newS_RtOsdTO = S_RtOsdTO; + newS_RtSkinColor = S_RtSkinColor; + newS_RtBgCol = S_RtBgCol; + newS_RtBgTra = S_RtBgTra; + newS_RtFgCol = S_RtFgCol; + newS_RtDispl = (S_RtDispl > 2 ? 2 : S_RtDispl); + newS_RtMsgItems = S_RtMsgItems; + //newS_RtpMemNo = S_RtpMemNo; + newS_RassText = S_RassText; + newS_ExtInfo = S_ExtInfo; + + Add(new cMenuEditBoolItem( tr("Activate"), &newS_Activate)); + Add(new cMenuEditBoolItem( tr("Use StillPicture-Function"), &newS_StillPic)); + Add(new cMenuEditBoolItem( tr("Hide MainMenuEntry"), &newS_HMEntry)); + Add(new cMenuEditStraItem( tr("RDSText Function"), &newS_RtFunc, 3, T_RtFunc)); + Add(new cMenuEditStraItem( tr("RDSText OSD-Position"), &newS_RtOsdPos, 2, T_RtOsdPos)); + Add(new cMenuEditBoolItem( tr("RDSText OSD-Titlerow"), &newS_RtOsdTitle)); + Add(new cMenuEditIntItem( tr("RDSText OSD-Rows (1-5)"), &newS_RtOsdRows, 1, 5)); + Add(new cMenuEditStraItem( tr("RDSText OSD-Scrollmode"), &newS_RtOsdLoop, 2, T_RtOsdLoop)); + Add(new cMenuEditStraItem( tr("RDSText OSD-Taginfo"), &newS_RtOsdTags, 3, T_RtOsdTags)); + Add(new cMenuEditBoolItem( tr("RDSText OSD-Skincolors used"), &newS_RtSkinColor)); + if (newS_RtSkinColor == 0) { + Add(new cMenuEditStraItem( tr("RDSText OSD-Backgr.Color"), &newS_RtBgCol, 9, T_RtBgColor)); + Add(new cMenuEditIntItem( tr("RDSText OSD-Backgr.Transp."), &newS_RtBgTra, 1, 255)); + Add(new cMenuEditStraItem( tr("RDSText OSD-Foregr.Color"), &newS_RtFgCol, 8, T_RtFgColor)); + } + Add(new cMenuEditIntItem( tr("RDSText OSD-Timeout (0-1440 min)"), &newS_RtOsdTO, 0, 1440)); + Add(new cMenuEditStraItem( tr("RDSText OSD-Display"), &newS_RtDispl, 3, T_RtDisplay)); + Add(new cMenuEditStraItem( tr("RDSText StatusMsg (lcdproc & co)"), &newS_RtMsgItems, 4, T_RtMsgItems)); + //Add(new cMenuEditIntItem( tr("RDSplus Memorynumber (10-99)"), &newS_RtpMemNo, 10, 99)); + Add(new cMenuEditStraItem( tr("RDSText Rass-Function"), &newS_RassText, 3, T_RassText)); + Add(new cMenuEditBoolItem( tr("External Info-Request"), &newS_ExtInfo)); +} + +void cMenuSetupRadio::Store(void) +{ + SetupStore("Activate", S_Activate = newS_Activate); + SetupStore("UseStillPic", S_StillPic = newS_StillPic); + SetupStore("HideMenuEntry", S_HMEntry = newS_HMEntry); + SetupStore("RDSText-Function", S_RtFunc = newS_RtFunc); + SetupStore("RDSText-OsdTitle", S_RtOsdTitle = newS_RtOsdTitle); + SetupStore("RDSText-OsdTags", S_RtOsdTags = newS_RtOsdTags); + SetupStore("RDSText-OsdPosition", S_RtOsdPos = newS_RtOsdPos); + SetupStore("RDSText-OsdRows", S_RtOsdRows = newS_RtOsdRows); + SetupStore("RDSText-OsdLooping", S_RtOsdLoop = newS_RtOsdLoop); + SetupStore("RDSText-OsdSkinColor", S_RtSkinColor = newS_RtSkinColor); + SetupStore("RDSText-OsdBackgrColor", S_RtBgCol = newS_RtBgCol); + SetupStore("RDSText-OsdBackgrTrans", S_RtBgTra = newS_RtBgTra); + SetupStore("RDSText-OsdForegrColor", S_RtFgCol = newS_RtFgCol); + SetupStore("RDSText-OsdTimeout", S_RtOsdTO = newS_RtOsdTO); + SetupStore("RDSText-Display", S_RtDispl = newS_RtDispl); + SetupStore("RDSText-MsgItems", S_RtMsgItems = newS_RtMsgItems); + //SetupStore("RDSplus-MemNumber", S_RtpMemNo = newS_RtpMemNo); + SetupStore("RDSText-Rass", S_RassText = newS_RassText); + SetupStore("ExtInfo-Req", S_ExtInfo = newS_ExtInfo); +} + + +// --- cPluginRadio ------------------------------------------------------- + + +class cRadioImage; +class cRadioAudio; + +class cPluginRadio : public cPlugin, cStatus { +private: + // Add any member variables or functions you may need here. + bool ConfigDirParam; + bool DataDirParam; + bool LiveFileParam; + bool ReplayFileParam; + cRadioImage *radioImage; + cRadioAudio *radioAudio; +public: + cPluginRadio(void); + virtual ~cPluginRadio(); + virtual const char *Version(void) { return VERSION; } + virtual const char *Description(void) { return tr(DESCRIPTION); } + virtual const char *CommandLineHelp(void); + virtual bool ProcessArgs(int argc, char *argv[]); + virtual bool Start(void); + virtual void Stop(void); + virtual void Housekeeping(void); + virtual void MainThreadHook(void) { } + virtual cString Active(void) { return NULL; } + virtual const char *MainMenuEntry(void) { return (S_Activate==0 || S_RtFunc==0 || S_RtDispl==0 || S_HMEntry ? NULL : tr(MAINMENUENTRY)); } + virtual cOsdObject *MainMenuAction(void); + virtual cMenuSetupPage *SetupMenu(void); + virtual bool SetupParse(const char *Name, const char *Value); + virtual bool Service(const char *Id, void *Data); + virtual const char **SVDRPHelpPages(void); + virtual cString SVDRPCommand(const char *Command, const char *Option, int &ReplyCode); +protected: + virtual void ChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView); + virtual void Replaying(const cControl *Control, const char *Name, const char *FileName, bool On); +}; + +cPluginRadio::cPluginRadio(void) +{ + // Initialize any member variables here. + // DON'T DO ANYTHING ELSE THAT MAY HAVE SIDE EFFECTS, REQUIRE GLOBAL + // VDR OBJECTS TO EXIST OR PROADUCE ANY OUTPUT! + + radioImage = 0; + radioAudio = 0; + + ConfigDirParam = false; + DataDirParam = false; + LiveFileParam = false; + ReplayFileParam = false; + + rt_color[0] = 0xFF000000; //Black + rt_color[1] = 0xFFFCFCFC; //White + rt_color[2] = 0xFFFC1414; //Red + rt_color[3] = 0xFF24FC24; //Green + rt_color[4] = 0xFFFCC024; //Yellow + rt_color[5] = 0xFFB000FC; //Magenta + rt_color[6] = 0xFF0000FC; //Blue + rt_color[7] = 0xFF00FCFC; //Cyan + rt_color[8] = 0x00000000; //Transparent +} + +cPluginRadio::~cPluginRadio() +{ + // Clean up after yourself! + if (ConfigDir) free(ConfigDir); + if (DataDir) free(DataDir); + if (LiveFile) free(LiveFile); + if (ReplayFile) free(ReplayFile); + + cRadioCheck::Exit(); + radioImage->Exit(); +} + + +const char *cPluginRadio::CommandLineHelp(void) +{ + // Return a string that describes all known command line options. + return " -f dir, --files=dir use dir as image directory (default: <vdrconfig>/plugins/radio)\n" + " -d dir, --data=dir use dir as temp. data directory (default: <vdrconfig>/plugins/radio)\n" + " -l file, --live=file use file as default mpegfile in livemode (default: <dir>/radio.mpg)\n" + " -r file, --replay=file use file as default mpegfile in replaymode (default: <dir>/replay.mpg)\n" + " -e 1, --encrypted=1 use transfermode/backgroundimage @ encrypted radiochannels \n" + " -v level, --verbose=level set verbose level (default = 1, 0 = Off, 1 = RDS-Text+Tags, \n" + " 2 = +RDS-Telegram/Debug, 3 = +RawData 0xfd, \n" + " += 16 = Rass-Info, +=32 = TMC-Info) \n"; +} + +bool cPluginRadio::ProcessArgs(int argc, char *argv[]) +{ + // Implement command line argument processing here if applicable. + + static struct option long_options[] = { + { "files", required_argument, NULL, 'f' }, + { "data", required_argument, NULL, 'd' }, + { "live", required_argument, NULL, 'l' }, + { "replay", required_argument, NULL, 'r' }, + { "encrypted", required_argument, NULL, 'e' }, + { "verbose", required_argument, NULL, 'v' }, + { NULL } + }; + + int c; + while ((c = getopt_long(argc, argv, "f:d:l:r:e:v:", long_options, NULL)) != -1) { + switch (c) { + case 'f': + printf("vdr-radio: arg files-dir = %s\n", optarg); + ConfigDir = strdup(optarg); + ConfigDirParam = true; + break; + case 'd': + printf("vdr-radio: arg data-dir = %s\n", optarg); + DataDir = strdup(optarg); + DataDirParam = true; + break; + case 'l': + printf("vdr-radio: arg live-mpeg = %s\n", optarg); + LiveFile = strdup(optarg); + LiveFileParam = true; + break; + case 'r': + printf("vdr-radio: arg replay-mpeg = %s\n", optarg); + ReplayFile = strdup(optarg); + ReplayFileParam = true; + break; + case 'v': + printf("vdr-radio: arg verbose = %s\n", optarg); + if (isnumber(optarg)) + S_Verbose = atoi(optarg); + break; + case 'e': + printf("vdr-radio: arg encrypted = %s\n", optarg); + if (isnumber(optarg)) + S_Encrypted = atoi(optarg); + break; + default: + printf("vdr-radio: arg char = %c\n", c); + return false; + } + } + + return true; +} + +bool cPluginRadio::Start(void) +{ + // Start any background activities the plugin shall perform. + printf("vdr-radio: Radio-Plugin Backgr.Image/RDS-Text starts...\n"); + + radioImage = new cRadioImage; + if (!radioImage) + return false; + radioImage->Init(); + + radioAudio = new cRadioAudio; + if (!radioAudio) + return false; + + if (!ConfigDirParam) + ConfigDir = strdup(ConfigDirectory(Name())); + if (!DataDirParam) { + DataDir = strdup("/tmp/vdr-radio.XXXXXX"); + mkdtemp(DataDir); + } + if (!LiveFileParam) + asprintf(&LiveFile, "%s/radio.mpg", ConfigDir); + if (!ReplayFileParam) + asprintf(&ReplayFile, "%s/replay.mpg", ConfigDir); + + cRadioCheck::Init(); + + return true; +} + +void cPluginRadio::Stop(void) +{ + cRadioCheck::Exit(); + + if (IsRadioOrReplay > 0) + radioAudio->DisableRadioTextProcessing(); + + radioImage->Exit(); +} + +void cPluginRadio::Housekeeping(void) +{ + // Perform any cleanup or other regular tasks. +} + +cOsdObject *cPluginRadio::MainMenuAction(void) +{ + // Perform the action when selected from the main VDR menu. +/* if (!cDevice::PrimaryDevice()->Transferring() && !cDevice::PrimaryDevice()->Replaying()) { + //cRemote::CallPlugin("radio"); // try again later <-- disabled, looping if activate over menu @ tv in dvb-livemode + } */ + if (S_Activate > 0 && S_RtFunc > 0 && S_RtDispl > 0 && IsRadioOrReplay > 0) { + if (!RTplus_Osd) { + cRadioTextOsd *rtosd = new cRadioTextOsd(); + return rtosd; + } + else { + cRTplusOsd *rtposd = new cRTplusOsd(); + return rtposd; + } + } + + return NULL; +} + +cMenuSetupPage *cPluginRadio::SetupMenu(void) +{ + // Return a setup menu in case the plugin supports one. + return new cMenuSetupRadio; +} + +bool cPluginRadio::SetupParse(const char *Name, const char *Value) +{ + // Parse your own setup parameters and store their values. + if (!strcasecmp(Name, "Activate")) S_Activate = atoi(Value); + else if (!strcasecmp(Name, "UseStillPic")) S_StillPic = atoi(Value); + else if (!strcasecmp(Name, "HideMenuEntry")) S_HMEntry = atoi(Value); + else if (!strcasecmp(Name, "RDSText-Function")) S_RtFunc = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdTitle")) S_RtOsdTitle = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdTags")) S_RtOsdTags = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdPosition")) S_RtOsdPos = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdRows")) { + S_RtOsdRows = atoi(Value); + if (S_RtOsdRows > 5) S_RtOsdRows = 5; + } + else if (!strcasecmp(Name, "RDSText-OsdLooping")) S_RtOsdLoop = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdSkinColor")) S_RtSkinColor = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdBackgrColor")) S_RtBgCol = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdBackgrTrans")) S_RtBgTra = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdForegrColor")) S_RtFgCol = atoi(Value); + else if (!strcasecmp(Name, "RDSText-OsdTimeout")) { + S_RtOsdTO = atoi(Value); + if (S_RtOsdTO > 1440) S_RtOsdTO = 1440; + } + else if (!strcasecmp(Name, "RDSText-Display")) S_RtDispl = atoi(Value); + else if (!strcasecmp(Name, "RDSText-MsgItems")) S_RtMsgItems = atoi(Value); + //else if (!strcasecmp(Name, "RDSplus-MemNumber")) S_RtpMemNo = atoi(Value); + else if (!strcasecmp(Name, "RDSText-Rass")) S_RassText = atoi(Value); + else if (!strcasecmp(Name, "ExtInfo-Req")) S_ExtInfo = atoi(Value); + else + return false; + + return true; +} + +bool cPluginRadio::Service(const char *Id, void *Data) +{ + if (strcmp(Id,"RadioTextService-v1.0") == 0 && S_Activate > 0 && S_RtFunc >= 1) { + if (Data) { + RadioTextService_v1_0 *data = (RadioTextService_v1_0*)Data; + data->rds_pty = RT_PTY; + data->rds_info = (RT_Info < 0) ? 0 : RT_Info; + int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; + data->rds_text = RT_Text[ind]; + data->rds_title = RTP_Title; + data->rds_artist = RTP_Artist; + struct tm tm_store; + data->title_start = localtime_r(&RTP_Starttime, &tm_store); + } + return true; + } + + return false; +} + +const char **cPluginRadio::SVDRPHelpPages(void) +{ + static const char *HelpPages[] = { + "RTINFO\n" + " Print the radiotext information.", + "RTCLOSE\n" + " Close the radiotext-osd,\n" + " Reopen can only be done over menu or channelswitch.", + "RTTCLOSE\n" + " Close the radiotext-osd temporarily,\n" + " Reopen will be done after osd-messagetimeout.", + NULL + }; + + return HelpPages; +} + +cString cPluginRadio::SVDRPCommand(const char *Command, const char *Option, int &ReplyCode) +{ + if (strcasecmp(Command, "RTINFO") == 0) { + // we use the default reply code here + if (RT_Info == 2) { + int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; + return cString::sprintf(" Radiotext: %s\n RT-Title : %s\n RT-Artist: %s\n", RT_Text[ind], RTP_Title, RTP_Artist); + } + else if (RT_Info == 1) { + int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; + return cString::sprintf(" Radiotext: %s\n", RT_Text[ind]); + } + else + return cString::sprintf(" Radiotext not available (yet)\n"); + } + else if (strcasecmp(Command, "RTCLOSE") == 0) { + // we use the default reply code here + if (RT_OsdTO) + return cString::sprintf("RT-OSD already closed"); + else { + RT_OsdTO = true; + return cString::sprintf("RT-OSD will be closed now"); + } + } + else if (strcasecmp(Command, "RTTCLOSE") == 0) { + // we use the default reply code here + RT_OsdTOTemp = 2 * Setup.OSDMessageTime; + return cString::sprintf("RT-OSD will be temporarily closed"); + } + + return NULL; +} + +void cPluginRadio::ChannelSwitch(const cDevice *Device, int ChannelNumber, bool LiveView) +{ + if (Device != cDevice::PrimaryDevice()) return; + + IsRadioOrReplay = Radio_CA = 0; + radioAudio->DisableRadioTextProcessing(); + InfoTimeout = 3; + + if (S_Activate == false) return; + + char *image; + if (cDevice::CurrentChannel() == ChannelNumber) { + chan = ChannelNumber ? Channels.GetByNumber(ChannelNumber) : NULL; + if (chan != NULL && chan->Vpid() == 0 && chan->Apid(0) > 0) { + asprintf(&image, "%s/%s.mpg", ConfigDir, chan->Name()); + if (!file_exists(image)) { + dsyslog("radio: channel-image not found '%s' (Channelname= %s)", image, chan->Name()); + free(image); + asprintf(&image, "%s", LiveFile); + if (!file_exists(image)) + dsyslog("radio: live-image not found '%s' (Channelname= %s)", image, chan->Name()); + } + dsyslog("radio: [ChannelSwitch # Apid= %d, Ca= %d] channelname '%s', use image '%s'", chan->Apid(0), chan->Ca(0), chan->Name(), image); + if ((Radio_CA = chan->Ca(0)) == 0 || S_Encrypted == 1) + cDevice::PrimaryDevice()->ForceTransferMode(); + radioImage->SetBackgroundImage(image); + radioAudio->EnableRadioTextProcessing(chan->Name(), chan->Apid(0), false); + free(image); + IsRadioOrReplay = 1; + DoInfoReq = (S_ExtInfo > 0); + } + } +} + +void cPluginRadio::Replaying(const cControl *Control, const char *Name, const char *FileName, bool On) +{ + IsRadioOrReplay = 0; + radioAudio->DisableRadioTextProcessing(); + + if (S_Activate == false) return; + + bool isRadio = false; + + if (On && FileName != NULL) { + char *vdrfile; + // check VDR PES-Recordings + asprintf(&vdrfile, "%s/001.vdr", FileName); + if (file_exists(vdrfile)) { + cFileName fn(FileName, false, true, true); + cUnbufferedFile *f = fn.Open(); + if (f) { + uchar b[4] = { 0x00, 0x00, 0x00, 0x00 }; + ReadFrame(f, b, sizeof (b), sizeof (b)); + fn.Close(); + isRadio = (b[0] == 0x00) && (b[1] == 0x00) && (b[2] == 0x01) && (0xc0 <= b[3] && b[3] <= 0xdf); + } + } + // check VDR TS-Recordings + asprintf(&vdrfile, "%s/info", FileName); + if (file_exists(vdrfile)) { + cRecordingInfo rfi(FileName); + if (rfi.Read()) { + if (rfi.FramesPerSecond() > 0 && rfi.FramesPerSecond() < 18) // max. seen 13.88 @ ARD-RadioTP 320k + isRadio = true; + } + } + free(vdrfile); + } + + if (isRadio) { + if (!file_exists(ReplayFile)) + dsyslog("radio: replay-image not found '%s'", ReplayFile); + else + radioImage->SetBackgroundImage(ReplayFile); + radioAudio->EnableRadioTextProcessing(Name, 0, true); + IsRadioOrReplay = 2; + } +} + + +VDRPLUGINCREATOR(cPluginRadio); // Don't touch this! diff --git a/radioaudio.c b/radioaudio.c new file mode 100644 index 0000000..8c6a2dc --- /dev/null +++ b/radioaudio.c @@ -0,0 +1,2806 @@ +/* + * radioaudio.c - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include <vdr/remote.h> +#include <vdr/status.h> +#include <vdr/plugin.h> +#include "radioaudio.h" +#include "radioskin.h" +#include "radiotools.h" +#include <math.h> + +// OSD-Symbols +#include "symbols/rds.xpm" +#include "symbols/arec.xpm" +#include "symbols/rass.xpm" +#include "symbols/radio.xpm" +#include "symbols/index.xpm" +#include "symbols/marker.xpm" +#include "symbols/page1.xpm" +#include "symbols/pages2.xpm" +#include "symbols/pages3.xpm" +#include "symbols/pages4.xpm" +#include "symbols/no0.xpm" +#include "symbols/no1.xpm" +#include "symbols/no2.xpm" +#include "symbols/no3.xpm" +#include "symbols/no4.xpm" +#include "symbols/no5.xpm" +#include "symbols/no6.xpm" +#include "symbols/no7.xpm" +#include "symbols/no8.xpm" +#include "symbols/no9.xpm" +#include "symbols/bok.xpm" +#include "symbols/pageE.xpm" + + +// Radiotext +int RTP_ItemToggle = 1, RTP_TToggle = 0; +bool RT_MsgShow = false, RT_PlusShow = false; +bool RT_Replay = false; +char *RT_Titel, *RTp_Titel; +rtp_classes rtp_content; +// RDS rest +bool RDS_PSShow = false; +int RDS_PSIndex = 0; +char RDS_PSText[12][9]; +char RDS_PTYN[9]; +bool RdsLogo = false; +// plugin audiorecorder service +bool ARec_Receive = false, ARec_Record = false; +// Rass ... +int Rass_Show = -1; // -1=No, 0=Yes, 1=display +int Rass_Archiv = -1; // -1=Off, 0=Index, 1000-9990=Slidenr. +bool Rass_Flags[11][4]; // Slides+Gallery existent +// ... Gallery (1..999) +#define RASS_GALMAX 999 +bool Rass_Gallery[RASS_GALMAX+1]; +int Rass_GalStart, Rass_GalEnd, Rass_GalCount, Rass_SlideFoto; + +cRadioImage *RadioImage; +cRDSReceiver *RDSReceiver; +cRadioAudio *RadioAudio; +cRadioTextOsd *RadioTextOsd; + + +// RDS-Chartranslation: 0x80..0xff +unsigned char rds_addchar[128] = { + 0xe1, 0xe0, 0xe9, 0xe8, 0xed, 0xec, 0xf3, 0xf2, + 0xfa, 0xf9, 0xd1, 0xc7, 0x8c, 0xdf, 0x8e, 0x8f, + 0xe2, 0xe4, 0xea, 0xeb, 0xee, 0xef, 0xf4, 0xf6, + 0xfb, 0xfc, 0xf1, 0xe7, 0x9c, 0x9d, 0x9e, 0x9f, + 0xaa, 0xa1, 0xa9, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, + 0xa8, 0xa9, 0xa3, 0xab, 0xac, 0xad, 0xae, 0xaf, + 0xba, 0xb9, 0xb2, 0xb3, 0xb1, 0xa1, 0xb6, 0xb7, + 0xb5, 0xbf, 0xf7, 0xb0, 0xbc, 0xbd, 0xbe, 0xa7, + 0xc1, 0xc0, 0xc9, 0xc8, 0xcd, 0xcc, 0xd3, 0xd2, + 0xda, 0xd9, 0xca, 0xcb, 0xcc, 0xcd, 0xd0, 0xcf, + 0xc2, 0xc4, 0xca, 0xcb, 0xce, 0xcf, 0xd4, 0xd6, + 0xdb, 0xdc, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, + 0xc3, 0xc5, 0xc6, 0xe3, 0xe4, 0xdd, 0xd5, 0xd8, + 0xde, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xf0, + 0xe3, 0xe5, 0xe6, 0xf3, 0xf4, 0xfd, 0xf5, 0xf8, + 0xfe, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff +}; + +const char* ptynr2string(int nr) +{ + switch (nr) { + // Source: http://www.ebu.ch/trev_255-beale.pdf + case 0: return tr("unknown program type"); + case 1: return tr("News"); + case 2: return tr("Current affairs"); + case 3: return tr("Information"); + case 4: return tr("Sport"); + case 5: return tr("Education"); + case 6: return tr("Drama"); + case 7: return tr("Culture"); + case 8: return tr("Science"); + case 9: return tr("Varied"); + case 10: return tr("Pop music"); + case 11: return tr("Rock music"); + case 12: return tr("M.O.R. music"); + case 13: return tr("Light classical"); + case 14: return tr("Serious classical"); + case 15: return tr("Other music"); + // 16-30 "Spares" + case 31: return tr("Alarm"); + default: return "?"; + } +} + +// announce text/items for lcdproc & other +void radioStatusMsg(void) +{ + if (!RT_MsgShow || S_RtMsgItems <= 0) + return; + + if (S_RtMsgItems >= 2) { + char temp[100]; + int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; + strcpy(temp, RT_Text[ind]); + cStatus::MsgOsdTextItem(rtrim(temp), false); + } + + if ((S_RtMsgItems == 1 || S_RtMsgItems >= 3) && ((S_RtOsdTags == 1 && RT_PlusShow) || S_RtOsdTags >= 2)) { + struct tm tm_store; + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + cStatus::MsgOsdProgramme(mktime(ts), RTP_Title, RTP_Artist, 0, NULL, NULL); + } +} + + +// --- cRadioImage ------------------------------------------------------- + +cRadioImage::cRadioImage(void) + : cThread("radioimage") +{ + imagepath = 0; + imageShown = false; + RadioImage = this; +} + +cRadioImage::~cRadioImage() { + if (Running()) + Stop(); + free(imagepath); +} + +void cRadioImage::Init(void) { + RadioImage->Start(); +} + +void cRadioImage::Exit(void) { + if (RadioImage != NULL) { + RadioImage->Stop(); + DELETENULL(RadioImage); + } +} + +void cRadioImage::Stop(void) { + Cancel(2); +} + +void cRadioImage::Action(void) +{ + if ((S_Verbose && 0x0f) >= 2) + printf("vdr-radio: image-showing starts\n"); + + while (Running()) { + cCondWait::SleepMs(333); + if ((IsRadioOrReplay == 1) && imagepath && !imageShown) { // only live $20090905 + imageShown = true; + Show(imagepath); + } + } + + if ((S_Verbose && 0x0f) >= 2) + printf("vdr-radio: image-showing ends\n"); +} + +void cRadioImage::Show(const char *file) +{ + uchar *buffer; + int fd; + struct stat st; + struct video_still_picture sp; + if ((fd = open (file, O_RDONLY)) >= 0) { + fstat (fd, &st); + sp.iFrame = (char *) malloc (st.st_size); + if (sp.iFrame) { + sp.size = st.st_size; + if (read (fd, sp.iFrame, sp.size) > 0) { + buffer = (uchar *) sp.iFrame; + if (S_StillPic > 0) + cDevice::PrimaryDevice()->StillPicture(buffer, sp.size); + else { + for (int i = 1; i <= 25; i++) + send_pes_packet (buffer, sp.size, i); + } + } + free (sp.iFrame); + } + else {} + close (fd); + } + else {} +} + +void cRadioImage::send_pes_packet(unsigned char *data, int len, int timestamp) +{ +#define PES_MAX_SIZE 2048 + int ptslen = timestamp ? 5 : 1; + static unsigned char pes_header[PES_MAX_SIZE]; + pes_header[0] = pes_header[1] = 0; + pes_header[2] = 1; + pes_header[3] = 0xe0; + + while(len > 0) { + int payload_size = len; + if(6 + ptslen + payload_size > PES_MAX_SIZE) + payload_size = PES_MAX_SIZE - (6 + ptslen); + pes_header[4] = (ptslen + payload_size) >> 8; + pes_header[5] = (ptslen + payload_size) & 255; + if (ptslen == 5) { + int x; + x = (0x02 << 4) | (((timestamp >> 30) & 0x07) << 1) | 1; + pes_header[8] = x; + x = ((((timestamp >> 15) & 0x7fff) << 1) | 1); + pes_header[7] = x >> 8; + pes_header[8] = x & 255; + x = ((((timestamp) & 0x7fff) < 1) | 1); + pes_header[9] = x >> 8; + pes_header[10] = x & 255; + } + else + pes_header[6] = 0x0f; + + memcpy(&pes_header[6 + ptslen], data, payload_size); + cDevice::PrimaryDevice()->PlayPes(pes_header, 6 + ptslen + payload_size); + len -= payload_size; + data += payload_size; + ptslen = 1; + } +} + +void cRadioImage::SetBackgroundImage(const char *Image) +{ + free(imagepath); + imagepath = 0; + + if (Image) { + imageShown = false; + asprintf(&imagepath, "%s", Image); + } +} + + +// --- cRDSReceiver ------------------------------------------------------------ + +cRDSReceiver::cRDSReceiver(int Pid) +{ + dsyslog("radio: additional RDS-Receiver starts on Pid=%d", Pid); + + pid = Pid; + rt_start = rt_bstuff = false; +} + +cRDSReceiver::~cRDSReceiver() +{ + dsyslog("radio: additional RDS-Receiver stopped"); +} + +void cRDSReceiver::Receive(uchar *Data, int Length) +{ + const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data + static unsigned char mtext[mframel+1]; + static int index; + static int mec = 0; + + // check TS-Size, -Sync, PID, Payload + if (Length != TS_SIZE || Data[0] != 0x47 || pid != ((Data[1] & 0x1f)<<8)+Data[2] || !(Data[3] & 0x10)) + return; + + int offset; + if (Data[1] & 0x40) { // 1.TS-Frame, payload-unit-start + offset = (Data[3] & 0x20) ? Data[4] + 11 : 10; // Header + ADFL + 6 byte: PES-Startcode, -StreamID, -PacketLength + if (Data[offset-3] == 0xbd) { // StreamID = Private stream 1 (for rds) + offset += 3; // 3 byte: Extension + Headerlength + offset += Data[offset-1]; + } + else + return; + } + else + offset = (Data[3] & 0x20) ? Data[4] + 5 : 4; // Header + ADFL + + if (TS_SIZE-offset <= 0) + return; + + // print TS-RawData with RDS + if ((S_Verbose & 0x0f) >= 3) { + printf("\n\nTS-Data(%d): ", Length); + for (int a=0; a<Length; a++) + printf("%02x ", Data[a]); + printf("(End)\n\n"); + } + + for (int i = 0, val = 0; i < (TS_SIZE-offset); i++) { + val = Data[offset+i]; + + if (val == 0xfe) { // Start + index = -1; + rt_start = true; + rt_bstuff = false; + mec = 0; + if ((S_Verbose & 0x0f) >= 2) + printf("\nRDS-Start: "); + } + + if (rt_start) { + if ((S_Verbose & 0x0f) >= 2) + printf("%02x ", val); + // byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff + if (rt_bstuff) { + switch (val) { + case 0x00: mtext[index] = 0xfd; break; + case 0x01: mtext[index] = 0xfe; break; + case 0x02: mtext[index] = 0xff; break; + default: mtext[++index] = val; // should never be + } + rt_bstuff = false; + if ((S_Verbose & 0x0f) >= 2) + printf("(Bytestuffing -> %02x) ", mtext[index]); + } + else + mtext[++index] = val; + if (val == 0xfd && index > 0) // stuffing found + rt_bstuff = true; + + // early check for used MEC + if (index == 5) { + //mec = val; + switch (val) { + case 0x0a: // RT + case 0x46: // ODA-Data + case 0x07: // PTY + case 0x3e: // PTYN + case 0x30: // TMC + case 0x02: mec = val; // PS + RdsLogo = true; + break; + default: rt_start = false; + if ((S_Verbose & 0x0f) >= 2) + printf("[RDS-MEC '%02x' not used -> End]\n", val); + } + } + if (index >= mframel) { // max. rdslength, garbage ? + rt_start = false; + if ((S_Verbose & 0x0f) >= 2) + printf("(RDS-Error: too long, garbage ?)\n"); + } + } + + if (rt_start && val == 0xff) { // End + rt_start = false; + if ((S_Verbose & 0x0f) >= 2) + printf("(RDS-End)\n"); + if (index < 9) { // min. rdslength, garbage ? + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error: too short -> garbage ?\n"); + } + else { + // crc16-check + unsigned short crc16 = crc16_ccitt(mtext, index-3, true); + if (crc16 != (mtext[index-2]<<8)+mtext[index-1]) { + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error: wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[index-2], mtext[index-1]); + } + else { + switch (mec) { + case 0x0a: RadioAudio->RadiotextDecode(mtext, index); // Radiotext + break; + case 0x46: switch ((mtext[7]<<8)+mtext[8]) { // ODA-ID + case 0x4bd7: RadioAudio->RadiotextDecode(mtext, index); // RT+ + break; + case 0x0d45: + case 0xcd46: if ((S_Verbose & 0x20) > 0) { + unsigned char tmc[6]; // TMC Alert-C + int i; + for (i=9; i<=(index-3); i++) + tmc[i-9] = mtext[i]; + tmc_parser(tmc, i-8); + } + break; + default: if ((S_Verbose & 0x0f) >= 2) + printf("[RDS-ODA AID '%02x%02x' not used -> End]\n", mtext[7], mtext[8]); + } + break; + case 0x07: RT_PTY = mtext[8]; // PTY + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-PTY set to '%s'\n", ptynr2string(RT_PTY)); + break; + case 0x3e: RadioAudio->RDS_PsPtynDecode(true, mtext, index); // PTYN + break; + case 0x02: RadioAudio->RDS_PsPtynDecode(false, mtext, index); // PS + break; + case 0x30: if ((S_Verbose & 0x20) > 0) { // TMC Alert-C + unsigned char tmc[6]; + int i; + for (i=7; i<=(index-3); i++) + tmc[i-7] = mtext[i]; + tmc_parser(tmc, i-6); + } + break; + } + } + } + } + + } +} + + +// --- cRadioAudio ------------------------------------------------------------- + +cRadioAudio::cRadioAudio() + : cAudio() + , enabled(false) + , first_packets(0) +{ + RadioAudio = this; + dsyslog("radio: new cRadioAudio"); +} + +cRadioAudio::~cRadioAudio() +{ + dsyslog("radio: delete cRadioAudio"); +} + +/* for old pes-recordings */ +void cRadioAudio::Play(const uchar *Data, int Length, uchar Id) +{ + if (!enabled) + return; + + if (Id < 0xc0 || Id > 0xdf) + return; + + // Rass-Images Slideshow + if (S_RassText > 0 && Rass_Archiv == -1 && Rass_Show == 1) { + Rass_Show = 0; + char *image; + asprintf(&image, "%s/Rass_show.mpg", DataDir); + RadioImage->SetBackgroundImage(image); + free(image); + } + + // check Audo-Bitrate + if (S_RtFunc < 1) + return; + if (first_packets < 3) { + first_packets++; + if (first_packets == 3) + bitrate = audiobitrate(Data); + return; + } + + // check Radiotext-PES + if (Radio_CA == 0) + RadiotextCheckPES(Data, Length); +} + +void cRadioAudio::PlayTs(const uchar *Data, int Length) +{ + if (!enabled) + return; + + // Rass-Images Slideshow + if (S_RassText > 0 && Rass_Archiv == -1 && Rass_Show == 1) { + Rass_Show = 0; + char *image; + asprintf(&image, "%s/Rass_show.mpg", DataDir); + RadioImage->SetBackgroundImage(image); + free(image); + } + + if (S_RtFunc < 1) + return; + if (first_packets < 99) { + first_packets++; + return; + } + + // check Radiotext-TS + if (Radio_CA == 0) + RadiotextCheckTS(Data, Length); +} + +/* for old pes-recordings */ +void cRadioAudio::RadiotextCheckPES(const uchar *data, int len) +{ + const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data + static unsigned char mtext[mframel+1]; + static bool rt_start = false, rt_bstuff=false; + static int index; + static int mec = 0; + + int offset = 0; + while (true) { + + int pesl = (offset+5 < len) ? (data[offset+4] << 8) + data[offset+5] + 6 : -1; + if (pesl <= 0 || offset+pesl > len) + return; + + offset += pesl; + int rdsl = data[offset-2]; // RDS DataFieldLength + // RDS DataSync = 0xfd @ end + if (data[offset-1] == 0xfd && rdsl > 0) { + // print RawData with RDS-Info + if ((S_Verbose & 0x0f) >= 3) { + printf("\n\nPES-Data(%d/%d): ", pesl, len); + for (int a=offset-pesl; a<offset; a++) + printf("%02x ", data[a]); + printf("(End)\n\n"); + } + + for (int i = offset-3, val; i > offset-3-rdsl; i--) { // <-- data reverse, from end to start + val = data[i]; + + if (val == 0xfe) { // Start + index = -1; + rt_start = true; + rt_bstuff = false; + if ((S_Verbose & 0x0f) >= 2) + printf("\nRDS-Start: "); + } + + if (rt_start) { + if ((S_Verbose & 0x0f) >= 2) + printf("%02x ", val); + // byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff + if (rt_bstuff) { + switch (val) { + case 0x00: mtext[index] = 0xfd; break; + case 0x01: mtext[index] = 0xfe; break; + case 0x02: mtext[index] = 0xff; break; + default: mtext[++index] = val; // should never be + } + rt_bstuff = false; + if ((S_Verbose & 0x0f) >= 2) + printf("(Bytestuffing -> %02x) ", mtext[index]); + } + else + mtext[++index] = val; + if (val == 0xfd && index > 0) // stuffing found + rt_bstuff = true; + // early check for used MEC + if (index == 5) { + //mec = val; + switch (val) { + case 0x0a: // RT + case 0x46: // ODA-Data + case 0xda: // Rass + case 0x07: // PTY + case 0x3e: // PTYN + case 0x30: // TMC + case 0x02: mec = val; // PS + RdsLogo = true; + break; + default: rt_start = false; + if ((S_Verbose & 0x0f) >= 2) + printf("[RDS-MEC '%02x' not used -> End]\n", val); + } + } + if (index >= mframel) { // max. rdslength, garbage ? + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error(PES): too long, garbage ?\n"); + rt_start = false; + } + } + + if (rt_start && val == 0xff) { // End + if ((S_Verbose & 0x0f) >= 2) + printf("(RDS-End)\n"); + rt_start = false; + if (index < 9) { // min. rdslength, garbage ? + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error(PES): too short -> garbage ?\n"); + } + else { + // crc16-check + unsigned short crc16 = crc16_ccitt(mtext, index-3, true); + if (crc16 != (mtext[index-2]<<8)+mtext[index-1]) { + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error(PES): wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[index-2], mtext[index-1]); + } + else { + switch (mec) { + case 0x0a: RadiotextDecode(mtext, index); // Radiotext + break; + case 0x46: switch ((mtext[7]<<8)+mtext[8]) { // ODA-ID + case 0x4bd7: RadioAudio->RadiotextDecode(mtext, index); // RT+ + break; + case 0x0d45: + case 0xcd46: if ((S_Verbose & 0x20) > 0) { + unsigned char tmc[6]; // TMC Alert-C + int i; + for (i=9; i<=(index-3); i++) + tmc[i-9] = mtext[i]; + tmc_parser(tmc, i-8); + } + break; + default: if ((S_Verbose & 0x0f) >= 2) + printf("[RDS-ODA AID '%02x%02x' not used -> End]\n", mtext[7], mtext[8]); + } + break; + case 0x07: RT_PTY = mtext[8]; // PTY + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-PTY set to '%s'\n", ptynr2string(RT_PTY)); + break; + case 0x3e: RDS_PsPtynDecode(true, mtext, index); // PTYN + break; + case 0x02: RDS_PsPtynDecode(false, mtext, index); // PS + break; + case 0xda: RassDecode(mtext, index); // Rass + break; + case 0x30: if ((S_Verbose & 0x20) > 0) { // TMC Alert-C + unsigned char tmc[6]; + int i; + for (i=7; i<=(index-3); i++) + tmc[i-7] = mtext[i]; + tmc_parser(tmc, i-6); + } + } + } + } + } + + } + } + } +} + +void cRadioAudio::RadiotextCheckTS(const uchar *data, int len) +{ + static int pesfound = 0; + const int mframel = 263; // max. 255(MSG)+4(ADD/SQC/MFL)+2(CRC)+2(Start/Stop) of RDS-data + static unsigned char mtext[mframel+1], lastframe[TS_SIZE-4]; + static int rt_start = 0, rt_bstuff = 0; + static int index; + static int mec = 0; + int i, ii, val; + + /* TS-Frame && Payload, correct AudioPID ? */ + if (data[0] != 0x47 || !(data[3] & 0x10)) {// || audiopid != ((data[1] & 0x1f)<<8) + data[2])) { + pesfound = 0; + return; + } + + if ((S_Verbose & 0x0f) >= 3) { + printf("\n\nTS-Data: "); + for (int a=0; a<len; a++) + printf("%02x ", data[a]); + printf("(TS-End)\n\n"); + } + + int offset = TS_SIZE - 1; + int rdsl = 0, afdl = 0; + if ((data[1] & 0x40) == 0x40) { // 1.TS-Frame + offset = ((data[3] & 0x20)>>4) ? data[4] + 5 : 4; // Header+ADFL + if (data[offset] == 0x00 && data[offset+1] == 0x00 && data[offset+2] == 0x01 && // PES-Startcode + data[offset+3] >= 0xc0 && data[offset+3] <= 0xdf) { // PES-Audiostream MP1/2 + pesfound = 1; + if (!bratefound) { + bitrate = audiobitrate(data+offset); + bratefound = true; + } + return; + } + } + // RDS DataSync = 0xfd @ audio-end + else if (pesfound && data[3] == 0x3f && data[offset] == 0xfd) { // last TS-Frame + rdsl = data[offset-1]; + pesfound = 0; + } + else if (pesfound) { // TS-Frames between + afdl = ((data[3] & 0x20)>>4) ? data[4] + 1 : 0; // AdaptationField-Length + // search for PES-Change + for (i = afdl+3; i < TS_SIZE-4; i++) { + if (data[i] == 0xfd && data[i+1] == 0xff && ((data[i+2] & 0xf0) == 0xf0) && ((data[i+3] & 0x04) == 0x04)) { + // && ((data[i+4] & 0x0f) != 0x0f)) + offset = i; + rdsl = data[offset-1]; + break; + } + } + } + else /* no PES-Audio MPEG-1/2 found */ + return; + + if (rdsl <= 0) { // save payload of last frame with no PES-Change + for (i = TS_SIZE-1, ii = 0; i > 3; i--) + lastframe[ii++] = data[i]; + return; + } + + // RDS data + for (i = offset-2, ii = 0; i > offset-2-rdsl; i--) { // <-- data reverse, from end to start + if (i > afdl+3) + val = data[i]; + else if (ii < TS_SIZE-5) + val = lastframe[ii++]; + else + return; + + if (val == 0xfe) { // Start + index = -1; + rt_start = 1; + rt_bstuff = 0; + mec = 0; + if ((S_Verbose & 0x0f) >= 2) + printf("\nRDS-Start: "); + } + + if (rt_start == 1) { + if ((S_Verbose & 0x0f) >= 2) + printf("%02x ", val); + + // byte-stuffing reverse: 0xfd00->0xfd, 0xfd01->0xfe, 0xfd02->0xff + if (rt_bstuff == 1) { + switch (val) { + case 0x00: mtext[index] = 0xfd; break; + case 0x01: mtext[index] = 0xfe; break; + case 0x02: mtext[index] = 0xff; break; + default: mtext[++index] = val; // should never be + } + rt_bstuff = 0; + if ((S_Verbose & 0x0f) >= 2) + printf("(Bytestuffing -> %02x) ", mtext[index]); + } + else + mtext[++index] = val; + if (val == 0xfd && index > 0) // stuffing found + rt_bstuff = 1; + + // early check for used mec + if (index == 5) { + switch (val) { + case 0x0a: // RT + case 0x46: // ODA-Data + case 0xda: // Rass + case 0x07: // PTY + case 0x3e: // PTYN + case 0x30: // TMC + case 0x02: mec = val; // PS + RdsLogo = true; + break; + default: rt_start = 0; + if ((S_Verbose & 0x0f) >= 2) + printf("[RDS-MEC '%02x' not used -> End]\n", val); + } + } + if (index >= mframel) { // max. rdslength, garbage ? + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error(TS): too long, garbage ?\n"); + rt_start = 0; + } + } + + if (rt_start == 1 && val == 0xff) { // End + if ((S_Verbose & 0x0f) >= 2) + printf("(RDS-End)\n"); + rt_start = 0; + if (index < 9) { // min. rdslength, garbage ? + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error(TS): too short -> garbage ?\n"); + } + else { + // crc16-check + unsigned short crc16 = crc16_ccitt(mtext, index-3, 1); + if (crc16 != (mtext[index-2]<<8)+mtext[index-1]) { + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error(TS): wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[index-2], mtext[index-1]); + } + else { + switch (mec) { + case 0x0a: RadiotextDecode(mtext, index); // Radiotext + break; + case 0x46: switch ((mtext[7]<<8)+mtext[8]) { // ODA-ID + case 0x4bd7: RadiotextDecode(mtext, index); // RT+ + break; + case 0x0d45: + case 0xcd46: if ((S_Verbose & 0x20) > 0) { + unsigned char tmc[6]; // TMC Alert-C + int i; + for (i=9; i<=(index-3); i++) + tmc[i-9] = mtext[i]; + tmc_parser(tmc, i-8); + } + break; + default: if ((S_Verbose & 0x0f) >= 2) + printf("[RDS-ODA AID '%02x%02x' not used -> End]\n", mtext[7], mtext[8]); + } + break; + case 0x07: RT_PTY = mtext[8]; // PTY + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-PTY set to '%s'\n", ptynr2string(RT_PTY)); + break; + case 0x3e: RDS_PsPtynDecode(1, mtext, index); // PTYN + break; + case 0x02: RDS_PsPtynDecode(0, mtext, index); // PS + break; + case 0xda: RassDecode(mtext, index); // Rass + break; + case 0x30: if ((S_Verbose & 0x20) > 0) { // TMC Alert-C + unsigned char tmc[6]; + int i; + for (i=7; i<=(index-3); i++) + tmc[i-7] = mtext[i]; + tmc_parser(tmc, i-6); + } + } + } + } + } + } +} + +void cRadioAudio::RadiotextDecode(unsigned char *mtext, int len) +{ + static bool rtp_itoggle = false; + static int rtp_idiffs = 0; + static cTimeMs rtp_itime; + static char plustext[RT_MEL]; + + // byte 1+2 = ADD (10bit SiteAdress + 6bit EncoderAdress) + // byte 3 = SQC (Sequence Counter 0x00 = not used) + int leninfo = mtext[4]; // byte 4 = MFL (Message Field Length) + if (len >= leninfo+7) { // check complete length + + // byte 5 = MEC (Message Element Code, 0x0a for RT, 0x46 for RTplus) + if (mtext[5] == 0x0a) { + // byte 6+7 = DSN+PSN (DataSetNumber+ProgramServiceNumber, + // ignore here, always 0x00 ?) + // byte 8 = MEL (MessageElementLength, max. 64+1 byte @ RT) + if (mtext[8] == 0 || mtext[8] > RT_MEL || mtext[8] > leninfo-4) { + if ((S_Verbose & 0x0f) >= 1) + printf("RT-Error: Length=0 or not correct (MFL= %d, MEL= %d)\n", mtext[4], mtext[8]); + return; + } + // byte 9 = RT-Status bitcodet (0=AB-flagcontrol, 1-4=Transmission-Number, 5+6=Buffer-Config, + // ingnored, always 0x01 ?) + char temptext[RT_MEL]; + memset(temptext, 0x20, RT_MEL-1); + for (int i = 1, ii = 0; i < mtext[8]; i++) { + if (mtext[9+i] <= 0xfe) + // additional rds-character, see RBDS-Standard, Annex E + temptext[ii++] = (mtext[9+i] >= 0x80) ? rds_addchar[mtext[9+i]-0x80] : mtext[9+i]; + } + memcpy(plustext, temptext, RT_MEL-1); + rds_entitychar(temptext); + // check repeats + bool repeat = false; + for (int ind = 0; ind < S_RtOsdRows; ind++) { + if (memcmp(RT_Text[ind], temptext, RT_MEL-1) == 0) { + repeat = true; + if ((S_Verbose & 0x0f) >= 1) + printf("RText-Rep[%d]: %s\n", ind, RT_Text[ind]); + } + } + if (!repeat) { + memcpy(RT_Text[RT_Index], temptext, RT_MEL-1); + // +Memory + char *temp; + asprintf(&temp, "%s", RT_Text[RT_Index]); + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%s", rtrim(temp)); + free(temp); + if ((S_Verbose & 0x0f) >= 1) + printf("Radiotext[%d]: %s\n", RT_Index, RT_Text[RT_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + } + RTP_TToggle = 0x03; // Bit 0/1 = Title/Artist + RT_MsgShow = true; + (RT_Info > 0) ? : RT_Info = 1; + radioStatusMsg(); + } + + else if (RTP_TToggle > 0 && mtext[5] == 0x46 && S_RtFunc >= 2) { // RTplus tags V2.1, only if RT + if (mtext[6] > leninfo-2 || mtext[6] != 8) { // byte 6 = MEL, only 8 byte for 2 tags + if ((S_Verbose & 0x0f) >= 1) + printf("RTp-Error: Length not correct (MEL= %d)\n", mtext[6]); + return; + } + uint rtp_typ[2], rtp_start[2], rtp_len[2]; + // byte 7+8 = ApplicationID, always 0x4bd7 + // byte 9 = Applicationgroup Typecode / PTY ? + // bit 10#4 = Item Togglebit + // bit 10#3 = Item Runningbit + // Tag1: bit 10#2..11#5 = Contenttype, 11#4..12#7 = Startmarker, 12#6..12#1 = Length + rtp_typ[0] = (0x38 & mtext[10]<<3) | mtext[11]>>5; + rtp_start[0] = (0x3e & mtext[11]<<1) | mtext[12]>>7; + rtp_len[0] = 0x3f & mtext[12]>>1; + // Tag2: bit 12#0..13#3 = Contenttype, 13#2..14#5 = Startmarker, 14#4..14#0 = Length(5bit) + rtp_typ[1] = (0x20 & mtext[12]<<5) | mtext[13]>>3; + rtp_start[1] = (0x38 & mtext[13]<<3) | mtext[14]>>5; + rtp_len[1] = 0x1f & mtext[14]; + if ((S_Verbose & 0x0f) >= 2) + printf("RTplus (tag=Typ/Start/Len): Toggle/Run = %d/%d, tag#1 = %d/%d/%d, tag#2 = %d/%d/%d\n", + (mtext[10]&0x10)>0, (mtext[10]&0x08)>0, rtp_typ[0], rtp_start[0], rtp_len[0], rtp_typ[1], rtp_start[1], rtp_len[1]); + // save info + for (int i = 0; i < 2; i++) { + if (rtp_start[i]+rtp_len[i]+1 >= RT_MEL) { // length-error + if ((S_Verbose & 0x0f) >= 1) + printf("RTp-Error (tag#%d = Typ/Start/Len): %d/%d/%d (Start+Length > 'RT-MEL' !)\n", + i+1, rtp_typ[i], rtp_start[i], rtp_len[i]); + } + else { + char temptext[RT_MEL]; + memset(temptext, 0x20, RT_MEL-1); + memmove(temptext, plustext+rtp_start[i], rtp_len[i]+1); + rds_entitychar(temptext); + // +Memory + memset(rtp_content.temptext, 0x20, RT_MEL-1); + memcpy(rtp_content.temptext, temptext, RT_MEL-1); + switch (rtp_typ[i]) { + case 1: // Item-Title + if ((mtext[10] & 0x08) > 0 && (RTP_TToggle & 0x01) == 0x01) { + RTP_TToggle -= 0x01; + RT_Info = 2; + if (memcmp(RTP_Title, temptext, RT_MEL-1) != 0 || (mtext[10] & 0x10) != RTP_ItemToggle) { + memcpy(RTP_Title, temptext, RT_MEL-1); + if (RT_PlusShow && rtp_itime.Elapsed() > 1000) + rtp_idiffs = (int) rtp_itime.Elapsed()/1000; + if (!rtp_content.item_New) { + RTP_Starttime = time(NULL); + rtp_itime.Set(0); + sprintf(RTP_Artist, "---"); + if (++rtp_content.item_Index >= MAX_RTPC) + rtp_content.item_Index = 0; + rtp_content.item_Start[rtp_content.item_Index] = time(NULL); // todo: replay-mode + rtp_content.item_Artist[rtp_content.item_Index] = NULL; + } + rtp_content.item_New = (!rtp_content.item_New) ? true : false; + if (rtp_content.item_Index >= 0) + asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", rtrim(rtp_content.temptext)); + RT_PlusShow = RT_MsgShow = rtp_itoggle = true; + } + } + break; + case 4: // Item-Artist + if ((mtext[10] & 0x08) > 0 && (RTP_TToggle & 0x02) == 0x02) { + RTP_TToggle -= 0x02; + RT_Info = 2; + if (memcmp(RTP_Artist, temptext, RT_MEL-1) != 0 || (mtext[10] & 0x10) != RTP_ItemToggle) { + memcpy(RTP_Artist, temptext, RT_MEL-1); + if (RT_PlusShow && rtp_itime.Elapsed() > 1000) + rtp_idiffs = (int) rtp_itime.Elapsed()/1000; + if (!rtp_content.item_New) { + RTP_Starttime = time(NULL); + rtp_itime.Set(0); + sprintf(RTP_Title, "---"); + if (++rtp_content.item_Index >= MAX_RTPC) + rtp_content.item_Index = 0; + rtp_content.item_Start[rtp_content.item_Index] = time(NULL); // todo: replay-mode + rtp_content.item_Title[rtp_content.item_Index] = NULL; + } + rtp_content.item_New = (!rtp_content.item_New) ? true : false; + if (rtp_content.item_Index >= 0) + asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", rtrim(rtp_content.temptext)); + RT_PlusShow = RT_MsgShow = rtp_itoggle = true; + } + } + break; + case 12: // Info_News + asprintf(&rtp_content.info_News, "%s", rtrim(rtp_content.temptext)); + break; + case 13: // Info_NewsLocal + asprintf(&rtp_content.info_NewsLocal, "%s", rtrim(rtp_content.temptext)); + break; + case 14: // Info_Stockmarket + if (++rtp_content.info_StockIndex >= MAX_RTPC) + rtp_content.info_StockIndex = 0; + asprintf(&rtp_content.info_Stock[rtp_content.info_StockIndex], "%s", rtrim(rtp_content.temptext)); + break; + case 15: // Info_Sport + if (++rtp_content.info_SportIndex >= MAX_RTPC) + rtp_content.info_SportIndex = 0; + asprintf(&rtp_content.info_Sport[rtp_content.info_SportIndex], "%s", rtrim(rtp_content.temptext)); + break; + case 16: // Info_Lottery + if (++rtp_content.info_LotteryIndex >= MAX_RTPC) + rtp_content.info_LotteryIndex = 0; + asprintf(&rtp_content.info_Lottery[rtp_content.info_LotteryIndex], "%s", rtrim(rtp_content.temptext)); + break; + case 24: // Info_DateTime + asprintf(&rtp_content.info_DateTime, "%s", rtrim(rtp_content.temptext)); + break; + case 25: // Info_Weather + if (++rtp_content.info_WeatherIndex >= MAX_RTPC) + rtp_content.info_WeatherIndex = 0; + asprintf(&rtp_content.info_Weather[rtp_content.info_WeatherIndex], "%s", rtrim(rtp_content.temptext)); + break; + case 26: // Info_Traffic + asprintf(&rtp_content.info_Traffic, "%s", rtrim(rtp_content.temptext)); + break; + case 27: // Info_Alarm + asprintf(&rtp_content.info_Alarm, "%s", rtrim(rtp_content.temptext)); + break; + case 28: // Info_Advert + asprintf(&rtp_content.info_Advert, "%s", rtrim(rtp_content.temptext)); + break; + case 29: // Info_Url + asprintf(&rtp_content.info_Url, "%s", rtrim(rtp_content.temptext)); + break; + case 30: // Info_Other + if (++rtp_content.info_OtherIndex >= MAX_RTPC) + rtp_content.info_OtherIndex = 0; + asprintf(&rtp_content.info_Other[rtp_content.info_OtherIndex], "%s", rtrim(rtp_content.temptext)); + break; + case 31: // Programme_Stationname.Short + asprintf(&rtp_content.prog_StatShort, "%s", rtrim(rtp_content.temptext)); + break; + case 32: // Programme_Stationname.Long + asprintf(&rtp_content.prog_Station, "%s", rtrim(rtp_content.temptext)); + break; + case 33: // Programme_Now + asprintf(&rtp_content.prog_Now, "%s", rtrim(rtp_content.temptext)); + break; + case 34: // Programme_Next + asprintf(&rtp_content.prog_Next, "%s", rtrim(rtp_content.temptext)); + break; + case 35: // Programme_Part + asprintf(&rtp_content.prog_Part, "%s", rtrim(rtp_content.temptext)); + break; + case 36: // Programme_Host + asprintf(&rtp_content.prog_Host, "%s", rtrim(rtp_content.temptext)); + break; + case 37: // Programme_EditorialStaff + asprintf(&rtp_content.prog_EditStaff, "%s", rtrim(rtp_content.temptext)); + break; + case 39: // Programme_Homepage + asprintf(&rtp_content.prog_Homepage, "%s", rtrim(rtp_content.temptext)); + break; + case 41: // Phone_Hotline + asprintf(&rtp_content.phone_Hotline, "%s", rtrim(rtp_content.temptext)); + break; + case 42: // Phone_Studio + asprintf(&rtp_content.phone_Studio, "%s", rtrim(rtp_content.temptext)); + break; + case 44: // SMS_Studio + asprintf(&rtp_content.sms_Studio, "%s", rtrim(rtp_content.temptext)); + break; + case 46: // Email_Hotline + asprintf(&rtp_content.email_Hotline, "%s", rtrim(rtp_content.temptext)); + break; + case 47: // Email_Studio + asprintf(&rtp_content.email_Studio, "%s", rtrim(rtp_content.temptext)); + break; + } + } + } + + // Title-end @ no Item-Running' + if ((mtext[10] & 0x08) == 0) { + sprintf(RTP_Title, "---"); + sprintf(RTP_Artist, "---"); + if (RT_PlusShow) { + RT_PlusShow = false; + rtp_itoggle = true; + rtp_idiffs = (int) rtp_itime.Elapsed()/1000; + RTP_Starttime = time(NULL); + } + RT_MsgShow = (RT_Info > 0); + rtp_content.item_New = false; + } + + if (rtp_itoggle) { + if ((S_Verbose & 0x0f) >= 1) { + struct tm tm_store; + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + if (rtp_idiffs > 0) + printf(" StartTime : %02d:%02d:%02d (last Title elapsed = %d s)\n", + ts->tm_hour, ts->tm_min, ts->tm_sec, rtp_idiffs); + else + printf(" StartTime : %02d:%02d:%02d\n", ts->tm_hour, ts->tm_min, ts->tm_sec); + printf(" RTp-Title : %s\n RTp-Artist: %s\n", RTP_Title, RTP_Artist); + } + RTP_ItemToggle = mtext[10] & 0x10; + rtp_itoggle = false; + rtp_idiffs = 0; + radioStatusMsg(); + AudioRecorderService(); + } + + RTP_TToggle = 0; + } + } + + else { + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error: [RTDecode] Length not correct (MFL= %d, len= %d)\n", mtext[4], len); + } +} + +void cRadioAudio::RDS_PsPtynDecode(bool ptyn, unsigned char *mtext, int len) +{ + if (len < 16) return; + + // decode Text + for (int i = 8; i <= 15; i++) { + if (mtext[i] <= 0xfe) { + // additional rds-character, see RBDS-Standard, Annex E + if (!ptyn) + RDS_PSText[RDS_PSIndex][i-8] = (mtext[i] >= 0x80) ? rds_addchar[mtext[i]-0x80] : mtext[i]; + else + RDS_PTYN[i-8] = (mtext[i] >= 0x80) ? rds_addchar[mtext[i]-0x80] : mtext[i]; + } + } + + if ((S_Verbose & 0x0f) >= 1) { + if (!ptyn) + printf("RDS-PS No= %d, Content[%d]= '%s'\n", mtext[7], RDS_PSIndex, RDS_PSText[RDS_PSIndex]); + else + printf("RDS-PTYN No= %d, Content= '%s'\n", mtext[7], RDS_PTYN); + } + + if (!ptyn) { + RDS_PSIndex += 1; if (RDS_PSIndex >= 12) RDS_PSIndex = 0; + RT_MsgShow = RDS_PSShow = true; + } +} + +void cRadioAudio::AudioRecorderService(void) +{ + /* check plugin audiorecorder service */ + ARec_Receive = ARec_Record = false; + + if (!RT_PlusShow || RT_Replay) + return; + + Audiorecorder_StatusRtpChannel_v1_0 arec_service; + cPlugin *p; + + arec_service.channel = chan; + p = cPluginManager::CallFirstService("Audiorecorder-StatusRtpChannel-v1.0", &arec_service); + if (p) { + ARec_Receive = (arec_service.status >= 2); + ARec_Record = (arec_service.status == 3); + } +} + +// add <names> of DVB Radio Slides Specification 1.0, 20061228 +void cRadioAudio::RassDecode(unsigned char *mtext, int len) +{ + if (RT_Replay) // no recordings $20090905 + return; + + static uint splfd = 0, spmax = 0, index = 0; + static uint afiles, slidenumr, slideelem, filemax; + static int filetype; + static bool slideshow = false, slidesave = false, slidecan = false, slidedel = false, start = false; + static uchar daten[65536]; // mpegs-stills defined <= 50kB + FILE *fd; + + // byte 1+2 = ADD (10bit SiteAdress + 6bit EncoderAdress) + // byte 3 = SQC (Sequence Counter 0x00 = not used) + // byte 4 = MFL (Message Field Length), + if (len >= mtext[4]+7) { // check complete length + // byte 5 = MEC (0xda for Rass) + // byte 6 = MEL + if (mtext[6] == 0 || mtext[6] > mtext[4]-2) { + if ((S_Verbose & 0x0f) >= 1) + printf("Rass-Error: Length=0 or not correct (MFL= %d, MEL= %d)\n", mtext[4], mtext[6]); + return; + } + // byte 7+8 = Service-ID zugehöriger Datenkanal + // byte 9-11 = Nummer aktuelles Paket, <PNR> + uint plfd = mtext[11] | mtext[10]<<8 | mtext[9]<<16; + // byte 12-14 = Anzahl Pakete, <NOP> + uint pmax = mtext[14] | mtext[13]<<8 | mtext[12]<<16; + + // byte 15+16 = Rass-Kennung = Header, <Rass-STA> + if (mtext[15] == 0x40 && mtext[16] == 0xda) { // first + // byte 17+18 = Anzahl Dateien im Archiv, <NOI> + afiles = mtext[18] | mtext[17]<<8; + // byte 19+20 = Slide-Nummer, <Rass-ID> + slidenumr = mtext[20] | mtext[19]<<8; + // byte 21+22 = Element-Nummer im Slide, <INR> + slideelem = mtext[22] | mtext[21]<<8; + // byte 23 = Slide-Steuerbyte, <Cntrl-Byte>: bit0 = Anzeige, bit1 = Speichern, bit2 = DarfAnzeige bei Senderwechsel, bit3 = Löschen + slideshow = mtext[23] & 0x01; + slidesave = mtext[23] & 0x02; + slidecan = mtext[23] & 0x04; + slidedel = mtext[23] & 0x08; + // byte 24 = Dateiart, <Item-Type>: 0=unbekannt/1=MPEG-Still/2=Definition + filetype = mtext[24]; + if (filetype != 1 && filetype != 2) { + if ((S_Verbose & 0x0f) >= 1) + printf("Rass-Error: Filetype '%d' unknown !\n", filetype); + //return; + } + // byte 25-28 = Dateilänge, <Item-Length> + filemax = mtext[28] | mtext[27]<<8 | mtext[26]<<16 | mtext[25]<<24; + if (filemax >= 65536) { + if ((S_Verbose & 0x0f) >= 1) + printf("Rass-Error: Filesize '%d' will be too big !\n", filemax); + return; + } + // byte 29-31 = Dateioffset Paketnr old, now <rfu> + // byte 32 = Dateioffset Bytenr old, now <rfu> + if ((S_Verbose & 0x10) > 0) { + printf("Rass-Header: afiles= %d, slidenumr= %d, slideelem= %d\n slideshow= %d, -save= %d, -canschow= %d, -delete= %d\n filetype= %d, filemax= %d\n", + afiles, slidenumr, slideelem, slideshow, slidesave, slidecan, slidedel, filetype, filemax); + printf("Rass-Start ...\n"); + } + start = true; + index = 0; + for (int i=33; i < len-2; i++) { + if (index < filemax) + daten[index++] = mtext[i]; + else + start = false; + } + splfd = plfd; + } + + else if (plfd < pmax && plfd == splfd+1) { // Between + splfd = plfd; + if (start) { + for (int i=15; i < len-2; i++) { + if (index < filemax) + daten[index++] = mtext[i]; + else + start = false; + } + } + } + + else if (plfd == pmax && plfd == splfd+1) { // Last + if (start) { + for (int i=15; i < len-4; i++) { + if (index <= filemax) + daten[index++] = mtext[i]; + else { + start = false; + return; + } + } + if ((S_Verbose & 0x10) > 0) + printf("... Rass-End (%d bytes)\n", index); + } + if (filemax > 0) { // nothing todo, if 0 byte file + // crc-check with bytes 'len-4/3' + unsigned short crc16 = crc16_ccitt(daten, filemax, false); + if (crc16 != (mtext[len-4]<<8)+mtext[len-3]) { + if ((S_Verbose & 0x0f) >= 1) + printf("Rass-Error: wrong CRC # calc = %04x <> transmit = %02x%02x\n", crc16, mtext[len-4], mtext[len-3]); + start = false; + return; + } + } + // show & save file ? + if (index == filemax && enforce_directory(DataDir)) { + if (slideshow || (slidecan && Rass_Show == -1)) { + if (filetype == 1) { // show only mpeg-still + char *filepath; + asprintf(&filepath, "%s/%s", DataDir, "Rass_show.mpg"); + if ((fd = fopen(filepath, "wb")) != NULL) { + fwrite(daten, 1, filemax, fd); + //fflush(fd); // for test in replaymode + fclose(fd); + Rass_Show = 1; + if ((S_Verbose & 0x10) > 0) + printf("Rass-File: ready for displaying :-)\n"); + } + else + esyslog("radio: ERROR writing Rass-imagefile failed '%s'", filepath); + free(filepath); + } + } + if (slidesave || slidedel || slidenumr < RASS_GALMAX) { + // lfd. Fotogallery 100.. ??? + if (slidenumr >= 100 && slidenumr < RASS_GALMAX) { + (Rass_SlideFoto < RASS_GALMAX) ? Rass_SlideFoto++ : Rass_SlideFoto = 100; + slidenumr = Rass_SlideFoto; + } + // + char *filepath; + (filetype == 2) ? asprintf(&filepath, "%s/Rass_%d.def", DataDir, slidenumr) + : asprintf(&filepath, "%s/Rass_%d.mpg", DataDir, slidenumr); + if ((fd = fopen(filepath, "wb")) != NULL) { + fwrite(daten, 1, filemax, fd); + fclose(fd); + if ((S_Verbose & 0x10) > 0) + printf("Rass-File: saving '%s'\n", filepath); + // archivemarker mpeg-stills + if (filetype == 1) { + // 0, 1000/1100/1110/1111..9000/9900/9990/9999 + if (slidenumr == 0 || slidenumr > RASS_GALMAX) { + if (slidenumr == 0) { + Rass_Flags[0][0] = !slidedel; + (RT_Info > 0) ? : RT_Info = 0; // open RadioTextOsd for ArchivTip + } + else { + int islide = (int) floor(slidenumr/1000); + for (int i = 3; i >= 0; i--) { + if (fmod(slidenumr, pow(10, i)) == 0) { + Rass_Flags[islide][3-i] = !slidedel; + break; + } + } + } + } + // gallery + else { + Rass_Gallery[slidenumr] = !slidedel; + if (!slidedel && (int)slidenumr > Rass_GalEnd) + Rass_GalEnd = slidenumr; + if (!slidedel && (Rass_GalStart == 0 || (int)slidenumr < Rass_GalStart)) + Rass_GalStart = slidenumr; + // counter + Rass_GalCount = 0; + for (int i = Rass_GalStart; i <= Rass_GalEnd; i++) { + if (Rass_Gallery[i]) + Rass_GalCount++; + } + Rass_Flags[10][0] = (Rass_GalCount > 0); + } + } + } + else + esyslog("radio: ERROR writing Rass-image/data-file failed '%s'", filepath); + free(filepath); + } + } + start = false; + splfd = spmax = 0; + } + + else { + start = false; + splfd = spmax = 0; + } + } + + else { + start = false; + splfd = spmax = 0; + if ((S_Verbose & 0x0f) >= 1) + printf("RDS-Error: [Rass] Length not correct (MFL= %d, len= %d)\n", mtext[4], len); + } +} + +void cRadioAudio::EnableRadioTextProcessing(const char *Titel, int apid, bool replay) +{ + asprintf(&RT_Titel, "%s", Titel); + audiopid = apid; + RT_Replay = replay; + ARec_Receive = ARec_Record = false; + + first_packets = 0; + enabled = true; + bratefound = false; + asprintf(&bitrate, "..."); + + // Radiotext init + if (S_RtFunc >= 1) { + RT_MsgShow = RT_PlusShow = RdsLogo = false; + RT_ReOpen = true; + RT_OsdTO = false; + RT_Index = RT_PTY = RTP_TToggle = 0; + RTP_ItemToggle = 1; + for (int i = 0; i < 5; i++) + memset(RT_Text[i], 0x20, RT_MEL-1); + sprintf(RTP_Title, "---"); + sprintf(RTP_Artist, "---"); + RTP_Starttime = time(NULL); + RT_Charset = 0; + // + RDS_PSShow = false; + RDS_PSIndex = 0; + for (int i = 0; i < 12; i++) + memset(RDS_PSText[i], 0x20, 8); + } + // ...Memory + rtp_content.start = time(NULL); + rtp_content.item_New = false; + rtp_content.rt_Index = -1; + rtp_content.item_Index = -1; + rtp_content.info_StockIndex = -1; + rtp_content.info_SportIndex = -1; + rtp_content.info_LotteryIndex = -1; + rtp_content.info_WeatherIndex = -1; + rtp_content.info_OtherIndex = -1; + for (int i = 0; i < MAX_RTPC; i++) { + rtp_content.radiotext[i] = NULL; + rtp_content.radiotext[MAX_RTPC+i] = NULL; + rtp_content.item_Title[i] = NULL; + rtp_content.item_Artist[i] = NULL; + rtp_content.info_Stock[i] = NULL; + rtp_content.info_Sport[i] = NULL; + rtp_content.info_Lottery[i] = NULL; + rtp_content.info_Weather[i] = NULL; + rtp_content.info_Other[i] = NULL; + } + rtp_content.info_News = NULL; + rtp_content.info_NewsLocal = NULL; + rtp_content.info_DateTime = NULL; + rtp_content.info_Traffic = NULL; + rtp_content.info_Alarm = NULL; + rtp_content.info_Advert = NULL; + rtp_content.info_Url = NULL; + rtp_content.prog_StatShort = NULL; + rtp_content.prog_Station = NULL; + rtp_content.prog_Now = NULL; + rtp_content.prog_Next = NULL; + rtp_content.prog_Part = NULL; + rtp_content.prog_Host = NULL; + rtp_content.prog_EditStaff = NULL; + rtp_content.prog_Homepage = NULL; + rtp_content.phone_Hotline = NULL; + rtp_content.phone_Studio = NULL; + rtp_content.sms_Studio = NULL; + rtp_content.email_Hotline = NULL; + rtp_content.email_Studio = NULL; + + // Rass init + Rass_Show = Rass_Archiv = -1; + for (int i = 0; i <= 10; i++) { + for (int ii = 0; ii < 4; ii++) + Rass_Flags[i][ii] = false; + } + Rass_GalStart = Rass_GalEnd = Rass_GalCount = 0; + for (int i = 0; i < RASS_GALMAX; i++) + Rass_Gallery[i] = false; + Rass_SlideFoto = 99; + // + InfoRequest = false; + + if (S_RtFunc < 1) return; + + // RDS-Receiver for seperate Data-PIDs, only Livemode, hardcoded Astra_19E + Hotbird 13E + int pid = 0; + if (!replay) { + switch (chan->Tid()) { + case 1113: switch (pid = chan->Apid(0)) { // Astra_19.2E - 12633 GHz + /* case 0x161: pid = 0x229; // radio top40 + break; */ + case 0x400: // Hitradio FFH + case 0x406: // planet radio + case 0x40c: pid += 1; // harmony.ffm + break; + default: return; + } + break; + case 5300: switch (pid = chan->Apid(0)) { // Hotbird_13E - 11747 GHz, no Radiotext @ moment, only TMC + MECs 25/26 + case 0xdc3: // Radio 1 + case 0xdd3: // Radio 3 + case 0xddb: // Radio 5 + case 0xde3: // Radio Exterior + case 0xdeb: pid += 1; // Radio 4 + break; + default: return; + } + break; + default: return; + } + RDSReceiver = new cRDSReceiver(pid); + rdsdevice = cDevice::ActualDevice(); + rdsdevice->AttachReceiver(RDSReceiver); + } + +} + +void cRadioAudio::DisableRadioTextProcessing() +{ + RT_Replay = enabled = false; + + // Radiotext & Rass + RT_Info = -1; + RT_ReOpen = false; + Rass_Show = Rass_Archiv = -1; + Rass_GalStart = Rass_GalEnd = Rass_GalCount = 0; + + if (RadioTextOsd != NULL) + RadioTextOsd->Hide(); + + if (RDSReceiver != NULL) { + rdsdevice->Detach(RDSReceiver); + delete RDSReceiver; + RDSReceiver = NULL; + rdsdevice = NULL; + } +} + + +// --- cRadioTextOsd ------------------------------------------------------ + +cBitmap cRadioTextOsd::rds(rds_xpm); +cBitmap cRadioTextOsd::arec(arec_xpm); +cBitmap cRadioTextOsd::rass(rass_xpm); +cBitmap cRadioTextOsd::index(index_xpm); +cBitmap cRadioTextOsd::radio(radio_xpm); +cBitmap cRadioTextOsd::marker(marker_xpm); +cBitmap cRadioTextOsd::page1(page1_xpm); +cBitmap cRadioTextOsd::pages2(pages2_xpm); +cBitmap cRadioTextOsd::pages3(pages3_xpm); +cBitmap cRadioTextOsd::pages4(pages4_xpm); +cBitmap cRadioTextOsd::no0(no0_xpm); +cBitmap cRadioTextOsd::no1(no1_xpm); +cBitmap cRadioTextOsd::no2(no2_xpm); +cBitmap cRadioTextOsd::no3(no3_xpm); +cBitmap cRadioTextOsd::no4(no4_xpm); +cBitmap cRadioTextOsd::no5(no5_xpm); +cBitmap cRadioTextOsd::no6(no6_xpm); +cBitmap cRadioTextOsd::no7(no7_xpm); +cBitmap cRadioTextOsd::no8(no8_xpm); +cBitmap cRadioTextOsd::no9(no9_xpm); +cBitmap cRadioTextOsd::bok(bok_xpm); +cBitmap cRadioTextOsd::pageE(pageE_xpm); + +cRadioTextOsd::cRadioTextOsd() + : cCharSetConv((RT_Charset == 0) ? "ISO-8859-1" : NULL) +{ + RadioTextOsd = this; + osd = NULL; + qosd = NULL; + rtclosed = rassclosed = false; + RT_ReOpen = false; +} + +cRadioTextOsd::~cRadioTextOsd() +{ + if (Rass_Archiv >= 0) { + if (!RT_Replay) + Rass_Archiv = RassImage(-1, -1, false); + else { + Rass_Archiv = -1; + RadioImage->SetBackgroundImage(ReplayFile); + } + } + + if (osd != NULL) + delete osd; + if (qosd != NULL) + delete qosd; + RadioTextOsd = NULL; + RT_ReOpen = !RT_OsdTO; + + cRemote::Put(LastKey); +} + +void cRadioTextOsd::Show(void) +{ + LastKey = kNone; + RT_OsdTO = false; + osdtimer.Set(); + + ftext = cFont::GetFont(fontSml); + fheight = ftext->Height() + 4; + bheight = (S_RtOsdTags >=1 ) ? fheight * (S_RtOsdRows+3) : fheight * (S_RtOsdRows+1); + bheight += 20; + + asprintf(&RTp_Titel, "%s - %s", InfoRequest ? tr("ext. Info") : tr("RTplus"), RT_Titel); + + if (S_RtDispl >= 1 && (!Rass_Flags[0][0] || S_RassText >= 2)) { // Rass_Show == -1 + RT_MsgShow = (RT_Info >= 1); + ShowText(); + } +} + +void cRadioTextOsd::Hide(void) +{ + RTOsdClose(); + RassOsdClose(); +} + +void cRadioTextOsd::RTOsdClose(void) +{ + if (osd != NULL) { + delete osd; + osd = NULL; + } +} + +void cRadioTextOsd::ShowText(void) +{ + char stext[3][100]; + int yoff = 17, ii = 1; + + if (!osd && !qosd && !Skins.IsOpen() && !cOsd::IsOpen()) { + if (S_RtOsdPos == 1) + osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop+Setup.OSDHeight-bheight); + else + osd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop); + tArea Area = {0, 0, Setup.OSDWidth-1, bheight-1, 4}; + osd->SetAreas(&Area, 1); + } + + if (osd) { + uint32_t bcolor, fcolor; + int skin = theme_skin(); + ftitel = cFont::GetFont(fontOsd); + ftext = cFont::GetFont(fontSml); + if (S_RtOsdTitle == 1) { + // Title + bcolor = (S_RtSkinColor > 0) ? radioSkin[skin].clrTitleBack : (0x00FFFFFF | S_RtBgTra<<24) & rt_color[S_RtBgCol]; + fcolor = (S_RtSkinColor > 0) ? radioSkin[skin].clrTitleText : rt_color[S_RtFgCol]; + osd->DrawRectangle(0, 0, Setup.OSDWidth-1, ftitel->Height()+9, bcolor); + osd->DrawEllipse(0, 0, 5, 5, 0x00000000, -2); + osd->DrawEllipse(Setup.OSDWidth-6, 0, Setup.OSDWidth-1, 5, 0x00000000, -1); + sprintf(stext[0], RT_PTY == 0 ? "%s - %s %s%s" : "%s - %s (%s)%s", + RT_Titel, InfoRequest ? tr("ext. Info") : tr("Radiotext"), + RT_PTY == 0 ? RDS_PTYN : ptynr2string(RT_PTY), RT_MsgShow ? ":" : tr(" [waiting ...]")); + osd->DrawText(4, 5, stext[0], fcolor, clrTransparent, ftitel, Setup.OSDWidth-4, ftitel->Height()); + // Radio, RDS- or Rass-Symbol, ARec-Symbol or Bitrate + int inloff = (ftitel->Height() + 9 - 20) / 2; + if (Rass_Flags[0][0]) { + osd->DrawBitmap(Setup.OSDWidth-51, inloff, rass, bcolor, fcolor); + if (ARec_Record) + osd->DrawBitmap(Setup.OSDWidth-107, inloff, arec, bcolor, 0xFFFC1414); // FG=Red + else { + inloff = (ftitel->Height() + 9 - ftext->Height()) / 2; + osd->DrawText(4, inloff, RadioAudio->bitrate, fcolor, clrTransparent, ftext, Setup.OSDWidth-59, ftext->Height(), taRight); + } + } + else { + if (InfoRequest && !RdsLogo) { + osd->DrawBitmap(Setup.OSDWidth-72, inloff+1, radio, fcolor, bcolor); + osd->DrawBitmap(Setup.OSDWidth-48, inloff-1, radio, fcolor, bcolor); + } + else + osd->DrawBitmap(Setup.OSDWidth-84, inloff, rds, bcolor, fcolor); + if (ARec_Record) + osd->DrawBitmap(Setup.OSDWidth-140, inloff, arec, bcolor, 0xFFFC1414); // FG=Red + else { + inloff = (ftitel->Height() + 9 - ftext->Height()) / 2; + osd->DrawText(4, inloff, RadioAudio->bitrate, fcolor, clrTransparent, ftext, Setup.OSDWidth-92, ftext->Height(), taRight); + } + } + } + else + osd->DrawRectangle(0, 0, Setup.OSDWidth-1, ftitel->Height()+9, 0x00000000); + // Body + bcolor = (S_RtSkinColor > 0) ? radioSkin[skin].clrBack : (0x00FFFFFF | S_RtBgTra<<24) & rt_color[S_RtBgCol]; + fcolor = (S_RtSkinColor > 0) ? radioSkin[skin].clrText : rt_color[S_RtFgCol]; + osd->DrawRectangle(0, ftitel->Height()+10, Setup.OSDWidth-1, bheight-1, bcolor); + osd->DrawEllipse(0, bheight-6, 5, bheight-1, 0x00000000, -3); + osd->DrawEllipse(Setup.OSDWidth-6, bheight-6, Setup.OSDWidth-1, bheight-1, 0x00000000, -4); + if (S_RtOsdTitle == 1) + osd->DrawRectangle(5, ftitel->Height()+9, Setup.OSDWidth-6, ftitel->Height()+9, fcolor); + if (RT_MsgShow) { + // RT-Text roundloop + int ind = (RT_Index == 0) ? S_RtOsdRows - 1 : RT_Index - 1; + if (S_RtOsdLoop == 1) { // latest bottom + for (int i = ind+1; i < S_RtOsdRows; i++) + osd->DrawText(5, yoff+fheight*(ii++), Convert(RT_Text[i]), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height()); + for (int i = 0; i <= ind; i++) + osd->DrawText(5, yoff+fheight*(ii++), Convert(RT_Text[i]), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height()); + } + else { // latest top + for (int i = ind; i >= 0; i--) + osd->DrawText(5, yoff+fheight*(ii++), Convert(RT_Text[i]), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height()); + for (int i = S_RtOsdRows-1; i > ind; i--) + osd->DrawText(5, yoff+fheight*(ii++), Convert(RT_Text[i]), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height()); + } + // + RT-Plus or PS-Text = 2 rows + if ((S_RtOsdTags == 1 && RT_PlusShow) || S_RtOsdTags >= 2) { + if (!RDS_PSShow || !strstr(RTP_Title, "---") || !strstr(RTP_Artist, "---")) { + sprintf(stext[1], "> %s", tr("Title :")); + sprintf(stext[2], "> %s", tr("Artist :")); + int fwidth = ftext->Width(stext[1]); + fwidth = max(fwidth, ftext->Width(stext[2])) + 15; + osd->DrawText(4, 6+yoff+fheight*(ii), stext[1], fcolor, clrTransparent, ftext, fwidth-5, ftext->Height()); + osd->DrawText(fwidth, 6+yoff+fheight*(ii++), Convert(RTP_Title), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height()); + osd->DrawText(4, 3+yoff+fheight*(ii), stext[2], fcolor, clrTransparent, ftext, fwidth-5, ftext->Height()); + osd->DrawText(fwidth, 3+yoff+fheight*(ii++), Convert(RTP_Artist), fcolor, clrTransparent, ftext, Setup.OSDWidth-4, ftext->Height()); + } + else { + char *temp; + asprintf(&temp, "%s", ""); + int ind = (RDS_PSIndex == 0) ? 11 : RDS_PSIndex - 1; + for (int i = ind+1; i < 12; i++) + asprintf(&temp, "%s%s ", temp, RDS_PSText[i]); + for (int i = 0; i <= ind; i++) + asprintf(&temp, "%s%s ", temp, RDS_PSText[i]); + snprintf(stext[1], 6*9, "%s", temp); + snprintf(stext[2], 6*9, "%s", temp+(6*9)); + free(temp); + osd->DrawText(6, 6+yoff+fheight*ii, "[", fcolor, clrTransparent, ftext, 12, ftext->Height()); + osd->DrawText(Setup.OSDWidth-12, 6+yoff+fheight*ii, "]", fcolor, clrTransparent, ftext, Setup.OSDWidth-6, ftext->Height()); + osd->DrawText(16, 6+yoff+fheight*(ii++), stext[1], fcolor, clrTransparent, ftext, Setup.OSDWidth-16, ftext->Height(), taCenter); + osd->DrawText(6, 3+yoff+fheight*ii, "[", fcolor, clrTransparent, ftext, 12, ftext->Height()); + osd->DrawText(Setup.OSDWidth-12, 3+yoff+fheight*ii, "]", fcolor, clrTransparent, ftext, Setup.OSDWidth-6, ftext->Height()); + osd->DrawText(16, 3+yoff+fheight*(ii++), stext[2], fcolor, clrTransparent, ftext, Setup.OSDWidth-16, ftext->Height(), taCenter); + } + } + } + osd->Flush(); + } + + RT_MsgShow = false; +} + +int cRadioTextOsd::RassImage(int QArchiv, int QKey, bool DirUp) +{ + int i; + + if (QKey >= 0 && QKey <= 9) { + if (QArchiv == 0) + (Rass_Flags[QKey][0]) ? QArchiv = QKey * 1000 : QArchiv = 0; + else if (QArchiv > 0) { + if (floor(QArchiv/1000) == QKey) { + for (i = 3; i >= 0; i--) { + if (fmod(QArchiv, pow(10, i)) == 0) + break; + } + (i > 0) ? QArchiv += QKey * (int) pow(10, --i) : QArchiv = QKey * 1000; + (Rass_Flags[QKey][3-i]) ? : QArchiv = QKey * 1000; + } + else + (Rass_Flags[QKey][0]) ? QArchiv = QKey * 1000 : QArchiv = 0; + } + } + // Gallery + else if (QKey > 9 && Rass_GalCount >= 0) { + if (QArchiv < Rass_GalStart || QArchiv > Rass_GalEnd) + QArchiv = Rass_GalStart - 1; + if (DirUp) { + for (i = QArchiv+1; i <= Rass_GalEnd; i++) { + if (Rass_Gallery[i]) + break; + } + QArchiv = (i <= Rass_GalEnd) ? i : Rass_GalStart; + } + else { + for (i = QArchiv-1; i >= Rass_GalStart; i--) { + if (Rass_Gallery[i]) + break; + } + QArchiv = (i >= Rass_GalStart) ? i : Rass_GalEnd; + } + } + + // show mpeg-still + char *image; + if (QArchiv >= 0) + asprintf(&image, "%s/Rass_%d.mpg", DataDir, QArchiv); + else + asprintf(&image, "%s/Rass_show.mpg", DataDir); + RadioImage->SetBackgroundImage(image); + free(image); + + return QArchiv; +} + +void cRadioTextOsd::RassOsd(void) +{ + ftext = cFont::GetFont(fontSml); + int fh = ftext->Height(); + + if (!qosd && !osd && !Skins.IsOpen() && !cOsd::IsOpen()) { + qosd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop+Setup.OSDHeight - (29+264-6+36)); + tArea Area = {0, 0, 97, 29+264+5, 4}; + qosd->SetAreas(&Area, 1); + } + + if (qosd) { + uint32_t bcolor, fcolor; + int skin = theme_skin(); + // Logo + bcolor = radioSkin[skin].clrTitleBack; + fcolor = radioSkin[skin].clrTitleText; + qosd->DrawRectangle(0, 1, 97, 29, bcolor); + qosd->DrawEllipse(0, 0, 5, 5, 0x00000000, -2); + qosd->DrawEllipse(92, 0, 97, 5, 0x00000000, -1); + qosd->DrawBitmap(25, 5, rass, bcolor, fcolor); + // Body + bcolor = radioSkin[skin].clrBack; + fcolor = radioSkin[skin].clrText; + int offs = 29 + 2; + qosd->DrawRectangle(0, offs, 97, 29+264+5, bcolor); + qosd->DrawEllipse(0, 29+264, 5, 29+264+5, 0x00000000, -3); + qosd->DrawEllipse(92, 29+264, 97, 29+264+5, 0x00000000, -4); + qosd->DrawRectangle(5, 29, 92, 29, fcolor); + // Keys+Index + offs += 4; + qosd->DrawBitmap(4, offs, no0, bcolor, fcolor); + qosd->DrawBitmap(44, offs, index, bcolor, fcolor); + qosd->DrawBitmap(4, 24+offs, no1, bcolor, fcolor); + qosd->DrawBitmap(4, 48+offs, no2, bcolor, fcolor); + qosd->DrawBitmap(4, 72+offs, no3, bcolor, fcolor); + qosd->DrawBitmap(4, 96+offs, no4, bcolor, fcolor); + qosd->DrawBitmap(4, 120+offs, no5, bcolor, fcolor); + qosd->DrawBitmap(4, 144+offs, no6, bcolor, fcolor); + qosd->DrawBitmap(4, 168+offs, no7, bcolor, fcolor); + qosd->DrawBitmap(4, 192+offs, no8, bcolor, fcolor); + qosd->DrawBitmap(4, 216+offs, no9, bcolor, fcolor); + qosd->DrawBitmap(4, 240+offs, bok, bcolor, fcolor); + // Content + bool mark = false; + for (int i = 1; i <= 9; i++) { + // Pages + if (Rass_Flags[i][0] && Rass_Flags[i][1] && Rass_Flags[i][2] && Rass_Flags[i][3]) + qosd->DrawBitmap(48, (i*24)+offs, pages4, bcolor, fcolor); + else if (Rass_Flags[i][0] && Rass_Flags[i][1] && Rass_Flags[i][2]) + qosd->DrawBitmap(48, (i*24)+offs, pages3, bcolor, fcolor); + else if (Rass_Flags[i][0] && Rass_Flags[i][1]) + qosd->DrawBitmap(48, (i*24)+offs, pages2, bcolor, fcolor); + else if (Rass_Flags[i][0]) + qosd->DrawBitmap(48, (i*24)+offs, page1, bcolor, fcolor); + // Marker + if (floor(Rass_Archiv/1000) == i) { + qosd->DrawBitmap(28, (i*24)+offs, marker, bcolor, fcolor); + mark = true; + } + } + // Gallery + if (Rass_GalCount > 0) { + char *temp; + qosd->DrawBitmap(48, 240+offs, pageE, bcolor, fcolor); + asprintf(&temp, "%d", Rass_GalCount); + qosd->DrawText(67, 240+offs+(20-fh), temp, fcolor, clrTransparent, ftext, 97, fh); + free(temp); + } + // Marker gallery/index + if (!mark) { + if (Rass_Archiv > 0 && Rass_Archiv <= RASS_GALMAX) + qosd->DrawBitmap(30, 240+offs, marker, bcolor, fcolor); + else + qosd->DrawBitmap(28, offs, marker, bcolor, fcolor); + } + qosd->Flush(); + } +} + +void cRadioTextOsd::RassOsdTip(void) +{ + ftext = cFont::GetFont(fontSml); + int fh = ftext->Height(); + + if (!qosd && !osd && !Skins.IsOpen() && !cOsd::IsOpen()) { + qosd = cOsdProvider::NewOsd(Setup.OSDLeft, Setup.OSDTop+Setup.OSDHeight - (29+(2*fh)-6+36)); + tArea Area = {0, 0, 97, 29+(2*fh)+5, 4}; + qosd->SetAreas(&Area, 1); + } + + if (qosd) { + uint32_t bcolor, fcolor; + int skin = theme_skin(); + // Title + bcolor = radioSkin[skin].clrTitleBack; + fcolor = radioSkin[skin].clrTitleText; + qosd->DrawRectangle(0, 0, 97, 29, bcolor); + qosd->DrawEllipse(0, 0, 5, 5, 0x00000000, -2); + qosd->DrawEllipse(92, 0, 97, 5, 0x00000000, -1); + qosd->DrawBitmap(25, 5, rass, bcolor, fcolor); + // Body + bcolor = radioSkin[skin].clrBack; + fcolor = radioSkin[skin].clrText; + qosd->DrawRectangle(0, 29+2, 97, 29+(2*fh)+5, bcolor); + qosd->DrawEllipse(0, 29+(2*fh), 5, 29+(2*fh)+5, 0x00000000, -3); + qosd->DrawEllipse(92, 29+(2*fh), 97, 29+(2*fh)+5, 0x00000000, -4); + qosd->DrawRectangle(5, 29, 92, 29, fcolor); + qosd->DrawText(5, 29+4, tr("Records"), fcolor, clrTransparent, ftext, 97, fh); + qosd->DrawText(5, 29+fh+4, ".. <0>", fcolor, clrTransparent, ftext, 97, fh); + qosd->Flush(); + } +} + +void cRadioTextOsd::RassOsdClose(void) +{ + if (qosd != NULL) { + delete qosd; + qosd = NULL; + } +} + +void cRadioTextOsd::RassImgSave(const char *size, int pos) +{ + char *infile, *outfile, *cmd; + int filenr = 0, error = 0; + struct tm *ts, tm_store; + + if (!enforce_directory(DataDir)) + return; + + time_t t = time(NULL); + ts = localtime_r(&t, &tm_store); + switch (pos) { + // all from 1-9 + case 1 ... 9: for (int i = 3; i >= 0; i--) { + filenr += (int) (pos * pow(10, i)); + if (Rass_Flags[pos][3-i]) { + asprintf(&infile, "%s/Rass_%d.mpg", DataDir, filenr); + asprintf(&outfile, "%s/Rass_%s-%04d_%02d%02d%02d%02d.jpg", DataDir, RT_Titel, filenr, + ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min); + asprintf(&cmd, "ffmpeg -i \"%s\" -s %s -f mjpeg -y \"%s\"", infile, size, outfile); + if ((error = system(cmd))) + i = -1; + } + } + asprintf(&cmd, "%s '%d'", tr("Rass-Image(s) saved from Archiv "), pos); + break; + // all from gallery + case 10: for (int i = Rass_GalStart; i <= Rass_GalEnd; i++) { + if (Rass_Gallery[i]) { + asprintf(&infile, "%s/Rass_%d.mpg", DataDir, i); + asprintf(&outfile, "%s/Rass_%s-Gallery%04d_%02d%02d.jpg", DataDir, RT_Titel, i, + ts->tm_mon+1, ts->tm_mday); + asprintf(&cmd, "ffmpeg -i \"%s\" -s %s -f mjpeg -y \"%s\"", infile, size, outfile); + if ((error = system(cmd))) + i = Rass_GalEnd + 1; + } + } + asprintf(&cmd, "%s", tr("Rass-Image(s) saved from Gallery")); + break; + // single + default: asprintf(&infile, "%s/Rass_%d.mpg", DataDir, Rass_Archiv); + asprintf(&outfile, "%s/Rass_%s-%04d_%02d%02d%02d%02d.jpg", DataDir, RT_Titel, Rass_Archiv, + ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min); + asprintf(&cmd, "ffmpeg -i \"%s\" -s %s -f mjpeg -y \"%s\"", infile, size, outfile); + error = system(cmd); + asprintf(&cmd, "%s: %s", tr("Rass-Image saved"), outfile); + } + free(infile); + + // Info + RassOsdClose(); + if (error) { + asprintf(&cmd, "%s: %s", tr("Rass-Image failed"), outfile); + Skins.Message(mtError, cmd, Setup.OSDMessageTime); + } + else + Skins.Message(mtInfo, cmd, Setup.OSDMessageTime); + + free(outfile); + free(cmd); +} + +void cRadioTextOsd::rtp_print(void) +{ + struct tm tm_store; + time_t t = time(NULL); + printf("\n>>> %s-Memoryclasses @ %s", InfoRequest ? "Info" : "RTplus", asctime(localtime_r(&t, &tm_store))); + printf(" on '%s' since %s", RT_Titel, asctime(localtime_r(&rtp_content.start, &tm_store))); + + printf("--- Programme ---\n"); + if (rtp_content.prog_StatShort != NULL) printf("StationShort: %s\n", rtp_content.prog_StatShort); + if (rtp_content.prog_Station != NULL) printf(" Station: %s\n", rtp_content.prog_Station); + if (rtp_content.prog_Now != NULL) printf(" Now: %s\n", rtp_content.prog_Now); + if (rtp_content.prog_Next != NULL) printf(" Next: %s\n", rtp_content.prog_Next); + if (rtp_content.prog_Part != NULL) printf(" Part: %s\n", rtp_content.prog_Part); + if (rtp_content.prog_Host != NULL) printf(" Host: %s\n", rtp_content.prog_Host); + if (rtp_content.prog_EditStaff != NULL) printf(" Ed.Staff: %s\n", rtp_content.prog_EditStaff); + if (rtp_content.prog_Homepage != NULL) printf(" Homepage: %s\n", rtp_content.prog_Homepage); + + printf("--- Interactivity ---\n"); + if (rtp_content.phone_Hotline != NULL) printf(" Phone-Hotline: %s\n", rtp_content.phone_Hotline); + if (rtp_content.phone_Studio != NULL) printf(" Phone-Studio: %s\n", rtp_content.phone_Studio); + if (rtp_content.sms_Studio != NULL) printf(" SMS-Studio: %s\n", rtp_content.sms_Studio); + if (rtp_content.email_Hotline != NULL) printf(" Email-Hotline: %s\n", rtp_content.email_Hotline); + if (rtp_content.email_Studio != NULL) printf(" Email-Studio: %s\n", rtp_content.email_Studio); + + printf("--- Info ---\n"); + if (rtp_content.info_News != NULL) printf(" News: %s\n", rtp_content.info_News); + if (rtp_content.info_NewsLocal != NULL) printf(" NewsLocal: %s\n", rtp_content.info_NewsLocal); + if (rtp_content.info_DateTime != NULL) printf(" DateTime: %s\n", rtp_content.info_DateTime); + if (rtp_content.info_Traffic != NULL) printf(" Traffic: %s\n", rtp_content.info_Traffic); + if (rtp_content.info_Alarm != NULL) printf(" Alarm: %s\n", rtp_content.info_Alarm); + if (rtp_content.info_Advert != NULL) printf(" Advertisg: %s\n", rtp_content.info_Advert); + if (rtp_content.info_Url != NULL) printf(" Url: %s\n", rtp_content.info_Url); + // no sorting + for (int i = 0; i < MAX_RTPC; i++) + if (rtp_content.info_Stock[i] != NULL) printf(" Stock[%02d]: %s\n", i, rtp_content.info_Stock[i]); + for (int i = 0; i < MAX_RTPC; i++) + if (rtp_content.info_Sport[i] != NULL) printf(" Sport[%02d]: %s\n", i, rtp_content.info_Sport[i]); + for (int i = 0; i < MAX_RTPC; i++) + if (rtp_content.info_Lottery[i] != NULL) printf(" Lottery[%02d]: %s\n", i, rtp_content.info_Lottery[i]); + for (int i = 0; i < MAX_RTPC; i++) + if (rtp_content.info_Weather[i] != NULL) printf(" Weather[%02d]: %s\n", i, rtp_content.info_Weather[i]); + for (int i = 0; i < MAX_RTPC; i++) + if (rtp_content.info_Other[i] != NULL) printf(" Other[%02d]: %s\n", i, rtp_content.info_Other[i]); +/* + printf("--- Item-Playlist ---\n"); + // no sorting + if (rtp_content.item_Index >= 0) { + for (int i = 0; i < MAX_RTPC; i++) { + if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) { + struct tm tm_store; + struct tm *ts = localtime_r(&rtp_content.item_Start[i], &tm_store); + printf(" [%02d] %02d:%02d Title: %s | Artist: %s\n", + i, ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]); + } + } + } + + printf("--- Last seen Radiotext ---\n"); + // no sorting + if (rtp_content.rt_Index >= 0) { + for (int i = 0; i < 2*MAX_RTPC; i++) + if (rtp_content.radiotext[i] != NULL) printf(" [%03d] %s\n", i, rtp_content.radiotext[i]); + } +*/ + printf("<<<\n"); +} + +#define rtplog 0 +eOSState cRadioTextOsd::ProcessKey(eKeys Key) +{ + // RTplus Infolog + if (rtplog == 1 && (S_Verbose & 0x0f) >= 1) { + static int ct = 0; + if (++ct >= 60) { + ct = 0; + rtp_print(); + } + } + + // check end @ replay + if (RT_Replay) { + int rplayCur, rplayTot; + cControl::Control()->GetIndex(rplayCur, rplayTot, false); + if (rplayCur >= rplayTot-1) { + Hide(); + return osEnd; + } + } + + // Timeout or no Info/Rass + if (RT_OsdTO || (RT_OsdTOTemp > 0) || (RT_Info < 0)) { + Hide(); + return osEnd; + } + + eOSState state = cOsdObject::ProcessKey(Key); + if (state != osUnknown) return state; + + // Key pressed ... + if (Key != kNone && Key < k_Release) { + if (osd) { // Radiotext, -plus Osd + switch (Key) { + case kBack: RTOsdClose(); + rtclosed = true; + //rassclosed = false; + break; + case k0: RTOsdClose(); + RTplus_Osd = true; + cRemote::CallPlugin("radio"); + return osEnd; + default: Hide(); + LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key; + return osEnd; + } + } + else if (qosd && Rass_Archiv >= 0) { // Rass-Archiv Osd + int i, pos; + pos = (Rass_Archiv > 0 && Rass_Archiv <= RASS_GALMAX) ? 10 : (int) floor(Rass_Archiv/1000); + switch (Key) { + // back to Slideshow + case kBlue: + case kBack: if (!RT_Replay) + Rass_Archiv = RassImage(-1, 0, false); + else { + Rass_Archiv = -1; + RadioImage->SetBackgroundImage(ReplayFile); + } + RassOsdClose(); + rassclosed = rtclosed = false; + break; + // Archiv-Sides + case k0 ... k9: Rass_Archiv = RassImage(Rass_Archiv, Key-k0, false); + RassOsd(); + break; + case kOk: if (Rass_Flags[10][0]) { + Rass_Archiv = RassImage(Rass_Archiv, 10, true); + RassOsd(); + } + break; + case kLeft: + case kRight: Rass_Archiv = RassImage(Rass_Archiv, pos, (Key == kRight) ? true : false); + RassOsd(); + break; + case kDown: (pos == 10) ? i = 0 : i = pos + 1; + while (i != pos) { + if (Rass_Flags[i][0]) { + Rass_Archiv = RassImage(Rass_Archiv, i, true); + RassOsd(); + return osContinue; + } + if (++i > 10) i = 0; + } + break; + case kUp: (pos == 0) ? i = 10 : i = pos - 1; + while (i != pos) { + if (Rass_Flags[i][0]) { + Rass_Archiv = RassImage(Rass_Archiv, i, true); + RassOsd(); + return osContinue; + } + if (--i < 0) i = 10; + } + break; + case kRed: RassImgSave("1024x576", 0); + break; + case kGreen: RassImgSave("1024x576", pos); + break; + case kYellow: break; // todo, what ? + default: Hide(); + LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key; + return osEnd; + } + } + else if (qosd && Rass_Archiv == -1) { // Rass-Slideshow Osd + switch (Key) { + // close + case kBack: RassOsdClose(); + rassclosed = true; + //rtclosed = false; + break; + // Archiv-Index + case k0: if (Rass_Flags[0][0]) { + RassOsdClose(); + Rass_Archiv = RassImage(0, 0, false); + RassOsd(); + } + break; + default: Hide(); + LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key; + return osEnd; + } + } + else { // no RT && no Rass + Hide(); + LastKey = (Key == kChanUp || Key == kChanDn) ? kNone : Key; + return osEnd; + } + } + // no Key pressed ... + else if (S_RtOsdTO > 0 && osdtimer.Elapsed()/1000/60 >= (uint)S_RtOsdTO) { + RT_OsdTO = true; + Hide(); + return osEnd; + } + else if (Rass_Archiv >= 0) + RassOsd(); + else if (RT_MsgShow && !rtclosed && (!Rass_Flags[0][0]|| S_RassText >= 2 || rassclosed)) { // Rass_Show == -1 + RassOsdClose(); + ShowText(); + } + else if (Rass_Flags[0][0] && !rassclosed && (S_RassText < 2 || rtclosed)) { + RTOsdClose(); + RassOsdTip(); + } + + return osContinue; +} + + +// --- cRTplusOsd ------------------------------------------------------ + +cRTplusOsd::cRTplusOsd(void) + : cOsdMenu(RTp_Titel, 3, 12) + , cCharSetConv((RT_Charset == 0) ? "ISO-8859-1" : NULL) +{ + RTplus_Osd = false; + + bcount = helpmode = 0; + listtyp[0] = tr("Radiotext"); + listtyp[1] = tr("Playlist"); + listtyp[2] = tr("Sports"); + listtyp[3] = tr("Lottery"); + listtyp[4] = tr("Weather"); + listtyp[5] = tr("Stockmarket"); + listtyp[6] = tr("Other"); + + Load(); + Display(); +} + +cRTplusOsd::~cRTplusOsd() +{ +} + +void cRTplusOsd::Load(void) +{ + char text[80]; + + struct tm tm_store; + struct tm *ts = localtime_r(&rtp_content.start, &tm_store); + snprintf(text, sizeof(text), "%s %02d:%02d", InfoRequest ? tr("extra Info since") : tr("RTplus Memory since"), ts->tm_hour, ts->tm_min); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + + snprintf(text, sizeof(text), "-- %s --", tr("Programme")); + Add(new cOsdItem(hk(text))); + if (rtp_content.prog_StatShort != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Stat.Short"), Convert(rtp_content.prog_StatShort)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.prog_Station != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Station"), Convert(rtp_content.prog_Station)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.prog_Now != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Now"), Convert(rtp_content.prog_Now)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.prog_Part != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("...Part"), Convert(rtp_content.prog_Part)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.prog_Next != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Next"), Convert(rtp_content.prog_Next)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.prog_Host != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Host"), Convert(rtp_content.prog_Host)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.prog_EditStaff != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Edit.Staff"), Convert(rtp_content.prog_EditStaff)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.prog_Homepage != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Homepage"), Convert(rtp_content.prog_Homepage)); + Add(new cOsdItem(hk(text))); + } + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + + snprintf(text, sizeof(text), "-- %s --", tr("Interactivity")); + Add(new cOsdItem(hk(text))); + if (rtp_content.phone_Hotline != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Phone-Hotline"), Convert(rtp_content.phone_Hotline)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.phone_Studio != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Phone-Studio"), Convert(rtp_content.phone_Studio)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.sms_Studio != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("SMS-Studio"), Convert(rtp_content.sms_Studio)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.email_Hotline != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Email-Hotline"), Convert(rtp_content.email_Hotline)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.email_Studio != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Email-Studio"), Convert(rtp_content.email_Studio)); + Add(new cOsdItem(hk(text))); + } + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + + snprintf(text, sizeof(text), "-- %s --", tr("Info")); + Add(new cOsdItem(hk(text))); + if (rtp_content.info_News != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("News"), Convert(rtp_content.info_News)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.info_NewsLocal != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("NewsLocal"), Convert(rtp_content.info_NewsLocal)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.info_DateTime != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("DateTime"), Convert(rtp_content.info_DateTime)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.info_Traffic != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Traffic"), Convert(rtp_content.info_Traffic)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.info_Alarm != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Alarm"), Convert(rtp_content.info_Alarm)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.info_Advert != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Advertising"), Convert(rtp_content.info_Advert)); + Add(new cOsdItem(hk(text))); + } + if (rtp_content.info_Url != NULL) { + snprintf(text, sizeof(text), "\t%s:\t%s", tr("Url"), Convert(rtp_content.info_Url)); + Add(new cOsdItem(hk(text))); + } + + for (int i = 0; i <= 6; i++) + btext[i] = NULL; + bcount = 0; + asprintf(&btext[bcount++], "%s", listtyp[0]); + if (rtp_content.item_Index >= 0) + asprintf(&btext[bcount++], "%s", listtyp[1]); + if (rtp_content.info_SportIndex >= 0) + asprintf(&btext[bcount++], "%s", listtyp[2]); + if (rtp_content.info_LotteryIndex >= 0) + asprintf(&btext[bcount++], "%s", listtyp[3]); + if (rtp_content.info_WeatherIndex >= 0) + asprintf(&btext[bcount++], "%s", listtyp[4]); + if (rtp_content.info_StockIndex >= 0) + asprintf(&btext[bcount++], "%s", listtyp[5]); + if (rtp_content.info_OtherIndex >= 0) + asprintf(&btext[bcount++], "%s", listtyp[6]); + + switch (bcount) { + case 4: if (helpmode == 0) + SetHelp(btext[0], btext[1], btext[2], ">>"); + else if (helpmode == 1) + SetHelp("<<", btext[3], NULL, tr("Exit")); + break; + case 5: if (helpmode == 0) + SetHelp(btext[0], btext[1], btext[2], ">>"); + else if (helpmode == 1) + SetHelp("<<", btext[3], btext[4], tr("Exit")); + break; + case 6: if (helpmode == 0) + SetHelp(btext[0], btext[1], btext[2], ">>"); + else if (helpmode == 1) + SetHelp("<<", btext[3], btext[4], ">>"); + else if (helpmode == 2) + SetHelp("<<", btext[5], NULL, tr("Exit")); + break; + case 7: if (helpmode == 0) + SetHelp(btext[0], btext[1], btext[2], ">>"); + else if (helpmode == 1) + SetHelp("<<", btext[3], btext[4], ">>"); + else if (helpmode == 2) + SetHelp("<<", btext[5], btext[6], tr("Exit")); + break; + default: helpmode = 0; + SetHelp(btext[0], btext[1], btext[2], tr("Exit")); + } +} + +void cRTplusOsd::Update(void) +{ + Clear(); + Load(); + Display(); +} + +int cRTplusOsd::rtptyp(char *btext) +{ + for (int i = 0; i <= 6; i++) { + if (strcmp(btext, listtyp[i]) == 0) + return i; + } + + return -1; +} + +void cRTplusOsd::rtp_fileprint(void) +{ + struct tm *ts, tm_store; + char *fname, *fpath; + FILE *fd; + int ind, lfd = 0; + + if (!enforce_directory(DataDir)) + return; + + time_t t = time(NULL); + ts = localtime_r(&t, &tm_store); + asprintf(&fname, "%s_%s_%04d-%02d-%02d.%02d.%02d", InfoRequest ? "Info" : "RTplus", RT_Titel, ts->tm_year+1900, ts->tm_mon+1, ts->tm_mday, ts->tm_hour, ts->tm_min); + asprintf(&fpath, "%s/%s", DataDir, fname); + if ((fd = fopen(fpath, "w")) != NULL) { + + fprintf(fd, ">>> %s-Memoryclasses @ %s", InfoRequest ? "Info" : "RTplus", asctime(localtime_r(&t, &tm_store))); + fprintf(fd, " on '%s' since %s", RT_Titel, asctime(localtime_r(&rtp_content.start, &tm_store))); + + fprintf(fd, "--- Programme ---\n"); + if (rtp_content.prog_StatShort != NULL) fprintf(fd, "StationShort: %s\n", rtp_content.prog_StatShort); + if (rtp_content.prog_Station != NULL) fprintf(fd, " Station: %s\n", rtp_content.prog_Station); + if (rtp_content.prog_Now != NULL) fprintf(fd, " Now: %s\n", rtp_content.prog_Now); + if (rtp_content.prog_Part != NULL) fprintf(fd, " Part: %s\n", rtp_content.prog_Part); + if (rtp_content.prog_Next != NULL) fprintf(fd, " Next: %s\n", rtp_content.prog_Next); + if (rtp_content.prog_Host != NULL) fprintf(fd, " Host: %s\n", rtp_content.prog_Host); + if (rtp_content.prog_EditStaff != NULL) fprintf(fd, " Ed.Staff: %s\n", rtp_content.prog_EditStaff); + if (rtp_content.prog_Homepage != NULL) fprintf(fd, " Homepage: %s\n", rtp_content.prog_Homepage); + + fprintf(fd, "--- Interactivity ---\n"); + if (rtp_content.phone_Hotline != NULL) fprintf(fd, " Phone-Hotline: %s\n", rtp_content.phone_Hotline); + if (rtp_content.phone_Studio != NULL) fprintf(fd, " Phone-Studio: %s\n", rtp_content.phone_Studio); + if (rtp_content.sms_Studio != NULL) fprintf(fd, " SMS-Studio: %s\n", rtp_content.sms_Studio); + if (rtp_content.email_Hotline != NULL) fprintf(fd, " Email-Hotline: %s\n", rtp_content.email_Hotline); + if (rtp_content.email_Studio != NULL) fprintf(fd, " Email-Studio: %s\n", rtp_content.email_Studio); + + fprintf(fd, "--- Info ---\n"); + if (rtp_content.info_News != NULL) fprintf(fd, " News: %s\n", rtp_content.info_News); + if (rtp_content.info_NewsLocal != NULL) fprintf(fd, " NewsLocal: %s\n", rtp_content.info_NewsLocal); + if (rtp_content.info_DateTime != NULL) fprintf(fd, " DateTime: %s\n", rtp_content.info_DateTime); + if (rtp_content.info_Traffic != NULL) fprintf(fd, " Traffic: %s\n", rtp_content.info_Traffic); + if (rtp_content.info_Alarm != NULL) fprintf(fd, " Alarm: %s\n", rtp_content.info_Alarm); + if (rtp_content.info_Advert != NULL) fprintf(fd, " Advertisg: %s\n", rtp_content.info_Advert); + if (rtp_content.info_Url != NULL) fprintf(fd, " Url: %s\n", rtp_content.info_Url); + + + if (rtp_content.item_Index >= 0) { + fprintf(fd, "--- Item-Playlist ---\n"); + ind = rtp_content.item_Index; + if (ind < (MAX_RTPC-1) && rtp_content.item_Title[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) { + ts = localtime_r(&rtp_content.item_Start[i], &tm_store); + fprintf(fd, " %02d:%02d Title: '%s' | Artist: '%s'\n", ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]); + } + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) { + ts = localtime_r(&rtp_content.item_Start[i], &tm_store); + fprintf(fd, " %02d:%02d Title: '%s' | Artist: '%s'\n", ts->tm_hour, ts->tm_min, rtp_content.item_Title[i], rtp_content.item_Artist[i]); + } + } + } + + if (rtp_content.info_SportIndex >= 0) { + fprintf(fd, "--- Sports ---\n"); + ind = rtp_content.info_SportIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Sport[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Sport[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Sport[i]); + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Sport[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Sport[i]); + } + } + + if (rtp_content.info_LotteryIndex >= 0) { + fprintf(fd, "--- Lottery ---\n"); + ind = rtp_content.info_LotteryIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Lottery[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Lottery[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Lottery[i]); + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Lottery[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Lottery[i]); + } + } + + if (rtp_content.info_WeatherIndex >= 0) { + fprintf(fd, "--- Weather ---\n"); + ind = rtp_content.info_WeatherIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Weather[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Weather[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Weather[i]); + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Weather[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Weather[i]); + } + } + + if (rtp_content.info_StockIndex >= 0) { + fprintf(fd, "--- Stockmarket ---\n"); + ind = rtp_content.info_StockIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Stock[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Stock[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Stock[i]); + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Stock[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Stock[i]); + } + } + + if (rtp_content.info_OtherIndex >= 0) { + fprintf(fd, "--- Other ---\n"); + ind = rtp_content.info_OtherIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Other[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Other[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Other[i]); + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Other[i] != NULL) + fprintf(fd, " %02d. %s\n", ++lfd, rtp_content.info_Other[i]); + } + } + + fprintf(fd, "--- Last seen Radiotext ---\n"); + ind = rtp_content.rt_Index; + if (ind < (2*MAX_RTPC-1) && rtp_content.radiotext[ind+1] != NULL) { + for (int i = ind+1; i < 2*MAX_RTPC; i++) { + if (rtp_content.radiotext[i] != NULL) + fprintf(fd, " %03d. %s\n", ++lfd, rtp_content.radiotext[i]); + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.radiotext[i] != NULL) + fprintf(fd, " %03d. %s\n", ++lfd, rtp_content.radiotext[i]); + } + + fprintf(fd, "<<<\n"); + fclose(fd); + + char *infotext; + asprintf(&infotext, "%s: %s", InfoRequest ? tr("Info-File saved") : tr("RTplus-File saved"), fpath); + Skins.Message(mtInfo, infotext, Setup.OSDMessageTime); + free(infotext); + } + else + esyslog("radio: ERROR writing RTplus-File failed '%s'", fpath); + + free(fpath); + free(fname); +} + +eOSState cRTplusOsd::ProcessKey(eKeys Key) +{ + int typ, ind; + eOSState state = cOsdMenu::ProcessKey(Key); + + if (HasSubMenu()) + return osContinue; + + if (state == osUnknown) { + switch (Key) { + case kBack: + case kOk: return osEnd; + case kBlue: if (bcount >= 4 && helpmode == 0) { + helpmode += 1; + Update(); + } + else if (bcount >= 6 && helpmode == 1) { + helpmode += 1; + Update(); + } + else + return osEnd; + break; + case k0: Update(); + break; + case k8: rtp_fileprint(); + break; + case kRed: if (helpmode == 0) { + if (btext[0] != NULL) + if ((typ = rtptyp(btext[0])) >= 0) + AddSubMenu(new cRTplusList(typ)); + } + else { + helpmode -= 1; + Update(); + } + break; + case kGreen: ind = (helpmode*2) + 1; + if (btext[ind] != NULL) { + if ((typ = rtptyp(btext[ind])) >= 0) + AddSubMenu(new cRTplusList(typ)); + } + break; + case kYellow: ind = (helpmode*2) + 2; + if (btext[ind] != NULL) { + if ((typ = rtptyp(btext[ind])) >= 0) + AddSubMenu(new cRTplusList(typ)); + } + break; + default: state = osContinue; + } + } + + static int ct; + if (++ct >= 60) { + ct = 0; + Update(); + } + + return state; +} + + +// --- cRTplusList ------------------------------------------------------ + +cRTplusList::cRTplusList(int Typ) + : cOsdMenu(RTp_Titel, 4) + , cCharSetConv((RT_Charset == 0) ? "ISO-8859-1" : NULL) +{ + typ = Typ; + refresh = false; + + Load(); + Display(); +} + +cRTplusList::~cRTplusList() +{ + typ = 0; +} + +void cRTplusList::Load(void) +{ + char text[80]; + struct tm *ts, tm_store; + int ind, lfd = 0; + char ctitle[80]; + + ts = localtime_r(&rtp_content.start, &tm_store); + switch (typ) { + case 0: snprintf(text, sizeof(text), "-- %s (max. %d) --", tr("last seen Radiotext"), 2*MAX_RTPC); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + ind = rtp_content.rt_Index; + if (ind < (2*MAX_RTPC-1) && rtp_content.radiotext[ind+1] != NULL) { + for (int i = ind+1; i < 2*MAX_RTPC; i++) { + if (rtp_content.radiotext[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.radiotext[i])); + Add(new cOsdItem(hk(text))); + } + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.radiotext[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.radiotext[i])); + Add(new cOsdItem(hk(text)), refresh); + } + } + break; + case 1: SetCols(6, 19, 1); + snprintf(text, sizeof(text), "-- %s --", tr("Playlist")); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s\t%s\t\t%s", tr("Time"), tr("Title"), tr("Artist")); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + ind = rtp_content.item_Index; + if (ind < (MAX_RTPC-1) && rtp_content.item_Title[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) { + ts = localtime_r(&rtp_content.item_Start[i], &tm_store); + snprintf(ctitle, sizeof(ctitle), "%s", Convert(rtp_content.item_Title[i])); + snprintf(text, sizeof(text), "%02d:%02d\t%s\t\t%s", ts->tm_hour, ts->tm_min, ctitle, Convert(rtp_content.item_Artist[i])); + Add(new cOsdItem(hk(text))); + } + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.item_Title[i] != NULL && rtp_content.item_Artist[i] != NULL) { + ts = localtime_r(&rtp_content.item_Start[i], &tm_store); + snprintf(ctitle, sizeof(ctitle), "%s", Convert(rtp_content.item_Title[i])); + snprintf(text, sizeof(text), "%02d:%02d\t%s\t\t%s", ts->tm_hour, ts->tm_min, ctitle, Convert(rtp_content.item_Artist[i])); + Add(new cOsdItem(hk(text)), refresh); + } + } + break; + case 2: snprintf(text, sizeof(text), "-- %s --", tr("Sports")); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + ind = rtp_content.info_SportIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Sport[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Sport[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Sport[i])); + Add(new cOsdItem(hk(text))); + } + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Sport[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Sport[i])); + Add(new cOsdItem(hk(text)), refresh); + } + } + break; + case 3: snprintf(text, sizeof(text), "-- %s --", tr("Lottery")); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + ind = rtp_content.info_LotteryIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Lottery[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Lottery[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Lottery[i])); + Add(new cOsdItem(hk(text))); + } + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Lottery[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Lottery[i])); + Add(new cOsdItem(hk(text)), refresh); + } + } + break; + case 4: snprintf(text, sizeof(text), "-- %s --", tr("Weather")); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + ind = rtp_content.info_WeatherIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Weather[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Weather[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Weather[i])); + Add(new cOsdItem(hk(text))); + } + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Weather[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Weather[i])); + Add(new cOsdItem(hk(text)), refresh); + } + } + break; + case 5: snprintf(text, sizeof(text), "-- %s --", tr("Stockmarket")); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + ind = rtp_content.info_StockIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Stock[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Stock[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Stock[i])); + Add(new cOsdItem(hk(text))); + } + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Stock[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Stock[i])); + Add(new cOsdItem(hk(text)), refresh); + } + } + break; + case 6: snprintf(text, sizeof(text), "-- %s --", tr("Other")); + Add(new cOsdItem(hk(text))); + snprintf(text, sizeof(text), "%s", " "); + Add(new cOsdItem(hk(text))); + ind = rtp_content.info_OtherIndex; + if (ind < (MAX_RTPC-1) && rtp_content.info_Other[ind+1] != NULL) { + for (int i = ind+1; i < MAX_RTPC; i++) { + if (rtp_content.info_Other[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Other[i])); + Add(new cOsdItem(hk(text))); + } + } + } + for (int i = 0; i <= ind; i++) { + if (rtp_content.info_Other[i] != NULL) { + snprintf(text, sizeof(text), "%d.\t%s", ++lfd, Convert(rtp_content.info_Other[i])); + Add(new cOsdItem(hk(text)), refresh); + } + } + break; + } + + SetHelp(NULL, NULL , refresh ? tr("Refresh Off") : tr("Refresh On"), tr("Back")); +} + +void cRTplusList::Update(void) +{ + Clear(); + Load(); + Display(); +} + +eOSState cRTplusList::ProcessKey(eKeys Key) +{ + eOSState state = cOsdMenu::ProcessKey(Key); + + if (state == osUnknown) { + switch (Key) { + case k0: Update(); + break; + case kYellow: refresh = (refresh) ? false : true; + Update(); + break; + case kBack: + case kOk: + case kBlue: return osBack; + default: state = osContinue; + } + } + + static int ct; + if (refresh) { + if (++ct >= 20) { + ct = 0; + Update(); + } + } + + return state; +} + + +//--------------- End ----------------------------------------------------------------- diff --git a/radioaudio.h b/radioaudio.h new file mode 100644 index 0000000..90c9cae --- /dev/null +++ b/radioaudio.h @@ -0,0 +1,241 @@ +/* + * radioaudio.h - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef __RADIO_AUDIO_H +#define __RADIO_AUDIO_H + +#include <linux/types.h> +#include <linux/dvb/video.h> +#include <vdr/player.h> +#include <vdr/device.h> +#include <vdr/audio.h> +#include <vdr/osd.h> +#include <vdr/menu.h> +#include <vdr/receiver.h> + +extern char *ConfigDir; +extern char *DataDir; +extern char *ReplayFile; + +//Setup-Params +extern int S_RtFunc; +extern int S_StillPic; +extern int S_RtOsdTitle; +extern int S_RtOsdTags; +extern int S_RtOsdPos; +extern int S_RtOsdRows; +extern int S_RtOsdLoop; +extern int S_RtOsdTO; +extern int S_RtSkinColor; +extern int S_RtBgCol; +extern int S_RtBgTra; +extern int S_RtFgCol; +extern int S_RtDispl; +extern int S_RtMsgItems; +extern int S_RassText; +extern int S_RockAnt; +extern uint32_t rt_color[9]; +extern int S_Verbose; +//Radiotext +#define RT_MEL 65 +extern char RT_Text[5][RT_MEL]; +extern char RTP_Artist[RT_MEL], RTP_Title[RT_MEL]; +extern int RT_Info, RT_Index, RT_PTY; +extern time_t RTP_Starttime; +extern bool RT_OsdTO, RTplus_Osd, RT_ReOpen; +extern int Radio_CA; +extern int RT_OsdTOTemp; +extern int IsRadioOrReplay; +extern int RT_Charset; +// Info +extern bool InfoRequest; + +void radioStatusMsg(void); + +// seperate thread for showing RadioImages +class cRadioImage: public cThread { +private: + char *imagepath; + bool imageShown; + void Show (const char *file); + void send_pes_packet(unsigned char *data, int len, int timestamp); +protected: + virtual void Action(void); + void Stop(void); +public: + cRadioImage(void); + virtual ~cRadioImage(); + static void Init(void); + static void Exit(void); + void SetBackgroundImage(const char *Image); +}; + +// RDS-Receiver for seperate Data-Pids +class cRDSReceiver : public cReceiver { +private: + int pid; + bool rt_start; + bool rt_bstuff; +protected: + virtual void Receive(uchar *Data, int Length); +public: + cRDSReceiver(int Pid); + virtual ~cRDSReceiver(void); +}; + +class cRadioAudio : public cAudio { +private: + bool enabled; + int first_packets; + int audiopid; + bool bratefound; + //Radiotext + cDevice *rdsdevice; + void RadiotextCheckPES(const uchar *Data, int Length); + void RadiotextCheckTS(const uchar *Data, int Length); + void AudioRecorderService(void); + void RassDecode(uchar *Data, int Length); +protected: + virtual void Play(const uchar *Data, int Length, uchar Id); + virtual void PlayTs(const uchar *Data, int Length); + virtual void Mute(bool On) {}; + virtual void Clear(void) {}; +public: + cRadioAudio(void); + virtual ~cRadioAudio(void); + char *bitrate; + void EnableRadioTextProcessing(const char *Titel, int apid, bool replay = false); + void DisableRadioTextProcessing(); + void RadiotextDecode(uchar *Data, int Length); + void RDS_PsPtynDecode(bool PTYN, uchar *Data, int Length); +}; + +class cRadioTextOsd : public cOsdObject, public cCharSetConv { +private: + cOsd *osd; + cOsd *qosd; + cOsd *qiosd; + const cFont *ftitel; + const cFont *ftext; + int fheight; + int bheight; + eKeys LastKey; + cTimeMs osdtimer; + void rtp_print(void); + bool rtclosed; + bool rassclosed; + static cBitmap rds, arec, rass, radio; + static cBitmap index, marker, page1, pages2, pages3, pages4, pageE; + static cBitmap no0, no1, no2, no3, no4, no5, no6, no7, no8, no9, bok; +public: + cRadioTextOsd(); + ~cRadioTextOsd(); + virtual void Hide(void); + virtual void Show(void); + virtual void ShowText(void); + virtual void RTOsdClose(void); + int RassImage(int QArchiv, int QKey, bool DirUp); + virtual void RassOsd(void); + virtual void RassOsdTip(void); + virtual void RassOsdClose(void); + virtual void RassImgSave(const char *size, int pos); + virtual eOSState ProcessKey(eKeys Key); + virtual bool IsInteractive(void) { return false; } +}; + +class cRTplusOsd : public cOsdMenu, public cCharSetConv { +private: + int bcount; + int helpmode; + const char *listtyp[7]; + char *btext[7]; + int rtptyp(char *btext); + void rtp_fileprint(void); +public: + cRTplusOsd(void); + virtual ~cRTplusOsd(); + virtual void Load(void); + virtual void Update(void); + virtual eOSState ProcessKey(eKeys Key); +}; + +class cRTplusList : public cOsdMenu, public cCharSetConv { +private: + int typ; + bool refresh; +public: + cRTplusList(int Typ = 0); + ~cRTplusList(); + virtual void Load(void); + virtual void Update(void); + virtual eOSState ProcessKey(eKeys Key); +}; + + +// Radiotext-Memory RT+Classes 2.1 +#define MAX_RTPC 50 +struct rtp_classes { + time_t start; + char temptext[RT_MEL]; + char *radiotext[2*MAX_RTPC]; + int rt_Index; + // Item + bool item_New; + char *item_Title[MAX_RTPC]; // 1 + char *item_Artist[MAX_RTPC]; // 4 + time_t item_Start[MAX_RTPC]; + int item_Index; + // Info + char *info_News; // 12 + char *info_NewsLocal; // 13 + char *info_Stock[MAX_RTPC]; // 14 + int info_StockIndex; + char *info_Sport[MAX_RTPC]; // 15 + int info_SportIndex; + char *info_Lottery[MAX_RTPC]; // 16 + int info_LotteryIndex; + char *info_DateTime; // 24 + char *info_Weather[MAX_RTPC]; // 25 + int info_WeatherIndex; + char *info_Traffic; // 26 + char *info_Alarm; // 27 + char *info_Advert; // 28 + char *info_Url; // 29 + char *info_Other[MAX_RTPC]; // 30 + int info_OtherIndex; + // Programme + char *prog_StatShort; // 31 + char *prog_Station; // 32 + char *prog_Now; // 33 + char *prog_Next; // 34 + char *prog_Part; // 35 + char *prog_Host; // 36 + char *prog_EditStaff; // 37 + char *prog_Homepage; // 39 + // Interactivity + char *phone_Hotline; // 41 + char *phone_Studio; // 42 + char *sms_Studio; // 44 + char *email_Hotline; // 46 + char *email_Studio; // 47 +// to be continue... +}; + +// plugin audiorecorder service +struct Audiorecorder_StatusRtpChannel_v1_0 { + const cChannel *channel; + int status; + /* + * 0 = channel is unknown ... + * 1 = no receiver is attached + * 2 = receiver is attached + * 3 = actual recording + */ +}; +extern const cChannel *chan; + +#endif //__RADIO_AUDIO_H diff --git a/radioepg.c b/radioepg.c new file mode 100644 index 0000000..69bfff0 --- /dev/null +++ b/radioepg.c @@ -0,0 +1,370 @@ +/* + * radioepg.c - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "radioepg.h" + + +// Premiere-Radio +int epg_premiere(const char *epgtitle, const char *epgdescr, time_t epgstart, time_t epgend) +{ + int i; + const char *p; + char artist[RT_MEL], titel[RT_MEL], album[RT_MEL], jahr[RT_MEL]; + struct tm tm_store; + + // EPG not actual + if (epgtitle == NULL || epgdescr == NULL) { + dsyslog("radio: epg_premiere called, no title or description, nextCall in 5 s\n"); + return 5; + } + + // Interpret + p = strstr(epgtitle, PEPG_ARTIST); + if (p != NULL) { + p += strlen(PEPG_ARTIST); + strcpy(artist, p); + // Titel + p = strstr(epgdescr, PEPG_TITEL); + if (p != NULL) { + p += strlen(PEPG_TITEL); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(titel, p-i, i); + titel[i] = '\0'; + } + else + sprintf(titel, "---"); + // Album + p = strstr(epgdescr, PEPG_ALBUM); + if (p != NULL) { + p += strlen(PEPG_ALBUM); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(album, p-i, i); + album[i] = '\0'; + } + else + sprintf(album, "---"); + } + else { // P-Klassik ? + // Komponist + p = strstr(epgtitle, PEPG_KOMP); + if (p != NULL) { + p += strlen(PEPG_KOMP); + strcpy(artist, p); + // und Interpret + p = strstr(epgdescr, PEPG_ARTIST); + if (p != NULL) { + strcpy(album, artist); // Album = Komponist + p += strlen(PEPG_ARTIST); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(artist, p-i, i); + artist[i] = '\0'; + } + else + sprintf(album, "---"); + // Werk + p = strstr(epgdescr, PEPG_WERK); + if (p != NULL) { + p += strlen(PEPG_WERK); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(titel, p-i, i); + titel[i] = '\0'; + } + else + sprintf(titel, "---"); + } + else { + sprintf(artist, "---"); + sprintf(titel, "---"); + } + } + + // Jahr + p = strstr(epgdescr, PEPG_JAHR); + if (p != NULL) { + p += strlen(PEPG_JAHR); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(jahr, p-i, i); + jahr[i] = '\0'; + } + else + sprintf(jahr, "----"); + // quick hack for epg-blabla + if (strlen(jahr) > 24) + sprintf(jahr, "----"); + + int nextevent = epgend - time(NULL); + + if (strcmp(RTP_Artist, artist)!=0 || strcmp(RTP_Title, titel)!=0) { + snprintf(RTP_Artist, RT_MEL, "%s", artist); + snprintf(RTP_Title, RT_MEL, "%s", titel); + RTP_Starttime = epgstart; + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%02d:%02d %s: %s", ts->tm_hour, ts->tm_min, RTP_Artist, RTP_Title); + snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + if (strcmp(album, "---") != 0) { + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], " ... %s (%s)", album, jahr); + snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + } + if (++rtp_content.item_Index >= MAX_RTPC) + rtp_content.item_Index = 0; + if (rtp_content.item_Index >= 0) { + rtp_content.item_Start[rtp_content.item_Index] = RTP_Starttime; + asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", RTP_Artist); + asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", RTP_Title); + } + RT_MsgShow = RT_PlusShow = true; + (RT_Info > 0) ? : RT_Info = 2; + radioStatusMsg(); + if ((S_Verbose & 0x0f) >= 1) + printf("Premiereradio: %s / %s\n", RTP_Artist, RTP_Title); + } + + dsyslog("radio: epg_premiere called, nextEvent in %ds\n", nextevent); + return (nextevent < 0) ? 10 : nextevent+2; +} + + +// Kabel Deutschland Radio +int epg_kdg(const char *epgdescr, time_t epgstart, time_t epgend) +{ + int i; + const char *p; + char artist[RT_MEL], titel[RT_MEL], album[RT_MEL], komp[RT_MEL]; + struct tm tm_store; + + // EPG not actual + if (epgdescr == NULL) { + dsyslog("radio: epg_kdg called, no description, nextCall in 5s\n"); + return 5; + } + + // Titel + p = strstr(epgdescr, KDEPG_TITEL); + if (p != NULL) { + p += strlen(KDEPG_TITEL); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(titel, p-i, i); + titel[i] = '\0'; + } + else + sprintf(titel, "---"); + // Interpret + p = strstr(epgdescr, KDEPG_ARTIST); + if (p != NULL) { + p += strlen(KDEPG_ARTIST); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(artist, p-i, i); + artist[i] = '\0'; + } + else + sprintf(artist, "---"); + // Album + p = strstr(epgdescr, KDEPG_ALBUM); + if (p != NULL) { + p += strlen(KDEPG_ALBUM); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(album, p-i, i); + album[i] = '\0'; + } + else + sprintf(album, "---"); + // Komponist + p = strstr(epgdescr, KDEPG_KOMP); + if (p != NULL) { + p += strlen(KDEPG_KOMP); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(komp, p-i, i); + komp[i] = '\0'; + } + else + sprintf(komp, "---"); + + int nextevent = epgend - time(NULL); + + if (strcmp(RTP_Artist, artist)!=0 || strcmp(RTP_Title, titel)!=0) { + snprintf(RTP_Artist, RT_MEL, "%s", artist); + snprintf(RTP_Title, RT_MEL, "%s", titel); + RTP_Starttime = epgstart; + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%02d:%02d %s: %s", ts->tm_hour, ts->tm_min, RTP_Artist, RTP_Title); + snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + if (strcmp(album, "---") != 0) { + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], " ... %s (%s)", album, komp); + snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + } + if (++rtp_content.item_Index >= MAX_RTPC) + rtp_content.item_Index = 0; + if (rtp_content.item_Index >= 0) { + rtp_content.item_Start[rtp_content.item_Index] = RTP_Starttime; + asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", RTP_Artist); + asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", RTP_Title); + } + RT_MsgShow = RT_PlusShow = true; + (RT_Info > 0) ? : RT_Info = 2; + radioStatusMsg(); + if ((S_Verbose & 0x0f) >= 1) + printf("KDG-Radio: %s / %s\n", RTP_Artist, RTP_Title); + } + + dsyslog("radio: epg_kdg called, nextEvent in %ds\n", nextevent); + return (nextevent < 0) ? 10 : nextevent+2; +} + +// Unity Media - Music Choice, Kabel +int epg_unitymedia(const char *epgdescr, time_t epgstart, time_t epgend) +{ + int i; + const char *p; + char artist[RT_MEL], titel[RT_MEL], album[RT_MEL], jahr[RT_MEL], komp[RT_MEL]; + struct tm tm_store; + + // EPG not actual + if (epgdescr == NULL) { + dsyslog("radio: epg_unitymedia called, no title or description, nextCall in 5s\n"); + return 5; + } + + // Titel + p = strstr(epgdescr, UMEPG_TITEL); + if (p != NULL) { + p += strlen(UMEPG_TITEL); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(titel, p-i, i); + titel[i] = '\0'; + } + else { + // Kein titel check for Werk + p = strstr(epgdescr, UMEPG_WERK); + if (p != NULL) { + p += strlen(UMEPG_WERK); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(titel, p-i, i); + titel[i] = '\0'; + } + else + sprintf(titel, "---"); + } + + // Interpret + p = strstr(epgdescr, UMEPG_ARTIST); + if (p != NULL) { + p += strlen(UMEPG_ARTIST); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(artist, p-i, i); + artist[i] = '\0'; + } + else { + p = strstr(epgdescr, UMEPG_KOMP); + if (p != NULL) { + p += strlen(UMEPG_KOMP); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(artist, p-i, i); + artist[i] = '\0'; + } + else + sprintf(artist, "---"); + } + + // Komponist + p = strstr(epgdescr, UMEPG_KOMP); + if (p != NULL) { + p += strlen(UMEPG_KOMP); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(komp, p-i, i); + komp[i] = '\0'; + } + else + sprintf(komp, "---"); + + // Album + p = strstr(epgdescr, UMEPG_ALBUM); + if (p != NULL) { + p += strlen(UMEPG_ALBUM); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(album, p-i, i); + album[i] = '\0'; + } + else + sprintf(album, "---"); + + // Jahr + p = strstr(epgdescr, UMEPG_JAHR); + if (p != NULL) { + p += strlen(UMEPG_JAHR); + i = 1; + while (*++p!='\n' && *p!='\0' && i<(RT_MEL-1)) ++i; + memcpy(jahr, p-i, i); + jahr[i] = '\0'; + } + else + sprintf(jahr, "---"); + + int nextevent = epgend - time(NULL); + if (strcmp(RTP_Artist, artist)!=0 || strcmp(RTP_Title, titel)!=0) { + snprintf(RTP_Artist, RT_MEL, "%s", artist); + snprintf(RTP_Title, RT_MEL, "%s", titel); + RTP_Starttime = epgstart; + struct tm *ts = localtime_r(&RTP_Starttime, &tm_store); + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], "%02d:%02d %s: %s", ts->tm_hour, ts->tm_min, RTP_Artist, RTP_Title); + snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + if (strcmp(album, "---") != 0) { + if (++rtp_content.rt_Index >= 2*MAX_RTPC) + rtp_content.rt_Index = 0; + asprintf(&rtp_content.radiotext[rtp_content.rt_Index], " ... %s (%s)", album, jahr); + snprintf(RT_Text[RT_Index], RT_MEL, "%s", rtp_content.radiotext[rtp_content.rt_Index]); + RT_Index +=1; if (RT_Index >= S_RtOsdRows) RT_Index = 0; + } + if (++rtp_content.item_Index >= MAX_RTPC) + rtp_content.item_Index = 0; + if (rtp_content.item_Index >= 0) { + rtp_content.item_Start[rtp_content.item_Index] = RTP_Starttime; + asprintf(&rtp_content.item_Artist[rtp_content.item_Index], "%s", RTP_Artist); + asprintf(&rtp_content.item_Title[rtp_content.item_Index], "%s", RTP_Title); + } + RT_Charset = 1; // UTF8 ?!? + RT_MsgShow = RT_PlusShow = true; + (RT_Info > 0) ? : RT_Info = 2; + radioStatusMsg(); + if ((S_Verbose & 0x0f) >= 1) + printf("UnityMedia-Radio: %s / %s\n", RTP_Artist, RTP_Title); + } + + dsyslog("radio: epg_um called, nextEvent in %ds\n", nextevent); + return (nextevent < 0) ? 10 : nextevent+2; +} + +// end diff --git a/radioepg.h b/radioepg.h new file mode 100644 index 0000000..56318e6 --- /dev/null +++ b/radioepg.h @@ -0,0 +1,61 @@ +/* + * radioeph.h - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef _RADIOEPG__H +#define _RADIOEPG__H + +#include <stdio.h> +#include <time.h> +#include "radioaudio.h" + +extern bool RT_MsgShow, RT_PlusShow; +extern rtp_classes rtp_content; + + +/* Premiere */ +#define PREMIERERADIO_TID 17 // Premiere changes to SKY, EPG working ??? +// EPG-Info +#define PEPG_ARTIST "Interpret: " +#define PEPG_TITEL "Titel: " +#define PEPG_ALBUM "Album: " +#define PEPG_JAHR "Jahr: " +// Klassik +#define PEPG_WERK "Werk: " +#define PEPG_KOMP "Komponist: " +int epg_premiere(const char *epgtitle, const char *epgdescr, time_t epgstart, time_t epgend); + + +/* Kabel Deutschlang */ +#define KDRADIO_TID 10003 +// EPG-Info +#define KDEPG_ARTIST "Artist: " +#define KDEPG_TITEL "Song: " +#define KDEPG_ALBUM "Album: " +#define KDEPG_KOMP "Comp: " +int epg_kdg(const char *epgdescr, time_t epgstart, time_t epgend); + + +/* Unity Media, Kabel */ +#define UMRADIO_TID1 111 +#define UMRADIO_TID2 131 +#define UMRADIO_TID3 141 +#define UMRADIO_TID4 181 +#define UMRADIO_TID5 191 + +// EPG-Info +#define UMEPG_SUFFIX "Music Choice bei Unitymedia" +#define UMEPG_ARTIST "Interpret: " +#define UMEPG_TITEL "Titel: " +#define UMEPG_ALBUM "Album: " +#define UMEPG_JAHR "Jahr: " +#define UMEPG_WERK "Werk: " +#define UMEPG_KOMP "Komponist: " + +int epg_unitymedia(const char *epgdescr, time_t epgstart, time_t epgend); + + +#endif diff --git a/radioskin.c b/radioskin.c new file mode 100644 index 0000000..0b4aa18 --- /dev/null +++ b/radioskin.c @@ -0,0 +1,345 @@ +/* + * radioskin.c - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include "radioskin.h" +#include <vdr/config.h> + + +const cRadioSkin radioSkin[eRadioSkinMaxNumber] = +{ + { + // dummy + "dummy", + 0xFFFCFCFC, // clrTitleBack + 0xFF000000, // clrTitleText + 0x7F000000, // clrBack + 0xFFFCFCFC, // clrText + }, + { + // Classic + "default~classic", + 0xFF00FCFC, // clrTitleBack + 0xFF000000, // clrTitleText + 0x7F000000, // clrBack + 0xFFFCFCFC, // clrText + }, + { + // ST:TNG + "default~sttng", + 0xFFFCC024, // clrTitleBack + 0xFF000000, // clrTitleText + 0x7F000000, // clrBack + 0xFFFCC024, // clrText + }, + { + // EgalsTry + "default~EgalsTry", + 0xDFBEBAC3, // clrTitleBack + 0xFF280249, // clrTitleText + 0xCA280249, // clrBack + 0xDFD4D7DB, // clrText + }, + { + // EgalsTry + "blue~EgalsTry", + 0xDFBEBAC3, // clrTitleBack + 0xFF280249, // clrTitleText + 0xCA2B1B9E, // clrBack + 0xDFCFCFCF, // clrText + }, + { + // Enigma + "default~Enigma", + 0xB84158BC, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0xB8DEE5FA, // clrBack + 0xFF000000, // clrText + }, + { + // Enigma-DarkBlue + "DarkBlue~Enigma", + 0xB84158BC, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0xB82B2B3C, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // Enigma-WineRed + "WineRed~Enigma", + 0xB8BC5241, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0xB8FAE2DE, // clrBack + 0xFF000000, // clrText + }, + { + // Enigma-AppleGreen + "AppleGreen~Enigma", + 0xB847BC41, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0xB8E2FADE, // clrBack + 0xFF000000, // clrText + }, + { + // Enigma-WomensLike + "WomensLike~Enigma", + 0xB8BC41B2, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0xB8FADEFA, // clrBack + 0xFF000000, // clrText + }, + { + // Enigma-YellowSun + "YellowSun~Enigma", + 0xE5ffd927, // clrTitleBack + 0xFF000000, // clrTitleText + 0xE5fae9bc, // clrBack + 0xFF000000, // clrText + }, + { + // Enigma-Black + "Black~Enigma", + 0xEE37383a, // clrTitleBack + 0xFFDDDDDD, // clrTitleText + 0xEE3e4044, // clrBack + 0xFFDDDDDD, // clrText + }, + { + // Enigma-Blue + "Blue~Enigma", + 0xEE4158BC, // clrTitleBack + 0xFFDDDDDD, // clrTitleText + 0xEE496DCC, // clrBack + 0xFFDDDDDD, // clrText + }, + { + // Enigma-Blue2 + "Blue2~Enigma", + 0xEE4158BC, // clrTitleBack + 0xFFDDDDDD, // clrTitleText + 0xEE393D8C, // clrBack + 0xFFDDDDDD, // clrText + }, + { + // Enigma-Blue3 + "Blue3~Enigma", + 0xEE4158BC, // clrTitleBack + 0xFFDDDDDD, // clrTitleText + 0xEE333388, // clrBack + 0xFFDDDDDD, // clrText + }, + { + // Enigma-Coolblue + "Coolblue~Enigma", + 0xEEC40000, // clrTitleBack + 0xFFDDDDDD, // clrTitleText + 0xEE000066, // clrBack + 0xFFDDDDDD, // clrText + }, + { + // Enigma-Grey + "Grey~Enigma", + 0xEE5f6064, // clrTitleBack + 0xFFDDDDDD, // clrTitleText + 0xEE3e4044, // clrBack + 0xFFDDDDDD, // clrText + }, + { + // Enigma-MoBuntu + "MoBuntu~Enigma", + 0xDF793809, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0xDF200F02, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // Enigma-bgw + "bgw~Enigma", + 0xE5333333, // clrTitleBack + 0xFFDCDCDC, // clrTitleText + 0xE5DCDCDC, // clrBack + 0xFF000000, // clrText + }, + { + // DeepBlue + "default~DeepBlue", + 0xC832557A, // clrTitleBack + 0xFF000000, // clrTitleText + 0xC80C0C0C, // clrBack + 0xFF9A9A9A, // clrText + }, + { + // SilverGreen + "default~SilverGreen", + 0xD9293841, // clrTitleBack + 0xFFB3BDCA, // clrTitleText + 0xD9526470, // clrBack + 0xFFB3BDCA, // clrText + }, + { + // LightBlue 16/256 + "default~lightblue", + 0xC88488AA, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0xC853567B, // clrBack + 0xFF8488AA, // clrText + }, + { + // Soppalusikka + "default~soppalusikka", + 0xC833AAEE, // clrTitleBack + 0xFF000000, // clrTitleText + 0xC8000066, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // Soppalusikka-Mint + "mint~soppalusikka", + 0xCCBBFFFF, // clrTitleBack + 0xFF000000, // clrTitleText + 0xBB005555, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // Soppalusikka-Orange + "orange~soppalusikka", + 0xDDFF5500, // clrTitleBack + 0xFF000000, // clrTitleText + 0x88111100, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // Soppalusikka-Vanilla + "vanilla~soppalusikka", + 0xFF00FCFC, // clrTitleBack + 0xFF000000, // clrTitleText + 0x7F000000, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // Soppalusikka-Blackberry + "blackberry~soppalusikka", + 0xDD0000C0, // clrTitleBack + 0xFFEEEEEE, // clrTitleText + 0x88111100, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // Soppalusikka-Citron + "citron~soppalusikka", + 0xDDFCC024, // clrTitleBack + 0xFF000000, // clrTitleText + 0xAF101000, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // Elchi-default + "default~Elchi", + 0xCC2BA7F1, // clrTitleBack + 0xFF000000, // clrTitleText + 0x77000066, // clrBack + 0xFFFCFCFC, // clrText + }, + { + // Elchi-MVBlack + "MVBlack~Elchi", + 0xCC0000C0, // clrTitleBack + 0xFFEEEEEE, // clrTitleText + 0x88111100, // clrBack + 0xFFEEBB22, // clrText + }, + { + // Elchi-MVWhite + "MVWhite~Elchi", + 0xCC0000C0, // clrTitleBack + 0xFFEEEEEE, // clrTitleText + 0x88CCCCCC, // clrBack + 0xFF444488, // clrText + }, + { + // Elchi-Moose + "Moose~Elchi", + 0xCC2BA7F1, // clrTitleBack + 0xFF000000, // clrTitleText + 0x77000066, // clrBack + 0xFFFCFCFC, // clrText + }, + { + // Elchi_Plugin + "change~Elchi_Plugin", + 0xC833AAEE, // clrTitleBack + 0xFF000000, // clrTitleText + 0xC8000066, // clrBack + 0xFFFFFFFF, // clrText + }, + { + // EgalOrange + "default~EgalOrange", + 0xDFCC8037, // clrTitleBack + 0xFF202020, // clrTitleText + 0xBF2D4245, // clrBack + 0xDFCFCFCF, // clrText + }, + { + // Moronimo, can't test it + "default~Moronimo", + 0xDF3E5578, // clrTitleBack + 0xFF9BBAD7, // clrTitleText + 0xDF294A6B, // clrBack + 0xFF9A9A9A, // clrText + }, + { + // Duotone, can't test it + "default~DuoTone", + 0xFFFCFCFC, // clrTitleBack + 0x7F000000, // clrTitleText + 0x7F000000, // clrBack + 0xFFFCFCFC, // clrText + }, + { + // EgalT2-default + "default~EgalT2", + 0x9F000000, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0x9F000000, // clrBack + 0xFFABABAB, // clrText + }, + { + // EgalT2-BluYell + "bluyell~EgalT2", + 0x9F00005F, // clrTitleBack + 0xFFFCF680, // clrTitleText + 0x9F00005F, // clrBack + 0xAFC4BF64, // clrText + }, + { + // EgalT2-Purple + "purple~EgalT2", + 0xAF3e074c, // clrTitleBack + 0xFFFFFFFF, // clrTitleText + 0xAF3e074c, // clrBack + 0xFFABABAB, // clrText + }, +}; + +int theme_skin(void) +{ + //printf("vdr-radio: Theme~Skin = %s~%s\n", Setup.OSDTheme, Setup.OSDSkin); + char *temp; + int i = 0; + + asprintf(&temp, "%s~%s", Setup.OSDTheme, Setup.OSDSkin); + for (i = eRadioSkinMaxNumber-1; i > 0; i--) { + if (strstr(temp, radioSkin[i].name) != NULL) + break; + } + free(temp); + + return i; +} + + +//--------------- End ----------------------------------------------------------------- diff --git a/radioskin.h b/radioskin.h new file mode 100644 index 0000000..b14d3cf --- /dev/null +++ b/radioskin.h @@ -0,0 +1,69 @@ +/* + * radioskin.h - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef __RADIO_SKIN_H +#define __RADIO_SKIN_H + + +enum eRadioSkin +{ + eRadioSkinDummy, + eRadioSkinClassicDefault, + eRadioSkinSttngDefault, + eRadioSkinEgalsTryDefault, + eRadioSkinEgalsTryBlue, + eRadioSkinEnigmaDefault, + eRadioSkinEnigmaDarkBlue, + eRadioSkinEnigmaWineRed, + eRadioSkinEnigmaAppleGreen, + eRadioSkinEnigmaWomensLike, + eRadioSkinEnigmaYellowSun, + eRadioSkinEnigmaBlack, + eRadioSkinEnigmaBlue, + eRadioSkinEnigmaBlue2, + eRadioSkinEnigmaBlue3, + eRadioSkinEnigmaCoolblue, + eRadioSkinEnigmaGrey, + eRadioSkinEnigmaMoBuntu, + eRadioSkinEnigmabgw, + eRadioSkinDeepBlueDefault, + eRadioSkinSilverGreenDefault, + eRadioSkinLightBlueDefault, + eRadioSkinSoppalusikkaDefault, + eRadioSkinSoppalusikkaMint, + eRadioSkinSoppalusikkaOrange, + eRadioSkinSoppalusikkaVanilla, + eRadioSkinSoppalusikkaBlackberry, + eRadioSkinSoppalusikkaCitron, + eRadioSkinElchiDefault, + eRadioSkinElchiMVBlack, + eRadioSkinElchiMVWhite, + eRadioSkinElchiMoose, + eRadioSkinElchiPluginDefault, + eRadioSkinEgalOrangeDefault, + eRadioSkinMoronimoDefault, + eRadioSkinDuotoneDefault, + eRadioSkinEgalT2Default, + eRadioSkinEgalT2BluYell, + eRadioSkinEgalT2Purple, + eRadioSkinMaxNumber +}; + +struct cRadioSkin +{ + const char *name; // Theme~Skin + unsigned int clrTitleBack; // Title-Background + unsigned int clrTitleText; // Title-Text + unsigned int clrBack; // Background + unsigned int clrText; // Text +}; +extern const cRadioSkin radioSkin[eRadioSkinMaxNumber]; + +int theme_skin(void); + + +#endif //__RADIO_SKIN_H diff --git a/radiotools.c b/radiotools.c new file mode 100644 index 0000000..8ca9c19 --- /dev/null +++ b/radiotools.c @@ -0,0 +1,1882 @@ +/* + * radiotools.c - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#include <string.h> +#include <stdio.h> +#include <math.h> +#include <sys/stat.h> +#include <vdr/tools.h> +#include "radiotools.h" +#include "radioaudio.h" + + +/* ----------------------------------------------------------------------------------------------------------- */ + +bool file_exists(const char *filename) +{ + struct stat file_stat; + + return ((stat(filename, &file_stat) == 0) ? true : false); +} + +bool enforce_directory(const char *path) +{ + struct stat sbuf; + + if (stat(path, &sbuf) != 0) { + dsyslog("radio: creating directory %s", path); + if (mkdir(path, ACCESSPERMS)) { + esyslog("radio: ERROR failed to create directory %s", path); + return false; + } + } + else { + if (!S_ISDIR(sbuf.st_mode)) { + esyslog("radio: ERROR failed to create directory %s: file exists but is not a directory", path); + return false; + } + } + + return true; +} + +/* ----------------------------------------------------------------------------------------------------------- */ + +#define crc_timetest 0 +#if crc_timetest + #include <time.h> + #include <sys/time.h> +#endif + +unsigned short crc16_ccitt(unsigned char *daten, int len, bool skipfirst) +{ +#if crc_timetest + struct timeval t; + unsigned long long tstart = 0; + if (gettimeofday(&t, NULL) == 0) + tstart = t.tv_sec*1000000 + t.tv_usec; +#endif + + // CRC16-CCITT: x^16 + x^12 + x^5 + 1 + // with start 0xffff and result invers + register unsigned short crc = 0xffff; + + if (skipfirst) *daten++; + while (len--) { + crc = (crc >> 8) | (crc << 8); + crc ^= *daten++; + crc ^= (crc & 0xff) >> 4; + crc ^= (crc << 8) << 4; + crc ^= ((crc & 0xff) << 4) << 1; + } + +#if crc_timetest + if (tstart > 0 && gettimeofday(&t, NULL) == 0) + printf("vdr-radio: crc-calctime = %d usec\n", (int)((t.tv_sec*1000000 + t.tv_usec) - tstart)); +#endif + + return ~(crc); +} + +/* ----------------------------------------------------------------------------------------------------------- */ + +#define EntityChars 56 +const char *entitystr[EntityChars] = { "'", "&", """, ">", "<", "©", "×", " ", + "Ä", "ä", "Ö", "ö", "Ü", "ü", "ß", "°", + "À", "Á", "Â", "Ã", "à", "á", "â", "ã", + "È", "É", "Ê", "Ë", "è", "é", "ê", "ë", + "Ì", "Í", "Î", "Ï", "ì", "í", "î", "ï", + "Ò", "Ó", "Ô", "Õ", "ò", "ó", "ô", "õ", + "Ù", "Ú", "Û", "Ñ", "ù", "ú", "û", "ñ" }; +const char *entitychar[EntityChars] = { "'", "&", "\"", ">", "<", "c", "*", " ", + "Ä", "ä", "Ö", "ö", "Ü", "ü", "ß", "°", + "À", "Á", "Â", "Ã", "à", "á", "â", "ã", + "È", "É", "Ê", "Ë", "è", "é", "ê", "ë", + "Ì", "Í", "Î", "Ï", "ì", "í", "î", "ï", + "Ò", "Ó", "Ô", "Õ", "ò", "ó", "ô", "õ", + "Ù", "Ú", "Û", "Ñ", "ù", "ú", "û", "ñ" }; + +char *rds_entitychar(char *text) +{ + int i = 0, l, lof, lre, space; + char *temp; + + while (i < EntityChars) { + if ((temp = strstr(text, entitystr[i])) != NULL) { + if ((S_Verbose & 0x0f) >= 2) + printf("RText-Entity: %s\n", text); + l = strlen(entitystr[i]); + lof = (temp-text); + if (strlen(text) < RT_MEL) { + lre = strlen(text) - lof - l; + space = 1; + } + else { + lre = RT_MEL - 1 - lof - l; + space = 0; + } + memmove(text+lof, entitychar[i], 1); + memmove(text+lof+1, temp+l, lre); + if (space != 0) + memmove(text+lof+1+lre, " ", l-1); + } + else i++; + } + + return text; +} + +/* ----------------------------------------------------------------------------------------------------------- */ + +#define XhtmlChars 56 +const char *xhtmlstr[XhtmlChars] = { "'", "&", """, ">", "<", "©", "*", " ", + "Ä", "ä", "Ö", "ö", "Ü", "ü", "ß", "°", + "À", "Á", "Â", "Ã", "à", "á", "â", "ã", + "È", "É", "Ê", "Ë", "è", "é", "ê", "ë", + "Ì", "Í", "Î", "Ï", "ì", "í", "î", "ï", + "Ò", "Ó", "Ô", "Õ", "ò", "ó", "ô", "õ", + "Ù", "Ú", "Û", "Ñ", "ù", "ú", "û", "ñ" }; +/* hex todo: "'", "&", */ +/* see *entitychar[] +const char *xhtmlychar[EntityChars] = { "'", "&", "\"", ">", "<", "c", "*", " ", + "Ä", "ä", "Ö", "ö", "Ü", "ü", "ß", "°", + "À", "Á", "Â", "Ã", "à", "á", "â", "ã", + "È", "É", "Ê", "Ë", "è", "é", "ê", "ë", + "Ì", "Í", "Î", "Ï", "ì", "í", "î", "ï", + "Ò", "Ó", "Ô", "Õ", "ò", "ó", "ô", "õ", + "Ù", "Ú", "Û", "Ñ", "ù", "ú", "û", "ñ" }; +*/ + +char *xhtml2text(char *text) +{ + int i = 0, l, lof, lre, space; + char *temp; + + while (i < XhtmlChars) { + if ((temp = strstr(text, xhtmlstr[i])) != NULL) { + if ((S_Verbose & 0x0f) >= 2) + printf("XHTML-Char: %s\n", text); + l = strlen(xhtmlstr[i]); + lof = (temp-text); + if (strlen(text) < RT_MEL) { + lre = strlen(text) - lof - l; + space = 1; + } + else { + lre = RT_MEL - 1 - lof - l; + space = 0; + } + memmove(text+lof, entitychar[i], 1); + memmove(text+lof+1, temp+l, lre); + if (space != 0) + memmove(text+lof+1+lre, " ", l-1); + } + else i++; + } + + rds_entitychar(text); + return text; +} + +/* ----------------------------------------------------------------------------------------------------------- */ + +char *rtrim(char *text) +{ + char *s = text + strlen(text) - 1; + while (s >= text && (*s == ' ' || *s == '\t' || *s == '\n' || *s == '\r')) + *s-- = 0; + + return text; +} + +/* ----------------------------------------------------------------------------------------------------------- */ + +const char *bitrates[5][16] = { + // MPEG 1, Layer 1-3 + { "free", "32k", "64k", "96k", "128k", "160k", "192k", "224k", "256k", "288k", "320k", "352k", "384k", "416k", "448k", "bad" }, + { "free", "32k", "48k", "56k", "64k", "80k", "96k", "112k", "128k", "160k", "192k", "224k", "256k", "320k", "384k", "bad" }, + { "free", "32k", "40k", "48k", "56k", "64k", "80k", "96k", "112k", "128k", "160k", "192k", "224k", "256k", "320k", "bad" } +/* MPEG 2/2.5, Layer 1+2/3 + { "free", "32k", "48k", "56k", "64k", "80k", "96k", "112k", "128k", "144k", "160k", "176k", "192k", "224k", "256k", "bad" }, + { "free", "8k", "16k", "24k", "32k", "40k", "48k", "56k", "64k", "80k", "96k", "112k", "128k", "144k", "160k", "bad" } +*/ +}; + +char *audiobitrate(const unsigned char *data) +{ + int hl = (data[8] > 0) ? 9 + data[8] : 9; + //printf("vdr-radio: audioheader = <%02x %02x %02x %02x>\n", data[hl], data[hl+1], data[hl+2], data[hl+3]); + + char *temp; + if (data[hl] == 0xff && (data[hl+1] & 0xe0) == 0xe0) { // syncword o.k. + int layer = (data[hl+1] & 0x06) >> 1; // Layer description + if (layer > 0) { + switch ((data[hl+1] & 0x18) >> 3) { // Audio Version ID + case 0x00: asprintf(&temp, "V2.5"); + break; + case 0x01: asprintf(&temp, "Vres"); + break; + case 0x02: asprintf(&temp, "V2"); + break; + case 0x03: asprintf(&temp, "%s", bitrates[3-layer][data[hl+2] >> 4]); + break; + } + } + else + asprintf(&temp, "Lres"); + } + else + asprintf(&temp, "???"); + + return temp; +} + +/* ----------------------------------------------------------------------------------------------------------- */ + +const char *tmc_duration[8] = { + "none", + "15 minutes", + "30 minutes", + "1 hour", + "2 hours", + "3 hours", + "4 hours", + "all day", +}; + +const char *tmc_direction[2] = { "+", "-" }; + +const char *tmc_event[2048] = { + "---", // 0 + "traffic problem", + "queuing traffic (with average speeds Q). Danger of stationary traffic", + "..", "..", "..", "..", "..", "..", "..", "..", // 10 + "overheight warning system triggered", + "(Q) accident(s), traffic being directed around accident area", + "..", "..", "..", + "closed, rescue and recovery work in progress", + "..", "..", "..", + "service area overcrowded, drive to another service area", // 20 + "..", + "service area, fuel station closed", + "service area, restaurant closed", + "bridge closed", + "tunnel closed", + "bridge blocked", + "tunnel blocked", + "road closed intermittently", + "..", "..", // 30 + "..", "..", "..", "..", "..", + "fuel station reopened", + "restaurant reopened", + "..", "..", + "smog alert ended", // 40 + "(Q) overtaking lane(s) closed", + "(Q) overtaking lane(s) blocked", + "..", "..", "..", "..", "..", "..", "..", "..", // 50 + "roadworks, (Q) overtaking lane(s) closed", + "(Q sets of) roadworks on the hard shoulder", + "(Q sets of) roadworks in the emergency lane", + "..", + "traffic problem expected", + "traffic congestion expected", + "normal traffic expected", + "..", "..", "..", // 60 + "(Q) object(s) on roadway {something that does not neccessarily block the road}", + "(Q) burst pipe(s)", + "(Q) object(s) on the road. Danger", + "burst pipe. Danger", + "..", "..", "..", "..", "..", + "traffic congestion, average speed of ?? km/h", // 70 + "traffic congestion, average speed of ?? km/h", + "traffic congestion, average speed of ?? km/h", + "traffic congestion, average speed of ?? km/h", + "traffic congestion, average speed of ?? km/h", + "traffic congestion, average speed of ?? km/h", + "traffic congestion, average speed of ?? km/h", + "..", "..", "..", "..", // 80 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 90 + "delays (Q) for cars", + "..", "..", "..", "..", "..", "..", "..", "..", "..", // 100 + "stationary traffic", + "stationary traffic for 1 km", + "stationary traffic for 2 km", + "stationary traffic for 4 km", + "stationary traffic for 6 km", + "stationary traffic for 10 km", + "stationary traffic expected", + "queuing traffic (with average speeds Q)", + "queuing traffic for 1 km (with average speeds Q)", + "queuing traffic for 2 km (with average speeds Q)", // 110 + "queuing traffic for 4 km (with average speeds Q)", + "queuing traffic for 6 km (with average speeds Q)", + "queuing traffic for 10 km (with average speeds Q)", + "queuing traffic expected", + "slow traffic (with average speeds Q)", + "slow traffic for 1 km (with average speeds Q)", + "slow traffic for 2 km (with average speeds Q)", + "slow traffic for 4 km (with average speeds Q)", + "slow traffic for 6 km (with average speeds Q)", + "slow traffic for 10 km (with average speeds Q)", // 120 + "slow traffic expected", + "heavy traffic (with average speeds Q)", + "heavy traffic expected", + "traffic flowing freely (with average speeds Q)", + "traffic building up (with average speeds Q)", + "no problems to report", + "traffic congestion cleared", + "message cancelled", + "stationary traffic for 3 km", + "danger of stationary traffic", // 130 + "queuing traffic for 3 km (with average speeds Q)", + "danger of queuing traffic (with average speeds Q)", + "long queues (with average speeds Q)", + "slow traffic for 3 km (with average speeds Q)", + "traffic easing", + "traffic congestion (with average speeds Q)", + "traffic lighter than normal (with average speeds Q)", + "queuing traffic (with average speeds Q). Approach with care", + "queuing traffic around a bend in the road", + "queuing traffic over the crest of a hill", // 140 + "all accidents cleared, no problems to report", + "traffic heavier than normal (with average speeds Q)", + "traffic very much heavier than normal (with average speeds Q)", + "..", "..", "..", "..", "..", "..", "..", // 150 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 160 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 170 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 180 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 190 + "..", "..", "..", "..", "..", "..", "..", "..", "..", + "multi vehicle pile up. Delays (Q)", // 200 + "(Q) accident(s)", + "(Q) serious accident(s)", + "multi-vehicle accident (involving Q vehicles)", + "accident involving (a/Q) heavy lorr(y/ies)", + "(Q) accident(s) involving hazardous materials", + "(Q) fuel spillage accident(s)", + "(Q) chemical spillage accident(s)", + "vehicles slowing to look at (Q) accident(s)", + "(Q) accident(s) in the opposing lanes", + "(Q) shed load(s)", // 210 + "(Q) broken down vehicle(s)", + "(Q) broken down heavy lorr(y/ies)", + "(Q) vehicle fire(s)", + "(Q) incident(s)", + "(Q) accident(s). Stationary traffic", + "(Q) accident(s). Stationary traffic for 1 km", + "(Q) accident(s). Stationary traffic for 2 km", + "(Q) accident(s). Stationary traffic for 4 km", + "(Q) accident(s). Stationary traffic for 6 km", + "(Q) accident(s). Stationary traffic for 10 km", // 220 + "(Q) accident(s). Danger of stationary traffic", + "(Q) accident(s). Queuing traffic", + "(Q) accident(s). Queuing traffic for 1 km", + "(Q) accident(s). Queuing traffic for 2 km", + "(Q) accident(s). Queuing traffic for 4 km", + "(Q) accident(s). Queuing traffic for 6 km", + "(Q) accident(s). Queuing traffic for 10 km", + "(Q) accident(s). Danger of queuing traffic", + "(Q) accident(s). Slow traffic", + "(Q) accident(s). Slow traffic for 1 km", // 230 + "(Q) accident(s). Slow traffic for 2 km", + "(Q) accident(s). Slow traffic for 4 km", + "(Q) accident(s). Slow traffic for 6 km", + "(Q) accident(s). Slow traffic for 10 km", + "(Q) accident(s). Slow traffic expected", + "(Q) accident(s). Heavy traffic", + "(Q) accident(s). Heavy traffic expected", + "(Q) accident(s). Traffic flowing freely", + "(Q) accident(s). Traffic building up", + "road closed due to (Q) accident(s)", // 240 + "(Q) accident(s). Right lane blocked", + "(Q) accident(s). Centre lane blocked", + "(Q) accident(s). Left lane blocked", + "(Q) accident(s). Hard shoulder blocked", + "(Q) accident(s). Two lanes blocked", + "(Q) accident(s). Three lanes blocked", + "accident. Delays (Q)", + "accident. Delays (Q) expected", + "accident. Long delays (Q)", + "vehicles slowing to look at (Q) accident(s). Stationary traffic", // 250 + "vehicles slowing to look at (Q) accident(s). Stationary traffic for 1 km", + "vehicles slowing to look at (Q) accident(s). Stationary traffic for 2 km", + "vehicles slowing to look at (Q) accident(s). Stationary traffic for 4 km", + "vehicles slowing to look at (Q) accident(s). Stationary traffic for 6 km", + "vehicles slowing to look at (Q) accident(s). Stationary traffic for 10 km", + "vehicles slowing to look at (Q) accident(s). Danger of stationary traffic", + "vehicles slowing to look at (Q) accident(s). Queuing traffic", + "vehicles slowing to look at (Q) accident(s). Queuing traffic for 1 km", + "vehicles slowing to look at (Q) accident(s). Queuing traffic for 2 km", + "vehicles slowing to look at (Q) accident(s). Queuing traffic for 4 km", // 260 + "vehicles slowing to look at (Q) accident(s). Queuing traffic for 6 km", + "vehicles slowing to look at (Q) accident(s). Queuing traffic for 10 km", + "vehicles slowing to look at (Q) accident(s). Danger of queuing traffic", + "vehicles slowing to look at (Q) accident(s). Slow traffic", + "vehicles slowing to look at (Q) accident(s). Slow traffic for 1 km", + "vehicles slowing to look at (Q) accident(s). Slow traffic for 2 km", + "vehicles slowing to look at (Q) accident(s). Slow traffic for 4 km", + "vehicles slowing to look at (Q) accident(s). Slow traffic for 6 km", + "vehicles slowing to look at (Q) accident(s). Slow traffic for 10 km", + "vehicles slowing to look at (Q) accident(s). Slow traffic expected", // 270 + "vehicles slowing to look at (Q) accident(s). Heavy traffic", + "vehicles slowing to look at (Q) accident(s). Heavy traffic expected", + "..", + "vehicles slowing to look at (Q) accident(s). Traffic building up", + "vehicles slowing to look at accident. Delays (Q)", + "vehicles slowing to look at accident. Delays (Q) expected", + "vehicles slowing to look at accident. Long delays (Q)", + "(Q) shed load(s). Stationary traffic", + "(Q) shed load(s). Stationary traffic for 1 km", + "(Q) shed load(s). Stationary traffic for 2 km", // 280 + "(Q) shed load(s). Stationary traffic for 4 km", + "(Q) shed load(s). Stationary traffic for 6 km", + "(Q) shed load(s). Stationary traffic for 10 km", + "(Q) shed load(s). Danger of stationary traffic", + "(Q) shed load(s). Queuing traffic", + "(Q) shed load(s). Queuing traffic for 1 km", + "(Q) shed load(s). Queuing traffic for 2 km", + "(Q) shed load(s). Queuing traffic for 4 km", + "(Q) shed load(s). Queuing traffic for 6 km", + "(Q) shed load(s). Queuing traffic for 10 km", // 290 + "(Q) shed load(s). Danger of queuing traffic", + "(Q) shed load(s). Slow traffic", + "(Q) shed load(s). Slow traffic for 1 km", + "(Q) shed load(s). Slow traffic for 2 km", + "(Q) shed load(s). Slow traffic for 4 km", + "(Q) shed load(s). Slow traffic for 6 km", + "(Q) shed load(s). Slow traffic for 10 km", + "(Q) shed load(s). Slow traffic expected", + "(Q) shed load(s). Heavy traffic", + "(Q) shed load(s). Heavy traffic expected", // 300 + "(Q) shed load(s). Traffic flowing freely", + "(Q) shed load(s). Traffic building up", + "blocked by (Q) shed load(s)", + "(Q) shed load(s). Right lane blocked", + "(Q) shed load(s). Centre lane blocked", + "(Q) shed load(s). Left lane blocked", + "(Q) shed load(s). Hard shoulder blocked", + "(Q) shed load(s). Two lanes blocked", + "(Q) shed load(s). Three lanes blocked", + "shed load. Delays (Q)", // 310 + "shed load. Delays (Q) expected", + "shed load. Long delays (Q)", + "(Q) broken down vehicle(s). Stationary traffic", + "(Q) broken down vehicle(s). Danger of stationary traffic", + "(Q) broken down vehicle(s). Queuing traffic", + "(Q) broken down vehicle(s). Danger of queuing traffic", + "(Q) broken down vehicle(s). Slow traffic", + "(Q) broken down vehicle(s). Slow traffic expected", + "(Q) broken down vehicle(s). Heavy traffic", + "(Q) broken down vehicle(s). Heavy traffic expected", // 320 + "(Q) broken down vehicle(s). Traffic flowing freely", + "(Q) broken down vehicle(s).Traffic building up", + "blocked by (Q) broken down vehicle(s).", + "(Q) broken down vehicle(s). Right lane blocked", + "(Q) broken down vehicle(s). Centre lane blocked", + "(Q) broken down vehicle(s). Left lane blocked", + "(Q) broken down vehicle(s). Hard shoulder blocked", + "(Q) broken down vehicle(s). Two lanes blocked", + "(Q) broken down vehicle(s). Three lanes blocked", + "broken down vehicle. Delays (Q)", // 330 + "broken down vehicle. Delays (Q) expected", + "broken down vehicle. Long delays (Q)", + "accident cleared", + "message cancelled", + "accident involving (a/Q) bus(es)", + "(Q) oil spillage accident(s)", + "(Q) overturned vehicle(s)", + "(Q) overturned heavy lorr(y/ies)", + "(Q) jackknifed trailer(s)", + "(Q) jackknifed caravan(s)", // 340 + "(Q) jackknifed articulated lorr(y/ies)", + "(Q) vehicle(s) spun around", + "(Q) earlier accident(s)", + "accident investigation work", + "(Q) secondary accident(s)", + "(Q) broken down bus(es)", + "(Q) overheight vehicle(s)", + "(Q) accident(s). Stationary traffic for 3 km", + "(Q) accident(s). Queuing traffic for 3 km", + "(Q) accident(s). Slow traffic for 3 km", // 350 + "(Q) accident(s) in roadworks area", + "vehicles slowing to look at (Q) accident(s). Stationary traffic for 3 km", + "vehicles slowing to look at (Q) accident(s). Queuing traffic for 3 km", + "vehicles slowing to look at (Q) accident(s). Slow traffic for 3 km", + "vehicles slowing to look at (Q) accident(s). Danger", + "(Q) shed load(s). Stationary traffic for 3 km", + "(Q) shed load(s). Queuing traffic for 3 km", + "(Q) shed load(s). Slow traffic for 3 km", + "(Q) shed load(s). Danger", + "(Q) overturned vehicle(s). Stationary traffic", // 360 + "(Q) overturned vehicle(s). Danger of stationary traffic", + "(Q) overturned vehicle(s). Queuing traffic", + "(Q) overturned vehicle(s). Danger of queuing traffic", + "(Q) overturned vehicle(s). Slow traffic", + "(Q) overturned vehicle(s). Slow traffic expected", + "(Q) overturned vehicle(s). Heavy traffic", + "(Q) overturned vehicle(s). Heavy traffic expected", + "(Q) overturned vehicle(s). Traffic building up", + "blocked by (Q) overturned vehicle(s)", + "(Q) overturned vehicle(s). Right lane blocked", // 370 + "(Q) overturned vehicle(s). Centre lane blocked", + "(Q) overturned vehicle(s). Left lane blocked", + "(Q) overturned vehicle(s). Two lanes blocked", + "(Q) overturned vehicle(s). Three lanes blocked", + "overturned vehicle. Delays (Q)", + "overturned vehicle. Delays (Q) expected", + "overturned vehicle. Long delays (Q)", + "(Q) overturned vehicle(s). Danger", + "Stationary traffic due to (Q) earlier accident(s)", + "Danger of stationary traffic due to (Q) earlier accident(s)", // 380 + "Queuing traffic due to (Q) earlier accident(s)", + "Danger of queuing traffic due to (Q) earlier accident(s)", + "Slow traffic due to (Q) earlier accident(s)", + "..", + "Heavy traffic due to (Q) earlier accident(s)", + "..", + "Traffic building up due to (Q) earlier accident(s)", + "Delays (Q) due to earlier accident", + "..", + "Long delays (Q) due to earlier accident", // 390 + "accident investigation work. Danger", + "(Q) secondary accident(s). Danger", + "(Q) broken down vehicle(s). Danger", + "(Q) broken down heavy lorr(y/ies). Danger", + "road cleared", + "incident cleared", + "rescue and recovery work in progress", + "..", + "message cancelled", + "..", // 400 + "closed", + "blocked", + "closed for heavy vehicles (over Q)", + "no through traffic for heavy lorries (over Q)", + "no through traffic", + "(Q th) entry slip road closed", + "(Q th) exit slip road closed", + "slip roads closed", + "slip road restrictions", + "closed ahead. Stationary traffic", // 410 + "closed ahead. Stationary traffic for 1 km", + "closed ahead. Stationary traffic for 2 km", + "closed ahead. Stationary traffic for 4 km", + "closed ahead. Stationary traffic for 6 km", + "closed ahead. Stationary traffic for 10 km", + "closed ahead. Danger of stationary traffic", + "closed ahead. Queuing traffic", + "closed ahead. Queuing traffic for 1 km", + "closed ahead. Queuing traffic for 2 km", + "closed ahead. Queuing traffic for 4 km", // 420 + "closed ahead. Queuing traffic for 6 km", + "closed ahead. Queuing traffic for 10 km", + "closed ahead. Danger of queuing traffic", + "closed ahead. Slow traffic", + "closed ahead. Slow traffic for 1 km", + "closed ahead. Slow traffic for 2 km", + "closed ahead. Slow traffic for 4 km", + "closed ahead. Slow traffic for 6 km", + "closed ahead. Slow traffic for 10 km", + "closed ahead. Slow traffic expected", // 430 + "closed ahead. Heavy traffic", + "closed ahead. Heavy traffic expected", + "closed ahead. Traffic flowing freely", + "closed ahead. Traffic building up", + "closed ahead. Delays (Q)", + "closed ahead. Delays (Q) expected", + "closed ahead. Long delays (Q)", + "blocked ahead. Stationary traffic", + "blocked ahead. Stationary traffic for 1 km", + "blocked ahead. Stationary traffic for 2 km", // 440 + "blocked ahead. Stationary traffic for 4 km", + "blocked ahead. Stationary traffic for 6 km", + "blocked ahead. Stationary traffic for 10 km", + "blocked ahead. Danger of stationary traffic", + "blocked ahead. Queuing traffic", + "blocked ahead. Queuing traffic for 1 km", + "blocked ahead. Queuing traffic for 2 km", + "blocked ahead. Queuing traffic for 4 km", + "blocked ahead. Queuing traffic for 6 km", + "blocked ahead. Queuing traffic for 10 km", // 450 + "blocked ahead. Danger of queuing traffic", + "blocked ahead. Slow traffic", + "blocked ahead. Slow traffic for 1 km", + "blocked ahead. Slow traffic for 2 km", + "blocked ahead. Slow traffic for 4 km", + "blocked ahead. Slow traffic for 6 km", + "blocked ahead. Slow traffic for 10 km", + "blocked ahead. Slow traffic expected", + "blocked ahead. Heavy traffic", + "blocked ahead. Heavy traffic expected", // 460 + "blocked ahead. Traffic flowing freely", + "blocked ahead. Traffic building up", + "blocked ahead. Delays (Q)", + "blocked ahead. Delays (Q) expected", + "blocked ahead. Long delays (Q)", + "slip roads reopened", + "reopened", + "message cancelled", + "closed ahead", + "blocked ahead", // 470 + "(Q) entry slip road(s) closed", + "(Q th) entry slip road blocked", + "entry blocked", + "(Q) exit slip road(s) closed", + "(Q th) exit slip road blocked", + "exit blocked", + "slip roads blocked", + "connecting carriageway closed", + "parallel carriageway closed", + "right-hand parallel carriageway closed", // 480 + "left-hand parallel carriageway closed", + "express lanes closed", + "through traffic lanes closed", + "local lanes closed", + "connecting carriageway blocked", + "parallel carriageway blocked", + "right-hand parallel carriageway blocked", + "left-hand parallel carriageway blocked", + "express lanes blocked", + "through traffic lanes blocked", // 490 + "local lanes blocked", + "no motor vehicles", + "restrictions", + "closed for heavy lorries (over Q)", + "closed ahead. Stationary traffic for 3 km", + "closed ahead. Queuing traffic for 3 km", + "closed ahead. Slow traffic for 3 km", + "blocked ahead. Stationary traffic for 3 km", + "blocked ahead. Queuing traffic for 3 km", + "(Q) lane(s) closed", // 500 + "(Q) right lane(s) closed", + "(Q) centre lane(s) closed", + "(Q) left lane(s) closed", + "hard shoulder closed", + "two lanes closed", + "three lanes closed", + "(Q) right lane(s) blocked", + "(Q) centre lane(s) blocked", + "(Q) left lane(s) blocked", + "hard shoulder blocked", // 510 + "two lanes blocked", + "three lanes blocked", + "single alternate line traffic", + "carriageway reduced (from Q lanes) to one lane", + "carriageway reduced (from Q lanes) to two lanes", + "carriageway reduced (from Q lanes) to three lanes", + "contraflow", + "narrow lanes", + "contraflow with narrow lanes", + "(Q) lane(s) blocked", // 520 + "(Q) lanes closed. Stationary traffic", + "(Q) lanes closed. Stationary traffic for 1 km", + "(Q) lanes closed. Stationary traffic for 2 km", + "(Q) lanes closed. Stationary traffic for 4 km", + "(Q) lanes closed. Stationary traffic for 6 km", + "(Q) lanes closed. Stationary traffic for 10 km", + "(Q) lanes closed. Danger of stationary traffic", + "(Q) lanes closed. Queuing traffic", + "(Q) lanes closed. Queuing traffic for 1 km", + "(Q) lanes closed. Queuing traffic for 2 km", // 530 + "(Q) lanes closed. Queuing traffic for 4 km", + "(Q) lanes closed. Queuing traffic for 6 km", + "(Q) lanes closed. Queuing traffic for 10 km", + "(Q) lanes closed. Danger of queuing traffic", + "(Q) lanes closed. Slow traffic", + "(Q) lanes closed. Slow traffic for 1 km", + "(Q) lanes closed. Slow traffic for 2 km", + "(Q) lanes closed. Slow traffic for 4 km", + "(Q) lanes closed. Slow traffic for 6 km", + "(Q) lanes closed. Slow traffic for 10 km", // 540 + "(Q) lanes closed. Slow traffic expected", + "(Q) lanes closed. Heavy traffic", + "(Q) lanes closed. Heavy traffic expected", + "(Q)lanes closed. Traffic flowing freely", + "(Q)lanes closed. Traffic building up", + "carriageway reduced (from Q lanes) to one lane. Stationary traffic", + "carriageway reduced (from Q lanes) to one lane. Danger of stationary traffic", + "carriageway reduced (from Q lanes) to one lane. Queuing traffic", + "carriageway reduced (from Q lanes) to one lane. Danger of queuing traffic", + "carriageway reduced (from Q lanes) to one lane. Slow traffic", // 550 + "carriageway reduced (from Q lanes) to one lane. Slow traffic expected", + "carriageway reduced (from Q lanes) to one lane. Heavy traffic", + "carriageway reduced (from Q lanes) to one lane. Heavy traffic expected", + "carriageway reduced (from Q lanes) to one lane. Traffic flowing freely", + "carriageway reduced (from Q lanes) to one lane. Traffic building up", + "carriageway reduced (from Q lanes) to two lanes. Stationary traffic", + "carriageway reduced (from Q lanes) to two lanes. Danger of stationary traffic", + "carriageway reduced (from Q lanes) to two lanes. Queuing traffic", + "carriageway reduced (from Q lanes) to two lanes. Danger of queuing traffic", + "carriageway reduced (from Q lanes) to two lanes. Slow traffic", // 560 + "carriageway reduced (from Q lanes) to two lanes. Slow traffic expected", + "carriageway reduced (from Q lanes) to two lanes. Heavy traffic", + "carriageway reduced (from Q lanes) to two lanes. Heavy traffic expected", + "carriageway reduced (from Q lanes) to two lanes. Traffic flowing freely", + "carriageway reduced (from Q lanes) to two lanes. Traffic building up", + "carriageway reduced (from Q lanes) to three lanes. Stationary traffic", + "carriageway reduced (from Q lanes) to three lanes. Danger of stationary traffic", + "carriageway reduced (from Q lanes) to three lanes. Queuing traffic", + "carriageway reduced (from Q lanes) to three lanes. Danger of queuing traffic", + "carriageway reduced (from Q lanes) to three lanes. Slow traffic", // 570 + "carriageway reduced (from Q lanes) to three lanes. Slow traffic expected", + "carriageway reduced (from Q lanes) to three lanes. Heavy traffic", + "carriageway reduced (from Q lanes) to three lanes. Heavy traffic expected", + "carriageway reduced (from Q lanes) to three lanes. Traffic flowing freely", + "carriageway reduced (from Q lanes) to three lanes. Traffic building up", + "contraflow. Stationary traffic", + "contraflow. Stationary traffic for 1 km", + "contraflow. Stationary traffic for 2 km", + "contraflow. Stationary traffic for 4 km", + "contraflow. Stationary traffic for 6 km", // 580 + "contraflow. Stationary traffic for 10 km", + "contraflow. Danger of stationary traffic", + "contraflow. Queuing traffic", + "contraflow. Queuing traffic for 1 km", + "contraflow. Queuing traffic for 2 km", + "contraflow. Queuing traffic for 4 km", + "contraflow. Queuing traffic for 6 km", + "contraflow. Queuing traffic for 10 km", + "contraflow. Danger of queuing traffic", + "contraflow. Slow traffic", // 590 + "contraflow. Slow traffic for 1 km", + "contraflow. Slow traffic for 2 km", + "contraflow. Slow traffic for 4 km", + "contraflow. Slow traffic for 6 km", + "contraflow. Slow traffic for 10 km", + "contraflow. Slow traffic expected", + "contraflow. Heavy traffic", + "contraflow. Heavy traffic expected", + "contraflow. Traffic flowing freely", + "contraflow. Traffic building up", // 600 + "contraflow. Carriageway reduced (from Q lanes) to one lane", + "contraflow. Carriageway reduced (from Q lanes) to two lanes", + "contraflow. Carriageway reduced (from Q lanes) to three lanes", + "narrow lanes. Stationary traffic", + "narrow lanes. Danger of stationary traffic", + "narrow lanes. Queuing traffic", + "narrow lanes. Danger of queuing traffic", + "narrow lanes. Slow traffic", + "narrow lanes. Slow traffic expected", + "narrow lanes. Heavy traffic", // 610 + "narrow lanes. Heavy traffic expected", + "narrow lanes. Traffic flowing freely", + "narrow lanes. Traffic building up", + "contraflow with narrow lanes. Stationary traffic", + "contraflow with narrow lanes. Stationary traffic. Danger of stationary traffic", + "contraflow with narrow lanes. Queuing traffic", + "contraflow with narrow lanes. Danger of queuing traffic", + "contraflow with narrow lanes. Slow traffic", + "contraflow with narrow lanes. Slow traffic expected", + "contraflow with narrow lanes. Heavy traffic", // 620 + "contraflow with narrow lanes. Heavy traffic expected", + "contraflow with narrow lanes. Traffic flowing freely", + "contraflow with narrow lanes. Traffic building up", + "lane closures removed", + "message cancelled", + "blocked ahead. Slow traffic for 3 km", + "no motor vehicles without catalytic converters", + "no motor vehicles with even-numbered registration plates", + "no motor vehicles with odd-numbered registration plates", + "open", // 630 + "road cleared", + "entry reopened", + "exit reopened", + "all carriageways reopened", + "motor vehicle restrictions lifted", + "traffic restrictions lifted {reopened for all traffic}", + "emergency lane closed", + "turning lane closed", + "crawler lane closed", + "slow vehicle lane closed", // 640 + "one lane closed", + "emergency lane blocked", + "turning lane blocked", + "crawler lane blocked", + "slow vehicle lane blocked", + "one lane blocked", + "(Q person) carpool lane in operation", + "(Q person) carpool lane closed", + "(Q person) carpool lane blocked", + "carpool restrictions changed (to Q persons per vehicle)", // 650 + "(Q) lanes closed. Stationary traffic for 3 km", + "(Q) lanes closed. Queuing traffic for 3 km", + "(Q) lanes closed. Slow traffic for 3 km", + "contraflow. Stationary traffic for 3 km", + "contraflow. Queuing traffic for 3 km", + "contraflow. Slow traffic for 3 km", + "lane blockages cleared", + "contraflow removed", + "(Q person) carpool restrictions lifted", + "lane restrictions lifted", // 660 + "use of hard shoulder allowed", + "normal lane regulations restored", + "all carriageways cleared", + "..", "..", "..", "..", "..", "..", "..", // 670 + "bus lane available for carpools (with at least Q occupants)", + "message cancelled", + "message cancelled", + "..", "..", + "bus lane blocked", + "..", + "heavy vehicle lane closed", + "heavy vehicle lane blocked", + "reopened for through traffic", // 680 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 690 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 700 + "(Q sets of) roadworks", + "(Q sets of) major roadworks", + "(Q sets of) maintenance work", + "(Q sections of) resurfacing work", + "(Q sets of) central reservation work", + "(Q sets of) road marking work", + "bridge maintenance work (at Q bridges)", + "(Q sets of) temporary traffic lights", + "(Q sections of) blasting work", + "(Q sets of) roadworks. Stationary traffic", // 710 + "(Q sets of) roadworks. Stationary traffic for 1 km", + "(Q sets of) roadworks. Stationary traffic for 2 km", + "(Q sets of) roadworks. Stationary traffic for 4 km", + "(Q sets of) roadworks. Stationary traffic for 6 km", + "(Q sets of) roadworks. Stationary traffic for 10 km", + "(Q sets of) roadworks. Danger of stationary traffic", + "(Q sets of) roadworks. Queuing traffic", + "(Q sets of) roadworks. Queuing traffic for 1 km", + "(Q sets of) roadworks. Queuing traffic for 2 km", + "(Q sets of) roadworks. Queuing traffic for 4 km", // 720 + "(Q sets of) roadworks. Queuing traffic for 6 km", + "(Q sets of) roadworks. Queuing traffic for 10 km", + "(Q sets of) roadworks. Danger of queuing traffic", + "(Q sets of) roadworks. Slow traffic", + "(Q sets of) roadworks. Slow traffic for 1 km", + "(Q sets of) roadworks. Slow traffic for 2 km", + "(Q sets of) roadworks. Slow traffic for 4 km", + "(Q sets of) roadworks. Slow traffic for 6 km", + "(Q sets of) roadworks. Slow traffic for 10 km", + "(Q sets of) roadworks. Slow traffic expected", // 730 + "(Q sets of) roadworks. Heavy traffic", + "(Q sets of) roadworks. Heavy traffic expected", + "(Q sets of) roadworks. Traffic flowing freely", + "(Q sets of) roadworks. Traffic building up", + "closed due to (Q sets of) roadworks", + "(Q sets of) roadworks. Right lane closed", + "(Q sets of) roadworks. Centre lane closed", + "(Q sets of) roadworks. Left lane closed", + "(Q sets of) roadworks. Hard shoulder closed", + "(Q sets of) roadworks. Two lanes closed", // 740 + "(Q sets of) roadworks. Three lanes closed", + "(Q sets of) roadworks. Single alternate line traffic", + "roadworks. Carriageway reduced (from Q lanes) to one lane", + "roadworks. Carriageway reduced (from Q lanes) to two lanes", + "roadworks. Carriageway reduced (from Q lanes) to three lanes", + "(Q sets of) roadworks. Contraflow", + "roadworks. Delays (Q)", + "roadworks. Delays (Q) expected", + "roadworks. Long delays (Q)", + "(Q sections of) resurfacing work. Stationary traffic", // 750 + "(Q sections of) resurfacing work. Stationary traffic for 1 km", + "(Q sections of) resurfacing work. Stationary traffic for 2 km", + "(Q sections of) resurfacing work. Stationary traffic for 4 km", + "(Q sections of) resurfacing work. Stationary traffic for 6 km", + "(Q sections of) resurfacing work. Stationary traffic for 10 km", + "(Q sections of) resurfacing work. Danger of stationary traffic", + "(Q sections of) resurfacing work. Queuing traffic", + "(Q sections of) resurfacing work. Queuing traffic for 1 km", + "(Q sections of) resurfacing work. Queuing traffic for 2 km", + "(Q sections of) resurfacing work. Queuing traffic for 4 km", // 760 + "(Q sections of) resurfacing work. Queuing traffic for 6 km", + "(Q sections of) resurfacing work. Queuing traffic for 10 km", + "(Q sections of) resurfacing work. Danger of queuing traffic", + "(Q sections of) resurfacing work. Slow traffic", + "(Q sections of) resurfacing work. Slow traffic for 1 km", + "(Q sections of) resurfacing work. Slow traffic for 2 km", + "(Q sections of) resurfacing work. Slow traffic for 4 km", + "(Q sections of) resurfacing work. Slow traffic for 6 km", + "(Q sections of) resurfacing work. Slow traffic for 10 km", + "(Q sections of) resurfacing work. Slow traffic expected", // 770 + "(Q sections of) resurfacing work. Heavy traffic", + "(Q sections of) resurfacing work. Heavy traffic expected", + "(Q sections of) resurfacing work. Traffic flowing freely", + "(Q sections of) resurfacing work. Traffic building up", + "(Q sections of) resurfacing work. Single alternate line traffic", + "resurfacing work. Carriageway reduced (from Q lanes) to one lane", + "resurfacing work. Carriageway reduced (from Q lanes) to two lanes", + "resurfacing work. Carriageway reduced (from Q lanes) to three lanes", + "(Q sections of) resurfacing work. Contraflow", + "resurfacing work. Delays (Q)", // 780 + "resurfacing work. Delays (Q) expected", + "resurfacing work. Long delays (Q)", + "(Q sets of) road marking work. Stationary traffic", + "(Q sets of) road marking work. Danger of stationary traffic", + "(Q sets of) road marking work. Queuing traffic", + "(Q sets of) road marking work. Danger of queuing traffic", + "(Q sets of) road marking work. Slow traffic", + "(Q sets of) road marking work. Slow traffic expected", + "(Q sets of) road marking work. Heavy traffic", + "(Q sets of) road marking work. Heavy traffic expected", // 790 + "(Q sets of) road marking work. Traffic flowing freely", + "(Q sets of) road marking work. Traffic building up", + "(Q sets of) road marking work. Right lane closed", + "(Q sets of) road marking work. Centre lane closed", + "(Q sets of) road marking work. Left lane closed", + "(Q sets of) road marking work. Hard shoulder closed", + "(Q sets of) road marking work. Two lanes closed", + "(Q sets of) road marking work. Three lanes closed", + "closed for bridge demolition work (at Q bridges)", + "roadworks cleared", // 800 + "message cancelled", + "(Q sets of) long-term roadworks", + "(Q sets of) construction work", + "(Q sets of) slow moving maintenance vehicles", + "bridge demolition work (at Q bridges)", + "(Q sets of) water main work", + "(Q sets of) gas main work", + "(Q sets of) work on buried cables", + "(Q sets of) work on buried services", + "new roadworks layout", // 810 + "new road layout", + "(Q sets of) roadworks. Stationary traffic for 3 km", + "(Q sets of) roadworks. Queuing traffic for 3 km", + "(Q sets of) roadworks. Slow traffic for 3 km", + "(Q sets of) roadworks during the day time", + "(Q sets of) roadworks during off-peak periods", + "(Q sets of) roadworks during the night", + "(Q sections of) resurfacing work. Stationary traffic for 3 km", + "(Q sections of) resurfacing work. Queuing traffic for 3 km", + "(Q sections of) resurfacing work. Slow traffic for 3 km", // 820 + "(Q sets of) resurfacing work during the day time", + "(Q sets of) resurfacing work during off-peak periods", + "(Q sets of) resurfacing work during the night", + "(Q sets of) road marking work. Danger", + "(Q sets of) slow moving maintenance vehicles. Stationary traffic", + "(Q sets of) slow moving maintenance vehicles. Danger of stationary traffic", + "(Q sets of) slow moving maintenance vehicles. Queuing traffic", + "(Q sets of) slow moving maintenance vehicles. Danger of queuing traffic", + "(Q sets of) slow moving maintenance vehicles. Slow traffic", + "(Q sets of) slow moving maintenance vehicles. Slow traffic expected", // 830 + "(Q sets of) slow moving maintenance vehicles. Heavy traffic", + "(Q sets of) slow moving maintenance vehicles. Heavy traffic expected", + "(Q sets of) slow moving maintenance vehicles. Traffic flowing freely", + "(Q sets of) slow moving maintenance vehicles. Traffic building up", + "(Q sets of) slow moving maintenance vehicles. Right lane closed", + "(Q sets of) slow moving maintenance vehicles. Centre lane closed", + "(Q sets of) slow moving maintenance vehicles. Left lane closed", + "(Q sets of) slow moving maintenance vehicles. Two lanes closed", + "(Q sets of) slow moving maintenance vehicles. Three lanes closed", + "water main work. Delays (Q)", // 840 + "water main work. Delays (Q) expected", + "water main work. Long delays (Q)", + "gas main work. Delays (Q)", + "gas main work. Delays (Q) expected", + "gas main work. Long delays (Q)", + "work on buried cables. Delays (Q)", + "work on buried cables. Delays (Q) expected", + "work on buried cables. Long delays (Q)", + "work on buried services. Delays (Q)", + "work on buried services. Delays (Q) expected", // 850 + "work on buried services. Long delays (Q)", + "construction traffic merging", + "roadwork clearance in progress", + "maintenance work cleared", + "road layout unchanged", + "construction traffic merging. Danger", + "..", "..", "..", "..", // 860 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 870 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 880 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 890 + "..", "..", "..", "..", "..", "..", "..", + "obstruction warning withdrawn", + "clearance work in progress, road free again", + "flooding expected", // 900 + "(Q) obstruction(s) on roadway {something that does block the road or part of", + "(Q) obstructions on the road. Danger", + "spillage on the road", + "storm damage", + "(Q) fallen trees", + "(Q) fallen trees. Danger", + "flooding", + "flooding. Danger", + "flash floods", + "danger of flash floods", // 910 + "avalanches", + "avalanche risk", + "rockfalls", + "landslips", + "earthquake damage", + "road surface in poor condition", + "subsidence", + "(Q) collapsed sewer(s)", + "burst water main", + "gas leak", // 920 + "serious fire", + "animals on roadway", + "animals on the road. Danger", + "clearance work", + "blocked by storm damage", + "blocked by (Q) fallen trees", + "(Q) fallen tree(s). Passable with care", + "flooding. Stationary traffic", + "flooding. Danger of stationary traffic", + "flooding. Queuing traffic", // 930 + "flooding. Danger of queuing traffic", + "flooding. Slow traffic", + "flooding. Slow traffic expected", + "flooding. Heavy traffic", + "flooding. Heavy traffic expected", + "flooding. Traffic flowing freely", + "flooding. Traffic building up", + "closed due to flooding", + "flooding. Delays (Q)", + "flooding. Delays (Q) expected", // 940 + "flooding. Long delays (Q)", + "flooding. Passable with care", + "closed due to avalanches", + "avalanches. Passable with care (above Q hundred metres)", + "closed due to rockfalls", + "rockfalls. Passable with care", + "road closed due to landslips", + "landslips. Passable with care", + "closed due to subsidence", + "subsidence. Single alternate line traffic", // 950 + "subsidence. Carriageway reduced (from Q lanes) to one lane", + "subsidence. Carriageway reduced (from Q lanes) to two lanes", + "subsidence. Carriageway reduced (from Q lanes) to three lanes", + "subsidence. Contraflow in operation", + "subsidence. Passable with care", + "closed due to sewer collapse", + "road closed due to burst water main", + "burst water main. Delays (Q)", + "burst water main. Delays (Q) expected", + "burst water main. Long delays (Q)", // 960 + "closed due to gas leak", + "gas leak. Delays (Q)", + "gas leak. Delays (Q) expected", + "gas leak. Long delays (Q)", + "closed due to serious fire", + "serious fire. Delays (Q)", + "serious fire. Delays (Q) expected", + "serious fire. Long delays (Q)", + "closed for clearance work", + "road free again", // 970 + "message cancelled", + "storm damage expected", + "fallen power cables", + "sewer overflow", + "ice build-up", + "mud slide", + "grass fire", + "air crash", + "rail crash", + "blocked by (Q) obstruction(s) on the road", // 980 + "(Q) obstructions on the road. Passable with care", + "blocked due to spillage on roadway", + "spillage on the road. Passable with care", + "spillage on the road. Danger", + "storm damage. Passable with care", + "storm damage. Danger", + "blocked by fallen power cables", + "fallen power cables. Passable with care", + "fallen power cables. Danger", + "sewer overflow. Danger", // 990 + "flash floods. Danger", + "avalanches. Danger", + "closed due to avalanche risk", + "avalanche risk. Danger", + "closed due to ice build-up", + "ice build-up. Passable with care (above Q hundred metres)", + "ice build-up. Single alternate traffic", + "rockfalls. Danger", + "landslips. Danger", + "earthquake damage. Danger", // 1000 + "hazardous driving conditions (above Q hundred metres)", + "danger of aquaplaning", + "slippery road (above Q hundred metres)", + "mud on road", + "leaves on road", + "ice (above Q hundred metres)", + "danger of ice (above Q hundred metres)", + "black ice (above Q hundred metres)", + "freezing rain (above Q hundred metres)", + "wet and icy roads (above Q hundred metres)", // 1010 + "slush (above Q hundred metres)", + "snow on the road (above Q hundred metres)", + "packed snow (above Q hundred metres)", + "fresh snow (above Q hundred metres)", + "deep snow (above Q hundred metres)", + "snow drifts (above Q hundred metres)", + "slippery due to spillage on roadway", + "slippery road (above Q hundred metres) due to snow", + "slippery road (above Q hundred metres) due to frost", + "road blocked by snow (above Q hundred metres)", // 1020 + "snow on the road. Carriageway reduced (from Q lanes) to one lane", + "snow on the road. Carriageway reduced (from Q lanes) to two lanes", + "snow on the road. Carriageway reduced (from Q lanes) to three lanes", + "conditions of road surface improved", + "message cancelled", + "subsidence. Danger", + "sewer collapse. Delays (Q)", + "sewer collapse. Delays (Q) expected", + "sewer collapse. Long delays (Q)", + "sewer collapse. Danger", // 1030 + "burst water main. Danger", + "gas leak. Danger", + "serious fire. Danger", + "clearance work. Danger", + "impassable (above Q hundred metres)", + "almost impassable (above Q hundred metres)", + "extremely hazardous driving conditions (above Q hundred metres)", + "difficult driving conditions (above Q hundred metres)", + "passable with care (up to Q hundred metres)", + "passable (up to Q hundred metres)", // 1040 + "surface water hazard", + "loose sand on road", + "loose chippings", + "oil on road", + "petrol on road", + "icy patches (above Q hundred metres)", + "danger of icy patches (above Q hundred metres)", + "danger of black ice (above Q hundred metres)", + "..", "..", // 1050 + "..", "..", "..", + "slippery due to loose sand on roadway", + "mud on road. Danger", + "loose chippings. Danger", + "oil on road. Danger", + "petrol on road. Danger", + "road surface in poor condition. Danger", + "icy patches (above Q hundred metres) on bridges", // 1060 + "danger of icy patches (above Q hundred metres) on bridges", + "icy patches (above Q hundred metres) on bridges, in shaded areas and on s", + "impassable for heavy vehicles (over Q)", + "impassable (above Q hundred metres) for vehicles with trailers", + "driving conditions improved", + "rescue and recovery work in progress. Danger", + "large animals on roadway", + "herds of animals on roadway", + "skid hazard reduced", + "snow cleared", // 1070 + "..", "..", + "extremely hazardous driving conditions expected (above Q hundred meters", + "freezing rain expected (above Q hundred metres)", + "danger of road being blocked by snow (above Q hundred metres)", + "..", "..", "..", + "temperature falling rapidly (to Q)", + "extreme heat (up to Q)", // 1080 + "extreme cold (of Q)", + "less extreme temperatures", + "current temperature (Q)", + "..", "..", "..", "..", "..", "..", "..", // 1090 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1100 + "heavy snowfall (Q)", + "heavy snowfall (Q). Visibility reduced to < ?? m", + "heavy snowfall (Q). Visibility reduced to < ?? m", + "snowfall (Q)", + "snowfall (Q). Visibility reduced to < ?? m", + "hail (visibility reduced to Q)", + "sleet (visibility reduced to Q)", + "thunderstorms (visibility reduced to Q)", + "heavy rain (Q)", + "heavy rain (Q). Visibility reduced to < ?? m", // 1110 + "heavy rain (Q). Visibility reduced to < ?? m", + "rain (Q)", + "rain (Q). Visibility reduced to < ?? m", + "showers (visibility reduced to Q)", + "heavy frost", + "frost", + "..", "..", "..", "..", // 1120 + "..", "..", "..", "..", "..", + "weather situation improved", + "message cancelled", + "winter storm (visibility reduced to Q)", + "..", + "blizzard (visibility reduced to Q)", // 1130 + "..", + "damaging hail (visibility reduced to Q)", + "..", + "heavy snowfall. Visibility reduced (to Q)", + "snowfall. Visibility reduced (to Q)", + "heavy rain. Visibility reduced (to Q)", + "rain. Visibility reduced (to Q)", + "..", "..", "..", // 1140 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1150 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1160 + "..", "..", "..", "..", "..", "..", "..", "..", "..", + "heavy snowfall (Q) expected", // 1170 + "heavy rain (Q) expected", + "weather expected to improve", + "blizzard (with visibility reduced to Q) expected", + "damaging hail (with visibility reduced to Q) expected", + "reduced visibility (to Q) expected", + "freezing fog expected (with visibility reduced to Q). Danger of slippery roads", + "dense fog (with visibility reduced to Q) expected", + "patchy fog (with visibility reduced to Q) expected", + "visibility expected to improve", + "adverse weather warning withdrawn", // 1180 + "..", "..", "..", "..", "..", "..", "..", "..", "..", + "severe smog", // 1190 + "severe exhaust pollution", + "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1200 + "tornadoes", + "hurricane force winds (Q)", + "gales (Q)", + "storm force winds (Q)", + "strong winds (Q)", + "..", "..", "..", + "gusty winds (Q)", + "crosswinds (Q)", // 1210 + "strong winds (Q) affecting high-sided vehicles", + "closed for high-sided vehicles due to strong winds (Q)", + "strong winds easing", + "message cancelled", + "restrictions for high-sided vehicles lifted", + "..", + "tornado warning ended", + "..", "..", "..", // 1220 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1230 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1240 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1250 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1260 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1270 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1280 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1290 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1300 + "dense fog (visibility reduced to Q)", + "dense fog. Visibility reduced to < ?? m", + "dense fog. Visibility reduced to < ?? m", + "fog (visibility reduced to Q)", + "fog. Visibility reduced to < ?? m", + "..", + "patchy fog (visibility reduced to Q)", + "freezing fog (visibility reduced to Q)", + "smoke hazard (visibility reduced to Q)", + "blowing dust (visibility reduced to Q)", // 1310 + "..", + "snowfall and fog (visibility reduced to Q)", + "visibility improved", + "message cancelled", + "..", "..", "..", + "visibility reduced (to Q)", + "visibility reduced to < ?? m", + "visibility reduced to < ?? m", // 1320 + "visibility reduced to < ?? m", + "white out (visibility reduced to Q)", + "blowing snow (visibility reduced to Q)", + "spray hazard (visibility reduced to Q)", + "low sun glare", + "sandstorms (visibility reduced to Q)", + "..", "..", "..", "..", // 1330 + "..", + "smog alert", + "..", "..", "..", "..", + "freezing fog (visibility reduced to Q). Slippery roads", + "no motor vehicles due to smog alert", + "..", + "swarms of insects (visibility reduced to Q)", // 1340 + "..", "..", "..", "..", + "fog clearing", + "fog forecast withdrawn", + "..", "..", "..", "..", // 1350 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1360 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1370 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1380 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1390 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1400 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1410 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1420 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1430 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1440 + "..", "..", "..", "..", "..", "..", "..", "..", "..", + "international sports meeting", // 1450 + "match", + "tournament", + "athletics meeting", + "ball game", + "boxing tournament", + "bull fight", + "cricket match", + "cycle race", + "football match", + "golf tournament", // 1460 + "marathon", + "race meeting", + "rugby match", + "show jumping", + "tennis tournament", + "water sports meeting", + "winter sports meeting", + "funfair", + "trade fair", + "procession", // 1470 + "sightseers obstructing access", + "people on roadway", + "children on roadway", + "cyclists on roadway", + "strike", + "security incident", + "police checkpoint", + "terrorist incident", + "gunfire on roadway, danger", + "civil emergency", // 1480 + "air raid, danger", + "people on roadway. Danger", + "children on roadway. Danger", + "cyclists on roadway. Danger", + "closed due to security incident", + "security incident. Delays (Q)", + "security incident. Delays (Q) expected", + "security incident. Long delays (Q)", + "police checkpoint. Delays (Q)", + "police checkpoint. Delays (Q) expected", // 1490 + "police checkpoint. Long delays (Q)", + "security alert withdrawn", + "sports traffic cleared", + "evacuation", + "evacuation. Heavy traffic", + "traffic disruption cleared", + "..", "..", "..", "..", // 1500 + "major event", + "sports event meeting", + "show", + "festival", + "exhibition", + "fair", + "market", + "ceremonial event", + "state occasion", + "parade", // 1510 + "crowd", + "march", + "demonstration", + "public disturbance", + "security alert", + "bomb alert", + "major event. Stationary traffic", + "major event. Danger of stationary traffic", + "major event. Queuing traffic", + "major event. Danger of queuing traffic", // 1520 + "major event. Slow traffic", + "major event. Slow traffic expected", + "major event. Heavy traffic", + "major event. Heavy traffic expected", + "major event. Traffic flowing freely", + "major event. Traffic building up", + "closed due to major event", + "major event. Delays (Q)", + "major event. Delays (Q) expected", + "major event. Long delays (Q)", // 1530 + "sports meeting. Stationary traffic", + "sports meeting. Danger of stationary traffic", + "sports meeting. Queuing traffic", + "sports meeting. Danger of queuing traffic", + "sports meeting. Slow traffic", + "sports meeting. Slow traffic expected", + "sports meeting. Heavy traffic", + "sports meeting. Heavy traffic expected", + "sports meeting. Traffic flowing freely", + "sports meeting. Traffic building up", // 1540 + "closed due to sports meeting", + "sports meeting. Delays (Q)", + "sports meeting. Delays (Q) expected", + "sports meeting. Long delays (Q)", + "fair. Stationary traffic", + "fair. Danger of stationary traffic", + "fair. Queuing traffic", + "fair. Danger of queuing traffic", + "fair. Slow traffic", + "fair. Slow traffic expected", // 1550 + "fair. Heavy traffic", + "fair. Heavy traffic expected", + "fair. Traffic flowing freely", + "fair. Traffic building up", + "closed due to fair", + "fair. Delays (Q)", + "fair. Delays (Q) expected", + "fair. Long delays (Q)", + "closed due to parade", + "parade. Delays (Q)", // 1560 + "parade. Delays (Q) expected", + "parade. Long delays (Q)", + "closed due to strike", + "strike. Delays (Q)", + "strike. Delays (Q) expected", + "strike. Long delays (Q)", + "closed due to demonstration", + "demonstration. Delays (Q)", + "demonstration. Delays (Q) expected", + "demonstration. Long delays (Q)", // 1570 + "security alert. Stationary traffic", + "security alert. Danger of stationary traffic", + "security alert. Queuing traffic", + "security alert. Danger of queuing traffic", + "security alert. Slow traffic", + "security alert. Slow traffic expected", + "security alert. Heavy traffic", + "security alert. Heavy traffic expected", + "security alert. Traffic building up", + "closed due to security alert", // 1580 + "security alert. Delays (Q)", + "security alert. Delays (Q) expected", + "security alert. Long delays (Q)", + "traffic has returned to normal", + "message cancelled", + "security alert. Traffic flowing freely", + "air raid warning cancelled", + "civil emergency cancelled", + "message cancelled", + "several major events", // 1590 + "information about major event no longer valid", + "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1600 + "delays (Q)", + "delays up to ?? minutes", + "delays up to ?? minutes", + "delays up to one hour", + "delays up to two hours", + "delays of several hours", + "delays (Q) expected", + "long delays (Q)", + "delays (Q) for heavy vehicles", + "delays up to ?? minutes for heavy lorr(y/ies)", // 1610 + "delays up to ?? minutes for heavy lorr(y/ies)", + "delays up to one hour for heavy lorr(y/ies)", + "delays up to two hours for heavy lorr(y/ies)", + "delays of several hours for heavy lorr(y/ies)", + "service suspended (until Q)", + "(Q) service withdrawn", + "(Q) service(s) fully booked", + "(Q) service(s) fully booked for heavy vehicles", + "normal services resumed", + "message cancelled", // 1620 + "delays up to ?? minutes", + "delays up to ?? minutes", + "delays up to ?? minutes", + "delays up to ?? minutes", + "delays up to ?? minutes", + "delays up to ?? minutes", + "delays up to ?? minutes", + "delays up to three hours", + "delays up to four hours", + "delays up to five hours", // 1630 + "very long delays (Q)", + "delays of uncertain duration", + "delayed until further notice", + "cancellations", + "park and ride service not operating (until Q)", + "special public transport services operating (until Q)", + "normal services not operating (until Q)", + "rail services not operating (until Q)", + "bus services not operating (until Q)", + "shuttle service operating (until Q)", // 1640 + "free shuttle service operating (until Q)", + "delays (Q) for heavy lorr(y/ies)", + "delays (Q) for buses", + "(Q) service(s) fully booked for heavy lorr(y/ies)", + "(Q) service(s) fully booked for buses", + "next departure (Q) for heavy lorr(y/ies)", + "next departure (Q) for buses", + "delays cleared", + "rapid transit service not operating (until Q)", + "delays (Q) possible", // 1650 + "underground service not operating (until Q)", + "cancellations expected", + "long delays expected", + "very long delays expected", + "all services fully booked (until Q)", + "next arrival (Q)", + "rail services irregular. Delays (Q)", + "bus services irregular. Delays (Q)", + "underground services irregular", + "normal public transport services resumed", // 1660 + "ferry service not operating (until Q)", + "park and ride trip time (Q)", + "delay expected to be cleared", + "..", "..", "..", "..", "..", "..", "..", // 1670 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1680 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1690 + "..", "..", "..", "..", + "current trip time (Q)", + "expected trip time (Q)", + "..", "..", "..", + "(Q) slow moving maintenance vehicle(s)", // 1700 + "(Q) vehicle(s) on wrong carriageway", + "dangerous vehicle warning cleared", + "message cancelled", + "(Q) reckless driver(s)", + "(Q) prohibited vehicle(s) on the roadway", + "(Q) emergency vehicles", + "(Q) high-speed emergency vehicles", + "high-speed chase (involving Q vehicles)", + "spillage occurring from moving vehicle", + "objects falling from moving vehicle", // 1710 + "emergency vehicle warning cleared", + "road cleared", + "..", "..", "..", "..", "..", "..", "..", + "rail services irregular", // 1720 + "public transport services not operating", + "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1730 + "(Q) abnormal load(s), danger", + "(Q) wide load(s), danger", + "(Q) long load(s), danger", + "(Q) slow vehicle(s), danger", + "(Q) track-laying vehicle(s), danger", + "(Q) vehicle(s) carrying hazardous materials. Danger", + "(Q) convoy(s), danger", + "(Q) military convoy(s), danger", + "(Q) overheight load(s), danger", + "abnormal load causing slow traffic. Delays (Q)", // 1740 + "convoy causing slow traffic. Delays (Q)", + "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1750 + "(Q) abnormal load(s)", + "(Q) wide load(s)", + "(Q) long load(s)", + "(Q) slow vehicle(s)", + "(Q) convoy(s)", + "abnormal load. Delays (Q)", + "abnormal load. Delays (Q) expected", + "abnormal load. Long delays (Q)", + "convoy causing delays (Q)", + "convoy. Delays (Q) expected", // 1760 + "convoy causing long delays (Q)", + "exceptional load warning cleared", + "message cancelled", + "(Q) track-laying vehicle(s)", + "(Q) vehicle(s) carrying hazardous materials", + "(Q) military convoy(s)", + "(Q) abnormal load(s). No overtaking", + "Vehicles carrying hazardous materials have to stop at next safe place!", + "hazardous load warning cleared", + "convoy cleared", // 1770 + "warning cleared", + "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1780 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1790 + "..", "..", "..", "..", "..", "..", "..", "..", "..", "..", // 1800 + "lane control signs not working", + "emergency telephones not working", + "emergency telephone number not working", + "(Q sets of) traffic lights not working", + "(Q sets of) traffic lights working incorrectly", + "level crossing failure", + "(Q sets of) traffic lights not working. Stationary traffic", + "(Q sets of) traffic lights not working. Danger of stationary traffic", + "(Q sets of) traffic lights not working. Queuing traffic", + "(Q sets of) traffic lights not working. Danger of queuing traffic", // 1810 + "(Q sets of) traffic lights not working. Slow traffic", + "(Q sets of) traffic lights not working. Slow traffic expected", + "(Q sets of) traffic lights not working. Heavy traffic", + "(Q sets of) traffic lights not working. Heavy traffic expected", + "(Q sets of) traffic lights not working. Traffic flowing freely", + "(Q sets of) traffic lights not working. Traffic building up", + "traffic lights not working. Delays (Q)", + "traffic lights not working. Delays (Q) expected", + "traffic lights not working. Long delays (Q)", + "level crossing failure. Stationary traffic", // 1820 + "level crossing failure. Danger of stationary traffic", + "level crossing failure. Queuing traffic", + "level crossing failure. Danger of queuing traffic", + "level crossing failure. Slow traffic", + "level crossing failure. Slow traffic expected", + "level crossing failure. Heavy traffic", + "level crossing failure. Heavy traffic expected", + "level crossing failure. Traffic flowing freely", + "level crossing failure. Traffic building up", + "level crossing failure. Delays (Q)", // 1830 + "level crossing failure. Delays (Q) expected", + "level crossing failure. Long delays (Q)", + "electronic signs repaired", + "emergency call facilities restored", + "traffic signals repaired", + "level crossing now working normally", + "message cancelled", + "lane control signs working incorrectly", + "lane control signs operating", + "variable message signs not working", // 1840 + "variable message signs working incorrectly", + "variable message signs operating", + "(Q sets of) ramp control signals not working", + "(Q sets of) ramp control signals working incorrectly", + "(Q sets of) temporary traffic lights not working", + "(Q sets of) temporary traffic lights working incorrectly", + "traffic signal control computer not working", + "traffic signal timings changed", + "tunnel ventilation not working", + "lane control signs not working. Danger", // 1850 + "temporary width limit (Q)", + "temporary width limit lifted", + "..", + "traffic regulations have been changed", + "less than parking spaces available", + "no parking information available (until Q)", + "message cancelled", + "..", "..", "..", // 1860 + "temporary height limit (Q)", + "temporary height limit lifted", + "..", + "lane control signs working incorrectly. Danger", + "emergency telephones out of order. Extra police patrols in operation", + "emergency telephones out of order. In emergency, wait for police patrol", + "(Q sets of) traffic lights not working. Danger", + "traffic lights working incorrectly. Delays (Q)", + "traffic lights working incorrectly. Delays (Q) expected", + "traffic lights working incorrectly. Long delays (Q)", // 1870 + "temporary axle load limit (Q)", + "temporary gross weight limit (Q)", + "temporary gross weight limit lifted", + "temporary axle weight limit lifted", + "(Q sets of) traffic lights working incorrectly. Danger", + "temporary traffic lights not working. Delays (Q)", + "temporary traffic lights not working. Delays (Q) expected", + "temporary traffic lights not working. Long delays (Q)", + "(Q sets of) temporary traffic lights not working. Danger", + "traffic signal control computer not working. Delays (Q)", // 1880 + "temporary length limit (Q)", + "temporary length limit lifted", + "message cancelled", + "traffic signal control computer not working. Delays (Q) expected", + "traffic signal control computer not working. Long delays (Q)", + "normal parking restrictions lifted", + "special parking restrictions in force", + "10% full", + "20% full", + "30% full", // 1890 + "40% full", + "50% full", + "60% full", + "70% full", + "80% full", + "90% full", + "less than ?? parking spaces available", + "less than ?? parking spaces available", + "less than ?? parking spaces available", + "less than ?? parking spaces available", // 1900 + "next departure (Q)", + "next departure (Q) for heavy vehicles", + "car park (Q) full", + "all car parks (Q) full", + "less than (Q) car parking spaces available", + "park and ride service operating (until Q)", + "(null event)", + "switch your car radio (to Q)", + "alarm call: important new information on this frequency follows now in normal", + "alarm set: new information will be broadcast between these times in normal", // 1910 + "message cancelled", + "..", + "switch your car radio (to Q)", + "no information available (until Q)", + "this message is for test purposes only (number Q), please ignore", + "no information available (until Q) due to technical problems", + "..", + "full", + "..", + "only a few parking spaces available", // 1920 + "(Q) parking spaces available", + "expect car park to be full", + "expect no parking spaces available", + "multi story car parks full", + "no problems to report with park and ride services", + "no parking spaces available", + "no parking (until Q)", + "special parking restrictions lifted", + "urgent information will be given (at Q) on normal programme broadcasts", + "this TMC-service is not active (until Q)", // 1930 + "detailed information will be given (at Q) on normal programme broadcasts", + "detailed information is provided by another TMC service", + "..", + "no park and ride information available (until Q)", + "..", "..", "..", + "park and ride information service resumed", + "..", + "additional regional information is provided by another TMC service", // 1940 + "additional local information is provided by another TMC service", + "additional public transport information is provided by another TMC service", + "national traffic information is provided by another TMC service", + "this service provides major road information", + "this service provides regional travel information", + "this service provides local travel information", + "no detailed regional information provided by this service", + "no detailed local information provided by this service", + "no cross-border information provided by this service", + "information restricted to this area", // 1950 + "no new traffic information available (until Q)", + "no public transport information available", + "this TMC-service is being suspended (at Q)", + "active TMC-service will resume (at Q)", + "reference to audio programmes no longer valid", + "reference to other TMC services no longer valid", + "previous announcement about this or other TMC services no longer valid", + "..", "..", "..", // 1960 + "allow emergency vehicles to pass in the carpool lane", + "carpool lane available for all vehicles", + "police directing traffic via the carpool lane", + "..", "..", "..", "..", "..", "..", "..", // 1970 + "police directing traffic", + "buslane available for all vehicles", + "police directing traffic via the buslane", + "allow emergency vehicles to pass", + "..", "..", + "allow emergency vehicles to pass in the heavy vehicle lane", + "heavy vehicle lane available for all vehicles", + "police directing traffic via the heavy vehicle lane", + "..", // 1980 + "..", + "buslane closed", + "..", "..", "..", "..", "..", "..", "..", "..", // 1990 + "..", "..", "..", "..", "..", "..", "..", "..", "..", + "closed due to smog alert (until Q)", // 2000 + "..", "..", "..", "..", "..", + "closed for vehicles with less than three occupants {not valid for lorries}", + "closed for vehicles with only one occupant {not valid for lorries}", + "..", "..", "..", // 2010 + "..", "..", + "service area busy", + "..", "..", "..", "..", "..", "..", "..", // 2020 + "service not operating, substitute service available", + "public transport strike", + "..", "..", "..", "..", "..", + "message cancelled", + "message cancelled", + "message cancelled", // 2030 + "..", "..", + "message cancelled", + "message cancelled", + "message cancelled", + "..", "..", + "message cancelled", + "message cancelled", + "message cancelled", // 2040 + "..", "..", "..", "..", "..", "..", + "(null message)", // last = 2047 +}; + +const char *tmc_mglabel[16] = { + "Duration", + "Control code", + "Length", + "Speed limit", + "Quantifier", + "Quantifier", + "Info code", + "Start time", + "Stop time", + "Event", + "Diversion", + "Location", + "unknown", + "Location", + "NOP", + "unknown", +}; +int tmc_mgsize[16] = { 3, 3, 5, 5, 5, 8, 8, 8, 8, 11, 16, 16, 16, 16, 0, 0 }; + +// TMC, Alert-C Coding +void tmc_parser(unsigned char *data, int len) +{ + static char lastdata[6]; + + if (len < 6) { + printf("TMC Length only '%d' bytes (<6).\n", len); + return; + } + + if (memcmp(data, lastdata, 6) == 0) { + printf("TMC Repeating.\n"); + return; + } + memcpy(lastdata, data, 6); + + // Buffer = data[0], todo or not :D + + // check Encrypted-Service, TMC Pro ? + if ((data[1] & 0x1f) == 0x00) { // Type+DP = '00000' + printf("TMC Encrypted Service detected, TMC-Pro?\n"); + return; + } + + int type = (data[1] & 0x18)>>3; // Type = User-,TuningInformation & Multi-,Singlegroup Message + int dp = data[1] & 0x07; // Duration+Persistance or Continuity Index + int da = (data[2] & 0x80)>>7; // DiversionAdvice or GroupIndicator + int di = (data[2] & 0x40)>>6; // Direction (-/+) or 2.GroupIndicator + int ex = (data[2] & 0x38)>>3; // Extent + int ev = (data[2] & 0x07)<<8 | data[3]; // Event + int lo = data[4]<<8 | data[5]; // Location + + switch (type) { + case 0: // Multigroup-Message + printf("TMC Multi-Group Message, "); + if (da == 1) { + printf("First:\n"); + printf(" CI: '%d', Direction: %s, Extent: '%d'\n", dp, tmc_direction[di], ex); + printf(" Event: '%d' = %s\n", ev, tmc_event[ev]); + printf(" Location: '%d' > LT not available yet :-(\n", lo); + } + else { + int gsi = (data[2] & 0x30)>>4; // GroupSequenceIdentifier + printf("Subsequent:\n"); + printf(" CI: '%d', 2.GI: '%d', GSI: '%d', Block_0x: '%02x%02x%02x%02x'\n", dp, di, gsi, data[2]&0xf, data[3], data[4], data[5]); + if (di == 0) { + printf(" SecondGroupIndicator = 0 -> todo, exit here.\n\n"); + return; + } + unsigned int block = (data[2]&0x0f)<<24 | data[3]<<16 | data[4]<<8 | data[5]; + int lc = 1; + int rbits = 28; + while (rbits > 0) { + int lb = block>>(rbits-4); + rbits -= 4; + if (lb <= 0) + return; + block = block & ((unsigned long int)(pow(2,rbits)) - 1); + rbits -= tmc_mgsize[lb]; + int val = block>>(rbits); + printf(" #%d: Label '%02d' = %s", lc, lb, tmc_mglabel[lb]); + if (val > 0) { + switch (lb) { + case 0: printf(", Value '%d' min.?\n", val); + break; + case 2: printf(", Value '%d' km?\n", val); + break; + case 3: printf(", Value '%d' km/h?\n", val); + break; + case 9: printf(", Value '%d' = %s\n", val, tmc_event[val]); + break; + case 11: + case 13: printf(", Value '%d' > LT not available yet :-(\n", val); + break; + case 14: + case 15: printf(" ---\n"); + break; + default: printf(", Value '%d'\n", val); + } + } + else { + if (block > 0) + printf(", rest block_0x '%04x'\n", (int)block); + else + printf(", ...\n"); + } + block = block & ((unsigned int)(pow(2,rbits)) - 1); + lc++; + } + } + break; + case 1: // Singlegroup-Message + printf("TMC Single-Group Message:\n"); + printf(" Duration: %s, Diversion: '%d', Direction: %s, Extent: '%d'\n", tmc_duration[dp], da, tmc_direction[di], ex); + printf(" Event: '%d' = %s\n", ev, tmc_event[ev]); + printf(" Location: '%d' > LT not available yet :-(\n", lo); + break; + case 2: + case 3: // System,Tuning + printf("TMC Tuning/System Information:\n"); + switch (data[1] & 0x0f) { + case 9: printf(" LTN: '%d', MGS: '%d', SID: '%d' %04x.\n", data[2]>>2, (data[2] & 0x03)<<2 | data[3]>>6, data[3] & 0x3f, lo); + break; + default: printf(" todo, exit.\n"); + } + } + +} + + +//--------------- End ----------------------------------------------------------------- diff --git a/radiotools.h b/radiotools.h new file mode 100644 index 0000000..b948202 --- /dev/null +++ b/radiotools.h @@ -0,0 +1,29 @@ +/* + * radiotools.h - part of radio.c, a plugin for the Video Disk Recorder + * + * See the README file for copyright information and how to reach the author. + * + */ + +#ifndef __RADIO_TOOLS_H +#define __RADIO_TOOLS_H + + +bool file_exists(const char *filename); + +bool enforce_directory(const char *path); + +unsigned short crc16_ccitt(unsigned char *daten, int len, bool skipfirst); + +char *rds_entitychar(char *text); + +char *xhtml2text(char *text); + +char *rtrim(char *text); + +char *audiobitrate(const unsigned char *data); + +void tmc_parser(unsigned char *data, int len); // Alert-c + + +#endif //__RADIO_TOOLS_H diff --git a/symbols/RTplus_80x80.png b/symbols/RTplus_80x80.png Binary files differnew file mode 100644 index 0000000..e6efc60 --- /dev/null +++ b/symbols/RTplus_80x80.png diff --git a/symbols/arec.xpm b/symbols/arec.xpm new file mode 100644 index 0000000..1c68f7f --- /dev/null +++ b/symbols/arec.xpm @@ -0,0 +1,26 @@ +/* XPM */ +static const char * arec_xpm[] = { +"52 21 2 1", +". c #000000", +"+ c #FFFFFF", +"....................................................", +"....................................................", +"..++++++++++++++++++++++++++++++++++++++++++++++++..", +"..++++++++++++++++++++++++++++++++++++++++++++++++..", +"..+++......+++++.......+++++++++++++++++++++++++++..", +"..++..++++..++++..++++..++++++++++++++++++++++++++..", +"..++..++++..++++..++++..++++++++++++++++++++++++++..", +"..++..++++..++++..++++..++++++++++++++++++++++++++..", +"..++..++++..++++..++++..+++++......++++++......+++..", +"..++..++++..++++..++++..++++..++++..++++..++++..++..", +"..++........++++.......+++++..++++..++++..++++++++..", +"..++..++++..++++....++++++++..++++..++++..++++++++..", +"..++..++++..++++..+..+++++++........++++..++++++++..", +"..++..++++..++++..++..++++++..++++++++++..++++++++..", +"..++..++++..++++..+++..+++++..++++++++++..++++++++..", +"..++..++++..++++..++++..++++..++++..++++..++++..++..", +"..++..++++..++++..++++..+++++......++++++......+++..", +"..++++++++++++++++++++++++++++++++++++++++++++++++..", +"..++++++++++++++++++++++++++++++++++++++++++++++++..", +"....................................................", +"...................................................."}; diff --git a/symbols/bok.xpm b/symbols/bok.xpm new file mode 100644 index 0000000..d3d1298 --- /dev/null +++ b/symbols/bok.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *bok_xpm[]={ +"23 20 2 1", +"# c #000000", +". c #ffffff", +".#####################.", +"#######################", +"##...................##", +"##...................##", +"##....###...##....#..##", +"##...#####..##...##..##", +"##..##...##.##...##..##", +"##..##...##.##..##...##", +"##..##...##.##.##....##", +"##..##...##.####.....##", +"##..##...##.####.....##", +"##..##...##.##.##....##", +"##..##...##.##..##...##", +"##..##...##.##...##..##", +"##...#####..##...##..##", +"##....###...##....#..##", +"##...................##", +"##...................##", +"#######################", +".#####################."}; diff --git a/symbols/index.xpm b/symbols/index.xpm new file mode 100644 index 0000000..86e23c7 --- /dev/null +++ b/symbols/index.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * index_xpm[] = { +"52 20 2 1", +". c #000000", +"+ c #FFFFFF", +"++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++....+++++++++++++++++++..+++++++++++++++++++++++", +"+++++..++++++++++++++++++++..+++++++++++++++++++++++", +"+++++..++++++++++++++++++++..+++++++++++++++++++++++", +"+++++..++++++++++++++++++++..+++++++++++++++++++++++", +"+++++..++++.......++++.......+++......+++..++++..+++", +"+++++..++++..++++..++..++++..++..++++..++..++++..+++", +"+++++..++++..++++..++..++++..++..++++..+++..++..++++", +"+++++..++++..++++..++..++++..++..++++..++++....+++++", +"+++++..++++..++++..++..++++..++........+++++..++++++", +"+++++..++++..++++..++..++++..++..++++++++++....+++++", +"+++++..++++..++++..++..++++..++..+++++++++..++..++++", +"+++++..++++..++++..++..++++..++..++++..++..++++..+++", +"++++....+++..++++..+++.......+++......+++..++++..+++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++++++++++++++++++++++++++++++++++++++++++++"}; diff --git a/symbols/marker.xpm b/symbols/marker.xpm new file mode 100644 index 0000000..f5a26fb --- /dev/null +++ b/symbols/marker.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * marker_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"++++++++++++++++++", +"++++++++++++++++++", +"++.+++++++++++++++", +"++...+++++++++++++", +"++.....+++++++++++", +"++..++...+++++++++", +"++..++++...+++++++", +"++..++++++...+++++", +"++..++++++++...+++", +"++..+++++++++...++", +"++..+++++++++...++", +"++..++++++++...+++", +"++..++++++...+++++", +"++..++++...+++++++", +"++..++...+++++++++", +"++.....+++++++++++", +"++...+++++++++++++", +"++.+++++++++++++++", +"++++++++++++++++++", +"++++++++++++++++++"}; diff --git a/symbols/no0.xpm b/symbols/no0.xpm new file mode 100644 index 0000000..9beddf0 --- /dev/null +++ b/symbols/no0.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no0_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++...+++++..", +"..+++++.....++++..", +"..++++...+...+++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..++++...+...+++..", +"..+++++.....++++..", +"..++++++...+++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no1.xpm b/symbols/no1.xpm new file mode 100644 index 0000000..96cf5c0 --- /dev/null +++ b/symbols/no1.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no1_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++...+++++..", +"..+++++....+++++..", +"..++++.....+++++..", +"..++++.+...+++++..", +"..++++++...+++++..", +"..++++++...+++++..", +"..++++++...+++++..", +"..++++++...+++++..", +"..++++++...+++++..", +"..++++.......+++..", +"..++++.......+++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no2.xpm b/symbols/no2.xpm new file mode 100644 index 0000000..669f1f8 --- /dev/null +++ b/symbols/no2.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no2_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..+++++....+++++..", +"..+++........+++..", +"..+++...++...+++..", +"..+++..+++...+++..", +"..++++++++...+++..", +"..+++++++...++++..", +"..++++++...+++++..", +"..+++++...++++++..", +"..++++...++..+++..", +"..+++........+++..", +"..+++........+++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no3.xpm b/symbols/no3.xpm new file mode 100644 index 0000000..3cc6bcc --- /dev/null +++ b/symbols/no3.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no3_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..+++++....+++++..", +"..+++........+++..", +"..+++..+++...+++..", +"..++++++++...+++..", +"..++++++....++++..", +"..++++++....++++..", +"..++++++++...+++..", +"..++++++++...+++..", +"..+++..+++...+++..", +"..+++........+++..", +"..++++.....+++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no4.xpm b/symbols/no4.xpm new file mode 100644 index 0000000..fced9ab --- /dev/null +++ b/symbols/no4.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no4_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++....++++..", +"..+++++.....++++..", +"..++++......++++..", +"..++++..+...++++..", +"..+++..++...++++..", +"..++...++...++++..", +"..++.........+++..", +"..++.........+++..", +"..+++++++...++++..", +"..+++++++...++++..", +"..+++++++...++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no5.xpm b/symbols/no5.xpm new file mode 100644 index 0000000..e62c7d1 --- /dev/null +++ b/symbols/no5.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no5_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..+++........+++..", +"..+++........+++..", +"..+++...++++++++..", +"..+++...++++++++..", +"..+++.......++++..", +"..+++........+++..", +"..++++++++...+++..", +"..++++++++...+++..", +"..+++..+++...+++..", +"..+++........+++..", +"..++++......++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no6.xpm b/symbols/no6.xpm new file mode 100644 index 0000000..0ebfee7 --- /dev/null +++ b/symbols/no6.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no6_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++.....+++..", +"..++++.......+++..", +"..++++...+++++++..", +"..+++...++++++++..", +"..+++...+...++++..", +"..+++........+++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..++++.......+++..", +"..+++++.....++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no7.xpm b/symbols/no7.xpm new file mode 100644 index 0000000..2266355 --- /dev/null +++ b/symbols/no7.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no7_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..+++.........++..", +"..+++.........++..", +"..+++..++++...++..", +"..++++++++...+++..", +"..++++++++...+++..", +"..+++++++...++++..", +"..+++++++...++++..", +"..++++++...+++++..", +"..++++++...+++++..", +"..+++++...++++++..", +"..+++++...++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no8.xpm b/symbols/no8.xpm new file mode 100644 index 0000000..227ba5e --- /dev/null +++ b/symbols/no8.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no8_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..+++++.....++++..", +"..++++.......+++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..++++.......+++..", +"..++++.......+++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..++++.......+++..", +"..+++++.....++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/no9.xpm b/symbols/no9.xpm new file mode 100644 index 0000000..b2a795a --- /dev/null +++ b/symbols/no9.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char * no9_xpm[] = { +"18 20 2 1", +". c #000000", +"+ c #FFFFFF", +"+................+", +"..................", +"..++++++++++++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..+++++.....++++..", +"..++++.......+++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..+++...+++...++..", +"..++++........++..", +"..+++++...+...++..", +"..+++++++++...++..", +"..++++++++...+++..", +"..++++.......+++..", +"..++++.....+++++..", +"..++++++++++++++..", +"..++++++++++++++..", +"..................", +"+................+"}; diff --git a/symbols/page1.xpm b/symbols/page1.xpm new file mode 100644 index 0000000..0d005a7 --- /dev/null +++ b/symbols/page1.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *page1_xpm[]={ +"36 20 2 1", +"# c #000000", +". c #ffffff", +"....................................", +"....................................", +"....############....................", +"....############....................", +"....##........##....................", +"....##.######.##....................", +"....##.######.##....................", +"....##........##....................", +"....##........##....................", +"....##.######.##....................", +"....##.######.##....................", +"....##........##....................", +"....##........##....................", +"....##.######.##....................", +"....##.######.##....................", +"....##........##....................", +"....############....................", +"....############....................", +"....................................", +"...................................."}; diff --git a/symbols/pageE.xpm b/symbols/pageE.xpm new file mode 100644 index 0000000..a47547f --- /dev/null +++ b/symbols/pageE.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *pageE_xpm[]={ +"36 20 2 1", +"# c #000000", +". c #ffffff", +"....................................", +"....................................", +"....############....................", +"....############....................", +"....##........##....................", +"....##........##....................", +"....##.######.##....................", +"....##.######.##....................", +"....##.##..##.##....................", +"....##.##..##.##....................", +"....##.##..##.##....................", +"....##.##..##.##....................", +"....##.######.##....................", +"....##.######.##....................", +"....##........##....................", +"....##........##....................", +"....############....................", +"....############....................", +"....................................", +"...................................."}; diff --git a/symbols/pages2.xpm b/symbols/pages2.xpm new file mode 100644 index 0000000..ff63eca --- /dev/null +++ b/symbols/pages2.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *pages2_xpm[]={ +"36 20 2 1", +"# c #000000", +". c #ffffff", +"....................................", +"....................................", +"....############....................", +"....##################..............", +"....##........########..............", +"....##.######.##....##..............", +"....##.######.#####.##..............", +"....##........#####.##..............", +"....##........##....##..............", +"....##.######.##....##..............", +"....##.######.#####.##..............", +"....##........#####.##..............", +"....##........##....##..............", +"....##.######.##....##..............", +"....##.######.#####.##..............", +"....##........#####.##..............", +"....############....##..............", +"....##################..............", +"..........############..............", +"...................................."}; diff --git a/symbols/pages3.xpm b/symbols/pages3.xpm new file mode 100644 index 0000000..b6342e8 --- /dev/null +++ b/symbols/pages3.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *pages3_xpm[]={ +"36 20 2 1", +"# c #000000", +". c #ffffff", +"....................................", +"....############....................", +"....##################..............", +"....##........##############........", +"....##.######.##....########........", +"....##.######.#####.##....##........", +"....##........#####.#####.##........", +"....##........##....#####.##........", +"....##.######.##....##....##........", +"....##.######.#####.##....##........", +"....##........#####.#####.##........", +"....##........##....#####.##........", +"....##.######.##....##....##........", +"....##.######.#####.##....##........", +"....##........#####.#####.##........", +"....############....#####.##........", +"....##################....##........", +"..........##################........", +"................############........", +"...................................."}; diff --git a/symbols/pages4.xpm b/symbols/pages4.xpm new file mode 100644 index 0000000..fa743a0 --- /dev/null +++ b/symbols/pages4.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *pages4_xpm[]={ +"36 20 2 1", +"# c #000000", +". c #ffffff", +"....................................", +"....############....................", +"....##################..............", +"....##........##############........", +"....##.######.##....##############..", +"....##.######.#####.##....########..", +"....##........#####.#####.##....##..", +"....##........##....#####.#####.##..", +"....##.######.##....##....#####.##..", +"....##.######.#####.##....##....##..", +"....##........#####.#####.##....##..", +"....##........##....#####.#####.##..", +"....##.######.##....##....#####.##..", +"....##.######.#####.##....##....##..", +"....##........#####.#####.##....##..", +"....############....#####.#####.##..", +"....##################....#####.##..", +"..........##################....##..", +"................##################..", +"......................############.."}; diff --git a/symbols/radio.xpm b/symbols/radio.xpm new file mode 100644 index 0000000..250c01e --- /dev/null +++ b/symbols/radio.xpm @@ -0,0 +1,23 @@ +/* XPM */ +static const char *radio_xpm[] = { +"27 18 2 1", +". c #FFFFFF", +"+ c #000000", +"...........................", +"............+++++..........", +"............+++++++++......", +"............+++++++++++....", +"............+++...++++++...", +"............+++.....++++...", +"............+++.....+++....", +"............+++.....++.....", +"............+++............", +"............+++............", +"............+++............", +"......+++++++++............", +"...+++++++++++++...........", +"..+++++++++++++++..........", +"..+++++++++++++++..........", +"...+++++++++++++...........", +".....++++++++++............", +"..........................."}; diff --git a/symbols/rass.xpm b/symbols/rass.xpm new file mode 100644 index 0000000..bc2ee5f --- /dev/null +++ b/symbols/rass.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *rass_xpm[]={ +"47 20 2 1", +"# c #000000", +". c #FFFFFF", +"...............................................", +"...............................................", +".....#####......######.........................", +".....######...#########........................", +"........###..##########........................", +"........########....###........................", +"........#######.....###........................", +".......######......####........................", +".......#####......####.............###....###..", +"......#####......####......###....####...###...", +"......####.....#####....######....###...####...", +".....#####.########....######....#####..#####..", +".....####..######.....####......######.######..", +"....####...####......####.##....###.#########..", +"....###.....####.....###..###.......##....###..", +"...####......#######.##..###.......###....###..", +"...###........######.##########.######.######..", +"..###..........####..#####.####.#####.######...", +"...............................................", +"..............................................."}; diff --git a/symbols/rds.xpm b/symbols/rds.xpm new file mode 100644 index 0000000..52d4017 --- /dev/null +++ b/symbols/rds.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *rds_xpm[] = { +"80 20 2 1", +". c #000000", +"+ c #FFFFFF", +"++++++++.....++++++......+++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++.+++++++.+++.+++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++.+++.+++++.+.+++++++++.++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++++.++++++++.+++.++++++++.+.+++++......+++++++++++......+++++++++++++++....+++", +"++.+.+++.....++++.++.....+++.+.++++..........+++++++.........+++++++++++.......+", +"++..+++.......++.++.......+++++++++..........+++++++..........+++++++++........+", +"+.+.++.......++.++.........++++.+++....++....+++++++...........++++++++.......++", +"+.+++........+.++...........+.+++++...+++....++++++.....+++....+++++++...+++++++", +"++++.....+++.+.++....+++......++.++...+++....++++++.....++++....++++++....++++++", +"........++++++.++...++++.........++...++.....+....+....+++++....+..+++.......+++", +"....+...++++++.++....+++....+....++.........++...++....+++++...++..+++........++", +"+...++.+.+++.++++....+++++.++....++........+++...++....+++++...++..++++.......++", +"+....+++++++++++....+++++.++....++........+++++++++....++++...++++++++++++....++", +"+.....++.....++....+....+++.....++...+....+++++++++...++++....+++++++++++++...++", +"++.....+++++++.....+++++++.....+++...++....++++++++...++.....++++++++..+++....++", +"++......+++++.......+++++......+++...++....++++++++..........+++++++.........+++", +"+++...........................+++....+++....++++++..........+++++++..........+++", +"++++.............+...........++++....+++....+++++++.......++++++++++++....++++++", +"++++++.........+++.........+++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++.....+++++++....++++++++++++++++++++++++++++++++++++++++++++++++++++++++"}; diff --git a/symbols/rds_20x80.xpm b/symbols/rds_20x80.xpm new file mode 100644 index 0000000..52d4017 --- /dev/null +++ b/symbols/rds_20x80.xpm @@ -0,0 +1,25 @@ +/* XPM */ +static const char *rds_xpm[] = { +"80 20 2 1", +". c #000000", +"+ c #FFFFFF", +"++++++++.....++++++......+++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++.+++++++.+++.+++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++.+++.+++++.+.+++++++++.++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++++.++++++++.+++.++++++++.+.+++++......+++++++++++......+++++++++++++++....+++", +"++.+.+++.....++++.++.....+++.+.++++..........+++++++.........+++++++++++.......+", +"++..+++.......++.++.......+++++++++..........+++++++..........+++++++++........+", +"+.+.++.......++.++.........++++.+++....++....+++++++...........++++++++.......++", +"+.+++........+.++...........+.+++++...+++....++++++.....+++....+++++++...+++++++", +"++++.....+++.+.++....+++......++.++...+++....++++++.....++++....++++++....++++++", +"........++++++.++...++++.........++...++.....+....+....+++++....+..+++.......+++", +"....+...++++++.++....+++....+....++.........++...++....+++++...++..+++........++", +"+...++.+.+++.++++....+++++.++....++........+++...++....+++++...++..++++.......++", +"+....+++++++++++....+++++.++....++........+++++++++....++++...++++++++++++....++", +"+.....++.....++....+....+++.....++...+....+++++++++...++++....+++++++++++++...++", +"++.....+++++++.....+++++++.....+++...++....++++++++...++.....++++++++..+++....++", +"++......+++++.......+++++......+++...++....++++++++..........+++++++.........+++", +"+++...........................+++....+++....++++++..........+++++++..........+++", +"++++.............+...........++++....+++....+++++++.......++++++++++++....++++++", +"++++++.........+++.........+++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++.....+++++++....++++++++++++++++++++++++++++++++++++++++++++++++++++++++"}; diff --git a/symbols/rds_24x95.xpm b/symbols/rds_24x95.xpm new file mode 100644 index 0000000..2ff5054 --- /dev/null +++ b/symbols/rds_24x95.xpm @@ -0,0 +1,29 @@ +/* XPM */ +static const char * rds_xpm[] = { +"95 24 2 1", +". c #000000", +"+ c #FFFFFF", +"+++++++++.......+++++++.......+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++++++.+++++++++.+++.+++++++++..++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++++..+++++++++++++.++++++++++++.+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++.+++.+++++++.+.+++.+++++++.++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"+++.++.++++++++++.+++.++++++++++.++.++++++.......+++++++++++++.......++++++++++++++++++.....+++", +"++.++.+++.......++++.+++......+++.++.+++++...........+++++++++..........+++++++++++++.........+", +"++.+.+++.........++.++.........+++.+++++++............++++++++............++++++++++..........+", +"+.++.++.........++.++...........+++++.++++............++++++++.............+++++++++.........++", +"+.++++..........++.++............++++.++++....+++.....++++++++....+++......++++++++.....+++++++", +"+.+.++..........+.++.............++.+++++.....+++.....+++++++.....++++.....++++++++....++++++++", +"+++.+......+++..+.++.....+++......+.++.++.....+++.....+++++++.....+++++.....+++++++.....+++++++", +"..........+++++.+.++....+++++.....+....++....+++.....++....++....++++++.....+...+++........++++", +".....+....+++++.+.++.....++++....+.....++...........+++...+++....++++++....++...+++..........++", +"+....++.++.+++.+++++.....+++.++.++.....++..........++++...++.....++++++....++...++++.........++", +"+.....+++++...++.++.....+...+++.+.....+++........++++++...++.....+++++.....++...+++++++......++", +"+.....+++++++++++++.....++++++.++.....++..........++++++++++.....+++++....++++++++++++++.....++", +"+......+++.....+++.....+.....+++......++....+.....++++++++++....+++++.....+++++++++++++++....++", +"++......+++++++++......++++++++......+++....++.....+++++++++....+++......+++++++++..++++.....++", +"++.......+++++++......+.++++++.......+++....++.....+++++++++............+++++++++...........+++", +"+++...................+.............+++.....+++.....+++++++............+++++++++...........++++", +"++++.................+.............++++....++++......++++++..........++++++++++++.........+++++", +"+++++...............+.............+++++++++++++++++++++++++++++++++++++++++++++++++.....+++++++", +"+++++++...........+++...........+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++", +"++++++++++.....+++++++++.....++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"}; |