# SuperDateTime plugin.pm by Greg Brown Feb 2005 # Copyright (c) 2005 # All rights reserved. # # DESCRIPTION # SlimServer plugin screensaver datetime replacement. Graphically displays current weather conditions and forecasts. # Will also optionally display stock quotes and upcoming/current game information for MLB, NBA, NHL, NFL, and college # football and basketball teams at user-configurable intervals. # # REMOTE CONTROL # Pressing up or down cycles the information shown on line one during time display. It will also immediately # display the time if it is not currently being shown. # Pressing right or left cycles through the available games and long weather forecasts that normally cycle automatically. # Pressing FWD or REW cycles through the long weather forecasts. # Pressing '+' will force an immediate data refresh. # # This screen saver is based on the standard SlimServer DateTime screensaver written written by kdf. # The graphical weather icons and the code to support them are based on the WeatherTime screensaver written by Martin Rehfeld. # # VERSION HISTORY # 5.0.13 09/05/07 Updated weather.com international current condition parsing to handle HTML changes. # 5.0.12 08/26/07 Updated weather.com international parsing to handle HTML changes. # Added german language translations. Thanks Jürgen! # 5.0.10 07/19/07 Updated MLB web parsing to handle changes made by ESPN. # 5.0.8 05/30/07 Added all remaing MLB icons. Thanks B. Yudichak! # 5.0.6 05/17/07 Added Minnesota, Tampa Bay, Boston, and Cleveland MLB icons. Thanks M.Meyer! # 5.0.5 04/02/07 Fixed ESPN MLB parsing to handle minor '07 season website changes. # Divided up MLB processing to decrease HTML parsing hangs. # Added a few additional MLB logos. # 5.0.4 01/19/07 Fixed bug where Top-25 conference selection is overwritten on sever restart. # 5.0.2 01/18/07 When a player is powered on SuperDateTime can be displayed/exited by holding the Size button for a couple # seconds. This requires a minor manual modification to the default.map file (see installation instructions). # Yahoo Finance ticker symbols that do not provide volume information are now supported. # Top-25 is now selectable as a conference for college basketball and football game information. # 5.0.0 12/07/06 This version introduces 34 graphical weather icons based on code from Martin Rehfeld's WeatherTime screensaver. # Pressing the up/down bottoms will scroll through the forecasts as well as various display options that # include/omit the forecast icons. # MLB, NBA, and NHL refreshing logic has been enhanced. The previous day's game information will continue # to be shown/refreshed until 5am Eastern time. Refreshing will also stop on a given day once all the games # you are monitoring have completed. # To save screen space Hi/Low and Precip information is no longer shown when the time is displayed with a # large font (non Transporters only). The $largeFontTimeIcon variable can be changed by the user if they # wish to show the hi/low and precip information or remove the current condition icon. # Added support for college football and tweaked code to handle ranked team name shortening. # Added experimental support for MLB and NFL team icons (must be enabled from plugin settings). # Parsing and networking tweaks. # Special thanks to Mike Meyer and Yannzola for contributing some of the weather icons. # 4.1.2 09/06/06 Merged code provided by Omen Wild. This adds server setting to show average temperature delta and # record temperature information on the top display line. # 4.1.1 08/31/06 The top line text in screen one, as well as the top and bottom lines of screen 2 can now be customized. # Minor networking bug fixes. # 4.1.0 08/16/06 Updated to utilize new display framework introduced in SlimServer 6.5. # Initial Transporter (dual screen) support. # Failed http calls will automatically be retried three times before a '?' is displayed (indicating failure). # Various bug/code enhancements. # *** SlimServer 6.5 or later is required. *** # 4.0.6 05/18/06 When using the large font, text will now automatically scroll. Shortened weather data, previously # only shown with smaller fonts on the top line, is now viewable by pressing the up and down remote buttons. # To view the entire scrolling text please set your display times accordingly. # 4.0.5 04/05/06 Updated MLB web parsing to handle 2006 format. # 4.0.4 03/03/06 Added wunderground.com support. # Added stock market support. # Added "ticker" display mode. # 4.0.1 01/09/06 Long weather forecasts are now always viewable via the FWD and REW remote control buttons. # Updated NBA New Orleans city name to handle its temp location of NO\Oklahoma City. Thanks sliph. # 4.0.0 12/13/05 Line two display information can now be customized via a format string. (Thanks MrC) # Added full text weather forecasts. # Added college basketball support. # Reworked background data refreshing. # Reworked information display/remote control to make clients independent of each other. # Added barometric pressure and dew point display. # Wind speed can now be displayed in knots. # Minor bug fixes. # 3.6.4 11/13/05 Updated Server Settings text to include Latin American Spanish. Much thanks Néstor. # 3.6.3 11/05/05 Added kilometers/hour conversion option for wind speed. # 3.6.1 10/26/05 Fixed spelling of the NY Knicks (thanks SBB). # Fixed bugs related to the NY Jets/Giants (thanks JL). # Hopefully fixed bug in displaying double digit innings as single digits (thanks JL). # 3.6.0 10/25/05 Added weather conditions/forecasts (shown on top line during two-line display mode). # Plug-in is now interactive # - Pressing up or down on remote will cycle weather forecast/condition information. # - Pressing left or right will cycle each of the games being displayed. # - Pressing + will force an immediate full data refresh. # Added text scroll type in server plug-in settings. # - Basic text scrolling updates the display immediately with no scrolling (original way). # - Slide text scrolling updates the display by sliding information onto and off of the screen (default). # Code clean up. # 3.5.0 10/08/05 Added NHL support. # Swapped order of wind speed and wind direction ("proper way"- Thanks Wojo). # 3.4.3 09/27/05 Added wind speed support. - Thanks CMcKinnon # 3.4.2 09/26/05 *** SlimServer 6.2 or later is most likely required. *** # Fixed NFL parsing to handle regular season data format. # Line one will now display the sport league pertaining to the game information in line two. # Added status indicator in top right hand corner of display line one. # - '*' is displayed while data is being refreshed. # - If a data update fails the sport abbreviation, or 'W' for weather will be displayed # until a successful update occurs. Stale data from the last successful update will continue # to be displayed. # - An alarm bell indicator is displayed during the clock display if an alarm clock is set and # no other status is being shown. # 3.4.0 08/23/05 Added BETA NFL support (parses content successfully most of the time). # Now utilizes Slim::Networking::SimpleAsyncHTTP for asynchronous/background network calls. # - This should decrease the chance of server freezes/crashes occuring while data is being retrieved. # Network debugging information is sent to -d_plugin. # Rewrote display algorithm to handle background data retrieval. # 3.2.11 08/12/05 Fixed bug where teams would not save on some new installations. # 3.2.10 06/22/05 Tweaked NBA web parsing. # 3.2.9 06/17/05 Added support for displaying active and upcoming/complete games at different intervals. # Added setting to enable/disable showing of the "feels like" temperature. # Fixed bug where humidity setting wouldn't save. # Tweaked NBA web parsing. # Tweaked weather web parsing. # 3.2.6 06/12/05 Shortened most teams to team name instead of city name to shorten their display character length. # Tweaked NBA web parsing. # 3.2.5 06/10/05 Added "BETA" NBA support. # 3.2.0 06/09/05 Added support for tracking of multiple baseball teams. Added option to display humidity level. # 3.0.8 06/01/05 Minor bug/display fixes. No longer displays "feels like" temperature if the same. # 3.0.7 05/20/05 Fixed timezone bug where a data refresh resets offset setting. # 3.0.6 05/20/05 Fixed display bug when displaying final game scores that trigger scrolling. # 3.0.5 05/20/05 Added celsius and fahrenheit support. Added more time zone offsets. # 3.0.0 03/19/05 Formal PUBLIC release. Fully configurable via plugins web interface. # # INSTALLATION # 1. Unzip downloaded zip file into SlimServer\server\Plugins\ directory. This should result in a SuperDateTime folder # being created within the Plugins folder that contains Plugin.pm. The folder name is case sensitive. # 2. Restart slimserver. # 3. Ensure plugin is enabled from Server Settings / Plugins web page. # 4. Configure custom plugin settings (city, teams, etc.) from Server Setttings / Plugins web page. # 5. Enable screensaver for when a player is turned off from Player Settings web page. # # [OPTIONAL] SlimServer can be configured to temporarily display SuperDateTime when powered on by holding the # size button for a couple seconds. The display is returned to it's previous state by holding the # size button again for a couple seconds. This is useful to view sports/weather/etc information # while listening to music. # # 6. Open up \SlimServer\Server\IR\Default.map in your favorite raw text editor. # 7. Scroll down to # textsize modes # 8. Edit the text in that section to mirror: # size = dead # size.single = textsize_toggle # size.hold = modefunction_PLUGIN.SuperDateTime::Plugin->showme # #size = textsize_toggle # textsize_small = textsize_small # textsize_medium = textsize_medium # textsize_large = textsize_large # 9. Restart SlimServer # # FEEDBACK # Please direct all feedback to GoCubs on the Slim Devices public forums at forums.slimdevices.com # # KNOWN BUGS/ISSUES # 1.) Text may get truncated if it does not fit on the screen. Selecting a smaller font fixes the problem. # 2.) When using the "slide" scroll option, time display may appear to skip a second when the display # transitions from showing game information or long description forecast to the time. # 3.) In celius mode, a long description forecast that contains a temperature group (ie mid to upper 30s) instead of # a specific high/low value (Low 30F) may not make sense after the conversion (ie mid to upper -2s). # 4.) When SuperDateTime is used as an offsaver in SoftSqueeze, data refreshes will continue to occur once SoftSqueeze is # closed. This is because SoftSqueeze is put in "off" state when it is closed, which activates the offsaver. # # 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 # # This code is derived from code with the following copyright message: # # SliMP3 Server Copyright (C) 2001 Sean Adams, Slim Devices Inc. # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License, # version 2. use strict; package Plugins::SuperDateTime::Plugin; use Slim::Utils::Misc; use Slim::Utils::Strings qw (string); use Slim::Networking::SimpleAsyncHTTP; use vars qw($VERSION); $VERSION = substr(q$Revision: 5.0.13 $,10); sub getDisplayName { return 'PLUGIN_SCREENSAVER_SUPERDATETIME'; } sub strings { return q! PLUGIN_SCREENSAVER_SUPERDATETIME DE Bildschirmschoner: Datum/Zeit (SuperDateTime) EN SuperDateTime Screensaver FR Ecran de veille Date/Heure ES Salvapantalla SuperFechaHora PLUGIN_SCREENSAVER_SUPERDATETIME_ENABLE DE PLAY drücken zum Aktivieren des Bildschirmschoners EN Press PLAY to enable this screensaver ES Presionar PLAY para habilitar este salvapantalla FR Appuyer sur PLAY pour activer PLUGIN_SCREENSAVER_SUPERDATETIME_DISABLE DE PLAY drücken zum Deaktivieren dieses Bildschirmschoners EN Press PLAY to disable this screensaver ES Presionar PLAY para deshabilitar este salvapantalla FR Appuyer sur PLAY pour désactiver PLUGIN_SCREENSAVER_SUPERDATETIME_ENABLING DE Datum/Zeit Bildschirmschoner aktivieren EN Enabling SuperDateTime as current screensaver ES Habilitando SuperFechaHora como salvapantalla por defecto FR Activation écran de veille Date/Heure PLUGIN_SCREENSAVER_SUPERDATETIME_DISABLING DE Standard-Bildschirmschoner aktivieren EN Resetting to default screensaver ES Restableciendo salvapantallas por defecto FR Retour à écran de veille par défaut SETUP_GROUP_PLUGIN_SCREENSAVER_SUPERDATETIME DE Einstellungen für den Bildschirmschoner 'Datum/Zeit' (SuperDateTime) EN SuperDateTime Screensaver SETUP_GROUP_PLUGIN_SCREENSAVER_SUPERDATETIME_DESC DE Zeigt die lokale Zeit, Datum, Wetter, Sport- und Börseninformationen an.
Achtung: Es kann bis zu 5min dauern bis Parameteränderungen sich auf die Anzeige auswirken. Durch Drücken der +-Fernbedienungstaste wird eine direkte Aktualsierung der Anzeige angestoßen. Abhängig von der gewählten Schriftart und den anzuzeigenden Daten kann Text abgeschnitten oder die Anzeige durchgerollt werden. EN Displays local time, date, weather, sports, and stocks information.
Note: Setting changes may take up to 5minutes before the display is updated accordingly. Pressing the + remote button will cause an immediate refresh. Text scrolling or truncation may occur based on display font and content options chosen. ES Muestra información sobre hora local, fecha, clima, y deportes.
Nota: Los cambios a la configuración pueden tardar hata 10 segundos en verse reflejados en la pantalla. De acuerdo a la fuente elegida y la información a mostrar, puede producirse truncamiento o desplazamiento de texto. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CITY DE Stadt EN City ES Ciudad SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CITY_DESC DE Ihre Postleitzahl oder ihr weather.com-Kennzeichen (z.B. Berlin = GMXX0007) EN Your US Zip Code or Weather.com identifier (ie London = UKXX0085) ES Tu código Zip (en EEUU) o identificador en Weather.com (ie Buenos Aires = ARBA0009) SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CITY_CHOOSE DE Postleitzahl oder weather.com-Kennzeichen: EN Zip code or identifier: ES Código Zip o identificador: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WUNDER DE Underground-Wetter EN Weather Underground SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WUNDER_DESC DE Sie haben die Möglichkeit die Kennziffer einer Undergroud-Wetterstation (www.wunderground.com) anzugeben und die aktuell von weather.com zur Verfügung gestellten Informationen zu überschreiben (z.B. Prenzlauer Berg, Berlin = IBERLIN15)..
Achtung: Die Datenfelder von Wetterstationen können sich ändern. Wetterdaten von weather.com werden jedoch weiter zur Verfügung gestellt. EN You have the option to supply a wunderground.com weather station to override weather.com current condition data (ie Lakeview, Chicago = KILCHICA42).
Note: Data fields supplied by weather stations will vary. Forecast data will continue to be supplied by weather.com. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WUNDER_CHOOSE DE Kennzeichen der Underground-Wetterstation: EN Weather station identifier: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT1T DE Zeit-/Wetterformat Zeile 1 EN Line 1 Time/Weather Format String SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT1T_DESC DE Sie können hier die in Zeile 1 anzuzeigenden Informationen anpassen. Dies wird durch die Verwendung von speziellen Platzhaltern ermöglicht:
Zeit = %1 (nur Zeile 2)
Temperatur (°F) = %t
Temperatur (°C) = %T
Gefühlte Temperatur (°F) = %f
Gefühlte Temperatur (°C) = %F
Luftfeuchtigkeit = %h
Windgeschwindigkeit = %w
Luftdruck (inHg) = %p
Luftdruck (hPa) = %P
Tiefsttemperatur (°F) = %d
Tiefsttemperatur (°C) = %D

Standardformat: %w TP:%D LD:%p

Achtung: Durch Drücken der hoch- und runter-Pfeiltasten kann die Informationensanzeige in Zeile 1 umgeschaltet werden. EN You can customize the display of information shown on line one. This is accomplished using macro variables:
Time = %1 (line 2 only)
Temperature (°F) = %t
Temperature (°C) = %T
Feels-Like Temperature (°F) = %f
Feels-Like Temperature (°C) = %F
Humidity = %h
Wind Speed = %w
Barometric Pressure (inHg) = %p
Barometric Pressure (hPa) = %P
Dew Point (°F) = %d
Dew Point (°C) = %D

The default format string is: %w DP:%d P:%p

Note: Pressing the up and down remote control buttons will cycle display of custom and pre-defined top line information. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT1T_CHOOSE DE Zeilenformat Zeile 1 (Anzeige 1): EN Line 1 format string (display 1): SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT1B DE Zeit-/Wetterformat Zeile 2 EN Line 2 Time/Weather Format String SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT1B_DESC DE Sie können hier die in Zeile 2 anzuzeigenden Informationen anpassen. Dies wird durch die Verwendung der gleichen Platzhaltern wie bei Zeile 1 ermöglicht.

Standardformat: %TC/%h %1 EN You can customize the display of information shown on line two. This is accomplished using the same macro variables used on line one.

The default format string is: %t/%h %1 SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT1B_CHOOSE DE Zeilenformat Zeile 2 (Anzeige 1): EN Line 2 format string (display 1): SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT2T DE Zeit-/Wetterformat Zeile 1 EN Line 1 Time/Weather Format String SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT2T_DESC DE Bei SqueezeBoxen mit mehreren Anzeigen können Sie hier die auf der zweiten Anzeige in Zeile 1 anzuzeigenden Informationen anpassen. Dies wird durch die Verwendung der gleichen Platzhalter wie bei der ersten Anzeige ermöglicht. EN For Squeeze Boxes with multiple displays, you can customize the display of information shown on line one of the second display. This is accomplished using the same macro variables used in display one. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT2T_CHOOSE DE Zeilenformat Zeile 1 (Anzeige 2): EN Line 1 format string (display 2): SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT2B DE Zeit-/Wetterformat Zeile 2 EN Line 2 Time/Weather Format String SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT2B_DESC DE Bei SqueezeBoxen mit mehreren Anzeigen können Sie hier die auf der zweiten Anzeige in Zeile 2 anzuzeigenden Informationen anpassen. Dies wird durch die Verwendung der gleichen Platzhalter wie bei der ersten Anzeige ermöglicht. EN For Squeeze Boxes with multiple displays, you can customize the display of information shown on line two of the second display. This is accomplished using the same macro variables used in display one. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WEATHERFORMAT2B_CHOOSE DE Zeilenformat: EN Line 2 format string (display 2): SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TEMPERATURE DE Temperatureinheit EN Forecast Temperature Unit ES Unidad de Temperatura SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TEMPERATURE_DESC DE Gewählte Temperatureineit in der Wettervorhersage. EN You have a choice as to which temperature unit is displayed within weather forecasts. ES Se puede elegir entre mostrar la temperatura en grados celsius o fahrenheit. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TEMPERATURE_CHOOSE DE Temperaturanzeigeeinheit: EN Temperature display: ES Mostrar Temperatura: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WINDUNIT DE Windgeschwindigkeitseinheit EN Forecast Wind Speed Unit ES Unidad para Velocidad del Viento SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WINDUNIT_DESC DE Gewählte Windgeschwindigkeitsanzeige in der Wettervorhersage. EN You have a choice as to which wind speed unit is displayed within weather forecasts. ES Se puede elegir entre mostrar la velocidad del viento en millas/hora o kilómetros/hour. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_WINDUNIT_CHOOSE DE Windgeschwindigkeitseinheit: EN Wind speed unit: ES Unidad de velocidad de viento: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_AVERAGES DE Durchschnittstemperaturanzeige EN Show average temperatures SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_AVERAGES_DESC DE Durchschnittstemperatur und aufgezeichnete Temperatur in Zeile 1 anzeigen. EN Show average temperature delta and record temperature on the top line. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_AVERAGES_CHOOSE DE Durchschnittstemperaturen anzeigen: EN Show average temperatures: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_OFFSET_CHOOSE DE Zeitzonenoffset: EN Time zone offset: ES Diferencia de huso horario: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_OFFSET DE Zeitzonenoffset EN Time Zone Offset ES Diferencia de Huso Horario SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_OFFSET_DESC DE Zeitdifferenz zwischen der lokalen Zeit und der US Eastern-Zeitzone festlegen. Diese Einstellung wird nur für die Spielzeitanzeige verwendet. EN The number of hours different your local time zone is from the US Eastern time zone. This setting is only used for gametime display. ES El número de horas que separan tu huso horario con el huso horario Este de EEUU. Esta configuración se utiliza solo para mostrar el horario de los partidos. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_SCROLL DE Textrollen EN Text Scrolling ES Desplazamiento de Texto SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_SCROLL_DESC DE Sie können entscheiden wie der Anzeigeübergang zwischen zwei Spielen aussehen soll.
Basic: Änderungen werden umgehend angezeigt ohne den Text rollen zu lassen.
Slide: Änderungen werden in bzw. aus der Anzeige geschoben.
Ticker: Änderungen werden in bzw. aus der Anzeige gerollt wie ein Aktienticker. EN You have a choice as to how the display transitions from one game to the next.
Basic: Changes are immediately displayed with no scrolling.
Slide: Changes slide onto and off of the screen.
Ticker: Changes scroll onto and off of the screen like a stock ticker. ES Se puede elegir cómo mostrar las transiciones de un partido a otro.
Básico: Los cambios se muestran en forma inmediata sin desplazamiento.
Desplazar: Los cambios se desplazan hacia y afuera de la pantalla. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_SCROLL_CHOOSE DE Rolltyp: EN Scroll type: ES Tipo de desplazamiento: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCKS DE Aktien EN Stocks SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCKS_DESC DE Sie können eine oder mehrere Aktien festlegen zu denen Informationen abgerufen werden sollen. Trennen Sie mehrere Aktien durch Kommas voneinander. Die Kursinformatien werden durch finance.yahoo.com zur Verfügung gestellt und jeweils mit einer Zeitverzögerung von 20 Minuten angezeigt. EN You can specify one or more stocks to retrieve information about. Separate each stock symbol with a comma. Quotes are supplied by finance.yahoo.com and individual stocks quotes are delayed 20 minutes. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCKS_CHOOSE DE Aktien: EN Stocks: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCK1FORMAT DE Aktienanzeigeformat Zeile 1 EN Stock Line 1 Format SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCK1FORMAT_DESC DE Sie können hier die in Zeile 1 anzuzeigenden Aktieninformationen anpassen. Dies wird durch die Verwendung von speziellen Platzhaltern ermöglicht:
Aktiensymbol = %s
Name = %n
Letzter Kurs = %l
Letztes Kursdatum (EST) = %d
Letzte Kurszeit (EST) = %t
Vorheriger Schlusskurs = %p
Änderung = %c
Prozentuale Änderung = %z
Eröffnungskurs = %o
Höchster Kurs = %h
Niedrigster Kurs = %w
Volumen = %v

Standardformat: %n EN You can customize the display of stock information shown on line one. This is accomplished using macro variables:
Ticker Symbol = %s
Name = %n
Last Trade = %l
Last Trade Date (EST) = %d
Last Trade Time (EST) = %t
Previous Close = %p
Change = %c
Percent Change = %z
Open = %o
High = %h
Low = %w
Volume = %v

The default format string is: %n SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCK1FORMAT_CHOOSE DE Aktienformat Zeile 1: EN Stock line 1 format string: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCK2FORMAT DE Aktienformat Zeile 2 EN Stock Line 2 Format SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCK2FORMAT_DESC DE Sie können hier die in Zeile 2 anzuzeigenden Aktieninformationen anpassen. Dies wird durch die Verwendung der gleichen Platzhaltern wie bei Zeile 1 ermöglicht.

Standardformat: %l %c %z %v EN You can customize the display of stock information shown on line two. This is accomplished using the same macro variables used in line one.

The default format string is: %l %c %z %v SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_STOCK2FORMAT_CHOOSE DE Aktienanzeigeformat Zeile 2 EN Stock line 2 format string: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TEAMLOGOS DE BETA-FUNKTION: Mannschaftslogos EN BETA FEATURE: Team Logos SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TEAMLOGOS_DESC DE Sie können hier festlegen wann Mannschaftslogos angezeigt werden sollen.
Anmerkung: Aktuell werden alle MLB und einige NFL Mannschaften unterstützt. Im Zweizeilenmodus sieht die Anzeige am besten aus. Falls ein Logo nicht verfügbar ist wird der Mannschaftsnahme angezeigt. EN You have the option on when to display graphical team logos.
Note: Currently all MLB and some NFL teams are supported and look best in two line mode. If an icon is not available the team name will be shown in text. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TEAMLOGOS_CHOOSE DE Mannschaftslogos: EN Team Logos: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_MLB_DESC DE Die MLB Baseball-Mannschaft(en) über die sie Informationen emfangen möchten. Wählen sie "None" um eine Mannschaft zu entfernen oder "All" um alle Manschaften zu beobachten. EN The MLB baseball team(s) you would like to retrieve game data about. Select "None" to remove a team, or "All" to monitor all teams. ES El/los equipo/s de baseball de los que se quiere mostrar información. Elegir "Ninguno" para eliminar un equipo, o "Todos" para monitorear todos los equipos. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_MLB DE MLB Baseball-Mannschaften EN MLB Baseball Teams ES Equipo de Baseball MLB SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_MLB_CHOOSE DE Baseball-Mannschaft: EN Baseball team: ES Equipo de baseball: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NBA_DESC DE Die NBA Basketball-Mannschaft(en) über die sie Informationen emfangen möchten. Wählen sie "None" um eine Mannschaft zu entfernen oder "All" um alle Manschaften zu beobachten. EN The NBA basketball team(s) you would like to retrieve game data about. Select "None" to remove a team, or "All" to monitor all teams. ES El/los equipo/s de basketball de los que se quiere mostrar información. Elegir "Ninguno" para eliminar un equipo, o "Todos" para monitorear todos los equipos. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NBA DE NBA Basketball-Mannschaften EN NBA Basketball Teams ES Equipo de Basketball NBA SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NBA_CHOOSE DE Basketball-Mannschaft: EN Basketball team: ES Equipo de basketball: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NHL_DESC DE Die NHL Eishockey-Mannschaft(en) über die sie Informationen emfangen möchten. Wählen sie "None" um eine Mannschaft zu entfernen oder "All" um alle Manschaften zu beobachten. EN The NHL hockey team(s) you would like to retrieve game data about. Select "None" to remove a team, or "All" to monitor all teams. ES El/los equipo/s de hockey de los que se quiere mostrar información. Elegir "Ninguno" para eliminar un equipo, o "Todos" para monitorear todos los equipos. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NHL DE NHL Eishockey-Mannschaften EN NHL Hockey Teams ES Equipos de Hockey NHL SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NHL_CHOOSE DE Eishockey-Mannschaft: EN Hockey team: ES Equipo de hockey: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NFL_DESC DE Die NFL American Football-Mannschaft(en) über die sie Informationen emfangen möchten. Wählen sie "None" um eine Mannschaft zu entfernen oder "All" um alle Manschaften zu beobachten. EN The NFL football team(s) you would like to retrieve game data about. Select "None" to remove a team, or "All" to monitor all teams. ES El/los equipo/s de football americano de los que se quiere mostrar información. Elegir "Ninguno" para eliminar un equipo, o "Todos" para monitorear todos los equipos. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NFL DE NFL American Football-Mannschaften EN NFL Football Teams ES Equipo de Football americano NFL SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_NFL_CHOOSE DE American Football-Mannschaft: EN Football team: ES Equipo de football americano: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CBBALLCONF DE College-Basketball-Konferenz EN College Basketball Conference SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CBBALLCONF_DESC DE Sie können wählen zu welcher College-Basketball-Konferenz Datendateien abgerufen werden sollen.
Anmerkung: Die Auswahl von "all" kann zum Abruf von sehr großen Dateien führen und Serverabstürze bei der Datenverarbeitung verursachen. EN You have a choice as to which college basketball conference data file is retrieved.
Note: Selecting "all" can result in a large download which may cause brief server hangs while data is being processed. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CBBALLCONF_CHOOSE DE Konferenz: EN Conference: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CBB DE College-Basketball-Mannschaften EN College Basketball Teams SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CBB_DESC DE Geben Sie die ESPN Mannschaftsnamen ein deren Spieldaten sie empfangen möchten. Geben Sie eine Mannschaft pro Zeile ein oder "All" um alle Mannschaften anzuzeigen. EN Enter the ESPN team name of the team(s) you would like to retrieve game data about. Enter one team per line or "All" to display all teams. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CFBALLCONF DE College-American Football-Konferenz EN College Football Conference SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CFBALLCONF_DESC DE Sie können wählen zu welcher College-American Football-Konferenz Datendateien abgerufen werden sollen.
Anmerkung: Die Auswahl von "All Div I-A" oder "All Div I-AA" kann zum Abruf von sehr großen Dateien führen und Serverabstürze bei der Datenverarbeitung verursachen. EN You have a choice as to which college football conference data file is retrieved.
Note: Selecting "All Div I-A" or "All Div I-AA" can result in a large download which may cause brief server hangs while data is being processed. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CFBALLCONF_CHOOSE DE Konferenz: EN Conference: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CFB DE College-American Football-Mannschaften EN College Football Teams SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_CFB_DESC DE Geben Sie die ESPN Mannschaftsnamen ein deren Spieldaten sie empfangen möchten. Geben Sie eine Mannschaft pro Zeile ein oder "All" um alle Mannschaften anzuzeigen. EN Enter the ESPN team name of the team(s) you would like to retrieve game data about. Enter one team per line or "All" to display all teams. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TIME DE Zeitintervall EN Time Interval ES Intervalo de Tiempo SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TIME_DESC DE Anzahl Sekunden nach denen zur Zeitanzeige gewechselt werden soll wenn kein Spiel aktiv ist. EN Number of seconds to display time information before cycling when no games are active. ES Número de segundos durante los cuales mostrar la información antes de ciclar cuando no hay partidos disputándose. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_TIME_CHOOSE DE Zeitintervall in Sekunden: EN Time interval in seconds: ES Intervalo de Tiempo en segundos: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_ATIME DE Zeitintervall (aktives Spiel) EN Time Interval (Active Game) ES Intervalo de Tiempo (Partido Disputándose) SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_ATIME_DESC DE Anzahl Sekunden nach denen zur Zeitanzeige gewechselt werden soll wenn ein Spiel aktiv ist. EN Number of seconds to display time information before cycling when a game is active. ES Número de segundos durante los cuales mostrar la información antes de ciclar cuando hay algún partido disputándose. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_ATIME_CHOOSE DE Zeitintervall in Sekunden: EN Time interval in seconds: ES Intervalo de Tiempo en segundos: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_SCORE DE Zeitintervall kommender und beendeter Spiele EN Upcoming/Completed Game Interval ES Intervalo para Partidos Terminados/Por empezar SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_SCORE_DESC DE Anzahl Sekunden während denen Informationen über zukünftige oder bereits beendete Spiele angezeigt werden sollen bevor die Anzeige gewechselt wird. EN Number of seconds to display upcoming or completed game information before cycling. ES Número de segundos durante los cuales mostrar la información sobre partidos terminados o por empezar, antes de ciclar. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_SCORE_CHOOSE DE Zeitintervall in Sekunden: EN Time interval in seconds: ES Intervalo de Tiempo en segundos: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_ASCORE DE Interval der Ergebnisanzeige bei aktiven Spielen EN Active Game Score Interval ES Intervalo para Tanteador de Partido en Juego SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_ASCORE_DESC DE Anzahl Sekunden während denen das Ergebnis eines aktiven Spiels angezeigt werden soll bevor die Anzeige gewechselt wird. EN Number of seconds to display an active game's score information before cycling. ES Número de segundos durante los cuales mostrar la información del tanteador del partido en juego, antes de ciclar. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_ASCORE_CHOOSE DE Zeitintervall in Sekunden: EN Time interval in seconds: ES Intervalo de Tiempo en segundos: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_REFRESH DE Datenaktualisierungsintervall EN Data Refresh Interval ES Intervalo de Refresco de Datos SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_REFRESH_DESC DE Anzahl der Minuten bevor externe Daten aktualsiert werden. EN Number of minutes before external data is refreshed. ES Número de minutos antes que se refresque la información del clima y deportiva. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_REFRESH_CHOOSE DE Aktualisierungsintervall in Minuten: EN Refresh interval in minutes: ES Intervalo de refresco en minutos: SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_LWEATHER DE Anzeige der ausführlichen Wettervorhersage EN Long Weather Forecast Display SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_LWEATHER_DESC DE Sie können wählen wann die ausführliche Wettervorhersage angezeigt werden soll.
Anmerkung: Ungeachtet dieser Einstellung kann die ausführliche Wettervorhersage jederzeit durch Drücken des FWD und REW Knopfes auf der Fernbedienung angezeigt werden. EN You have a choice as to when long weather forecasts are displayed.
Note: Regardless of this setting, long weather forecasts are always viewable via the FWD and REW remote control buttons. SETUP_PLUGIN_SCREENSAVER_SUPERDATETIME_LWEATHER_CHOOSE DE Ausführliche Wettervorhersage: EN Long Weather Forecasts: ES Intervalo de Tiempo en segundos: !}; ################################################## ### Super Variables ### DEFAULT VALUES ################################################## #What icon information should be used when the time is shown on a non-Transporter using the large font. #Set to 7 for current condition icon only #Set to 1 for current condition and hi/low and precip. info #Set to 12 for no icons or hi/low and precip info. my $largeFontTimeIcon = 7; my $weatherFormat1t = '%w DP:%d P:%p'; # default Weather display format - Line 1 display 1 my $weatherFormat1b = '%t/%h %1'; # default Weather display format - Line 2 display 1 my $weatherFormat2t = 'DP:%d P:%p'; # default Weather display format - Line 1 display 2 my $weatherFormat2b = '%t/%h/%w'; # default Weather display format - Line 2 display 2 my $stockFormat1 = '%n'; my $stockFormat2 = '%l %c %z %v'; my $line1; #Used to store previous value of display line 1 during ticker display my $killTicker = 0; #Flag used to exit out of ticker mode my $windspeedUnit = 0; #0 for miles, 1 for kilometers my $show_averages = 0; #Show averages my $temptype = 0; my $status = ''; #Used for the status indicator my $overlay = ''; #Used to show alarm indicator my $timeoffset = 0; #Time zone offset from eastern time my $city = 60614; #Defaults to Chicago my $wunderIdent = ''; #wundgerground identifier my $showtime = 5; #How long to show the time when no games are active my $showgame = 3; #How long to show an upcoming/completed game my $showactivetime = 5; #How long to show the time when games are active my $showactivegame = 3; #How long to show an active game my $activeGames = 0; #Flag set if any games are active my $newActiveGames; #Flag set during a data refresh if any games are active my $lweather = 1; #Used to determine when long forecasts are displayed my $scrollType = 'Slide'; #Type of display scrolling between games my $cbballconf = 0; #NCAA BBALL conference file to retrieve my $cfballconf = 0; #NCAA FBALL conference file to retrieve my $stocks; #Stocks being tracked by ticker my $errorCount = 0; #Used to keep track of network errors my $refreshint = 5; #Time interval between data refreshes (in minutes) my $refreshCounter; #How many data refreshes are still active my $activeClients = 0; #Number of players currently displaying SuperDateTime my %nowshowing; my %weathershowing; #Used for when the user chooses to just view the long weather forecasts via remote my %topNowShowing; #Which item is being shown on top line during time display my %displayGameID; #Current game number displaying by sport my %displayLine1; #What is currently being shown on the display line 1 my %displayLine2; #What is currently being shown on the display line 2 my $weatherString1b = '%1'; #Display the time initially my $weatherString2t = ''; my $weatherString2b = ''; my $showGraphics = 1; #Track the average high/low for today/tomorrow my %averages = (); $averages{'last'} = ""; # prep for data reload my $teamLogos = '0'; #Show graphical team logos #Arrays to contain bottom display lines for each sport my @MLBdisplayItems1 = (); my @MLBdisplayItems2 = (); my @divideMLB = (); #Array used to divide MLB processing my @NBAdisplayItems1 = (); my @NBAdisplayItems2 = (); my @NHLdisplayItems1 = (); my @NHLdisplayItems2 = (); my @NFLdisplayItems1 = (); my @NFLdisplayItems2 = (); my @CBBdisplayItems1 = (); my @CBBdisplayItems2 = (); my @CFBdisplayItems1 = (); my @CFBdisplayItems2 = (); my @WETdisplayItems1 = (); #Not currently used. Convert TOPdisplayItems to use this? my @WETdisplayItems2 = (); my @STKdisplayItems1 = (); #Line 1 for stocks my @STKdisplayItems2 = (); #Line 2 for stocks my @displayItems2; $displayItems2[0] =\@MLBdisplayItems2; $displayItems2[1] =\@NBAdisplayItems2; $displayItems2[2] =\@NHLdisplayItems2; $displayItems2[3] =\@NFLdisplayItems2; $displayItems2[4] =\@CBBdisplayItems2; $displayItems2[5] =\@CFBdisplayItems2; $displayItems2[6] =\@STKdisplayItems2; $displayItems2[7] =\@WETdisplayItems2; my @displayItems1; $displayItems1[0] =\@MLBdisplayItems1; $displayItems1[1] =\@NBAdisplayItems1; $displayItems1[2] =\@NHLdisplayItems1; $displayItems1[3] =\@NFLdisplayItems1; $displayItems1[4] =\@CBBdisplayItems1; $displayItems1[5] =\@CFBdisplayItems1; $displayItems1[6] =\@STKdisplayItems1; $displayItems1[7] =\@WETdisplayItems1; my @TOPdisplayItems = (); #Array for top line display items shown with time my @precipItems = (); my @btmLinePreSpace = (); #Array of blank spaces to append before bottom line text my $iconPreSpace = ' '; #Blank spaces to append before bottom line text when displaying an icon w/3line txt my $icon2PreSpace = ' '; #Blank spaces to append before bottom line text when displaying an icon wo/3line txt #Arrays to contain the display intervals for corresponding display lines my @MLBdisplayIntervals = (); my @NBAdisplayIntervals = (); my @NHLdisplayIntervals = (); my @NFLdisplayIntervals = (); my @CBBdisplayIntervals = (); my @CFBdisplayIntervals = (); #my @WETdisplayIntervals = (); #STUB --NOT CURRENTLY USED my @STKdisplayIntervals = (); my @displayIntervals; $displayIntervals[0] =\@MLBdisplayIntervals; $displayIntervals[1] =\@NBAdisplayIntervals; $displayIntervals[2] =\@NHLdisplayIntervals; $displayIntervals[3] =\@NFLdisplayIntervals; $displayIntervals[4] =\@CBBdisplayIntervals; $displayIntervals[5] =\@CFBdisplayIntervals; $displayIntervals[6] =\@STKdisplayIntervals; #$displayIntervals[7] =\@WETdisplayIntervals; #STUB --NOT CURRENTLY USED my @refreshTracker = (); #Used to keep track of which fields to continue to refresh my $lastRefresh = ''; #Date that pertains to @refreshTracker data #Arrays to contain the user selected teams to monitor for each sport my @MLBteams = (); my %MLBmap = ('Cubs' => 10, 'White Sox' => 11, 'Atlanta' => 12, 'San Francisco' => 13, 'LA Angels' => 14, 'Detroit' => 15, 'Houston' => 16, 'Cincinnati' => 17, 'Arizona' => 18, 'Minnesota' => 19, 'Tampa Bay' => 20, 'Boston' => 21, 'Cleveland' => 22, 'Texas' => 24, 'NY Yankees' => 25, 'Baltimore' => 26, 'Toronto' => 27, 'Kansas City' => 28, 'Oakland' => 29, 'Seattle' => 30, 'Pittsburgh' => 31, 'NY Mets' => 32, 'Philadelphia' => 33, 'Florida' => 34, 'Washington' => 35, "Milwaukee" => 36, 'St. Louis' => 37, 'LA Dodgers' => 38, 'San Diego' => 39, 'Colorado' => 40 ); #Graphical icon mapping my @NBAteams = (); my @NHLteams = (); my @NFLteams = (); my %NFLmap = ('Chicago' => 10, 'Detroit' => 11, 'Green Bay' => 12); my @CBBteams = (); my @CFBteams = (); #Graphical display stuff my %xmax = (); my %ymax = (); my @forecastG = (); my @forecastIcon = (); my %hashDisp; my $gxwidth = 125; # # Map ASCII characters to custom @Charset elements # my %Codepage = ( ' ' => 0, '1' => 1, '2' => 2, '3' => 3, '4' => 4, '5' => 5, '6' => 6, '7' => 7, '8' => 8, '9' => 9, '0' => 10, '-' => 11, 'g' => 12, '.' => 13, '%' => 14, 'A' => 15, 'B' => 16, 'C' => 17, 'D' => 18, 'E' => 19, 'F' => 20, 'G' => 21, 'H' => 22, 'I' => 23, 'J' => 24, 'K' => 25, 'L' => 26, 'M' => 27, 'N' => 28, 'O' => 29, 'P' => 30, 'Q' => 31, 'R' => 32, 'S' => 33, 'T' => 34, 'U' => 35, 'V' => 36, 'W' => 37, 'X' => 38, 'Y' => 39, 'Z' => 40, '/' => 41 ); # # Custom 7x5 mono charset for 3-line forecast display on Squeezebox2 # my @Charset = (' ',' * ** * * * * * ***** ',' *** * * * * * * ***** ',' *** * * * ** * * * *** ',' * ** * * ***** * * * ',' ***** * * **** * * * *** ',' *** * * **** * * * * *** ',' ***** * * * * * * ',' *** * * * * *** * * * * *** ',' *** * * * * **** * * *** ',' *** * * * * * * * * * * *** ',' **** ',' ** * * * * ** ',' ** ** ',' ** ** * * * * * ** ** ',' *** * * * * ***** * * * * * * ',' **** * * * * **** * * * * **** ',' *** * * * * * * * *** ',' **** * * * * * * * * * * **** ',' ***** * * **** * * ***** ',' ***** * * **** * * * ',' *** * * * * *** * * * * *** ',' * * * * * * ***** * * * * * * ',' *** * * * * * *** ',' * * * * * * * *** ',' * * * * * * ** * * * * * * ',' * * * * * * ***** ',' * * ** ** * * * * * * * * * * * ',' * * * * ** * * * * * ** * * * * ',' *** * * * * * * * * * * *** ',' **** * * * * **** * * * ',' *** * * * * * * * * * * * * ** ** * ',' **** * * * * **** * * * * * * ',' **** * * *** * * **** ',' ***** * * * * * * ',' * * * * * * * * * * * * *** ',' * * * * * * * * * * * * * ',' * * * * * * * * * * * ** ** * * ',' * * * * * * * * * * * * * ',' * * * * * * * * * * ',' ***** * * * * * ***** ',' * * * * * '); # # map standard weather.com icons to custom icons # my %Iconmap = ( '1' => 2, '2' => 2, '3' => 2, '4' => 2, '5' => 23, '6' => 27,'7' => 24,'8' => 3, '9' => 1, '10' => 3, '11' => 25,'12' => 1, '13' => 18,'14' => 3, '15' => 19, '16' => 20,'17' => 2, '18' => 26,'19' => 32,'20' => 33, '21' => 10,'22' => 9, '23' => 11,'24' => 11,'25' => 30, '26' => 0, '27' => 14,'28' => 6, '29' => 13,'30' => 5, '31' => 12,'32' => 4, '33' => 13,'34' => 5, '35' => 2, '36' => 31,'37' => 8, '38' => 8, '39' => 7, '40' => 28, '41' => 21,'42' => 22,'43' => 22,'44' => 9, '45' => 15, '46' => 16,'47' => 17,'48' => 29, '0' => 2, 'na' => 9, 'NA' => 9, 'N/A' => 9 ); # # Custom weather condition icons (40x32 pixel) # #234567890123456789012345678901234567890 - icon 0 my @Icons = (' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** ', #234567890123456789012345678901234567890 - icon 1 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 2 ' **** **** **** **** ** ** ** ** ** ** ** ** *** * ** *** ** **** ** * ** ** ** * ** ** ** * ** *** * ** ** ** * ****** * ** *** ** ** *** ** ** ****************************** ** ** * ** * * * * ** * * * * **** * * * * ***** * * * * * ** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 3 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * *** * * *** * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 4 ' * * * * * * * * * * * * * * * ** * * ***** * ** ********* ** *********** * ************* ************* *************** *************** *************** ******* *************** *************** *** ************* **** ************* *********** ********* ***** * * * ** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 5 ' * * * * * * * * * * * * * * * ** * * ***** * ** ********* ** *********** **** * ********** ** * ********* ** ********* * ** ******* * * ****** ** ***** ** ***** * *** ***** * **** ************************* *********** ********* ***** * * * ** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 6 ' * * * * * * * * * * * * * **** ******* **** **** ********* **** ************ ** ** ************ ** ** *********** ** ********** * *** ***** **** * **** ** *** * ** *** ** * *** ** * ** * * ** ** *** ** ****************************** ', #234567890123456789012345678901234567890 - icon 7 ' * * * * * * * * * * * * * **** ******* **** **** ********* **** ************ ** ** ************ ** ** *********** ** ********** * *** ***** **** * **** ** *** * ** *** ** * *** ** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 8 ' * * * * * * * * * * * * * **** ******* **** **** ********* **** ************ ** ** ************ ** ** *********** ** ** ********** * ** *** ***** **** ** * **** ** ** *** * ** ** *** ** * ** *** ** * ** ** ** * ****** * ** *** ** ** *** ** ** ****************************** ** ** * ** * * * * ** * * * * **** * * * * ***** * * * * * ** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 9 ' ***** ********* *** *** * *** *** *** **** **** **** **** *** *** *** *** *** *** *** *** ', #234567890123456789012345678901234567890 - icon 10 ' ** ** * ****** ** ** ** ** *** ** ** ** ** ** * * ** ** ** ******* ** * ** *** ** ** ***** ** * ** ** * * ** * ** ** * * ** * ** ** * * ******** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 11 - Windy - Thanks Yannzola ' * ***** ** ** ** ** ** * ****** * **** ****** * ** ****** **** * ****** ** ******* ********** ** ********** * ********** * ********** ********** ** ************** *** ************** ****************** ************** ************** **************** ******* ***************** ** ** ** * ** ** ** * * ** * ** ** * * ** ***** ** ** ** ** ** ************ ** *** * * * ************************ * ** *** ***************************** ', #234567890123456789012345678901234567890 - icon 12 ' ***** ** ** * * * * * ** * * * * * * * * * * ** * * ** * *** * *** * * ** ** * ** *** * **** * * ** ** ** ***** ', #234567890123456789012345678901234567890 - icon 13 ' ***** ** ** * ** **** * * ** * * * ** * ** * ** * * * * * * ** * * ** * * * * * * * ********************* * * ** ** ***** ', #234567890123456789012345678901234567890 - icon 14 ' ***** **** ** ** **** **** * * **** ** * ** ** * ** ** * ** ** *** * * *** ** * **** * * * ** ** ** ** * *** * ** * * ** ** *** ** ****************************** ', #234567890123456789012345678901234567890 - icon 15 ' ***** **** ** ** **** **** * * **** ** * ** ** * ** ** * ** ** *** * * *** ** * **** * * * ** ** ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 16 ' ***** **** ** ** **** **** * * **** ** * ** ** * ** ** * ** ** *** * * *** ** * **** * * * ** ** ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * *** * * *** * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 17 ' ***** **** ** ** **** **** * * **** ** * ** ** * ** ** * ** ** ** *** * * ** *** ** * **** ** * * * ** ** ** ** ** ** * ** *** * ** ** ** * ****** * ** *** ** ** *** ** ** ****************************** ** ** * ** * * * * ** * * * * **** * * * * ***** * * * * * ** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 18 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * *** * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 19 ' * * * * * * * * * *** * * * * * * * * * * * * * * * * * * * * * * * * * * * * *** * * *** * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 20 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * ** * * * * * * * * * * * * * *** * * *** * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 21 ' * * * * * * * * * * * * * **** ******* **** **** ********* **** ************ ** ** ************ ** ** *********** ** ********** * *** ***** **** * **** ** *** * ** *** ** * *** ** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * *** * * *** * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 22 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * *** * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *** * * *** * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 23 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * *** * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 24 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *** * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 25 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 26 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 27 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 28 ' **** **** **** **** ** ** ** ** ** ** ** *** * *** ** **** * ** ** * ** ** * *** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 29 ' * * * * * * * * * * * * * **** ******* **** **** ********* **** ************ ** ** ************ ** ** *********** ** ********** * *** ***** **** * **** ** *** * ** *** ** * *** ** * ** * * ** ** *** ** ****************************** * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * ', #234567890123456789012345678901234567890 - icon 30 Frigid - Thanks Yannzola ' ***** * ** ** * * * * * * * *** * *** * *** * * * * ***** * * ** * * *** * * * * * * * * *** * *** * * * *** * * * **** * **** * ** * *** * ** * * * *** *** * *** *** * *** * *** *** * *** *** * * * ***** * ** * *** * * * ***** * *** * *** *** * *** *** * * * *** *** * *** *** * ** * *** * *** * * * **** * **** * *** * *** * * * *** ** *** ** * * * * ***** * * *** * * ***** * * ***** * * ***** * *** * *** ** *** ** * * * ** ** * ***** * ', #234567890123456789012345678901234567890 - icon 31 HOT - Thanks Yannzola ' * ***** * ** ** * * * * * * * *** * * * * * * * * * * * *** * * * * *** * * ***** * * *** * ********* * *** * *********** * *** * ************* * *** * ************* * *** * *************** * *** * *************** * *** * ****** *************** ****** * *** * *************** * *** * *************** * *** * ************* * *** * ************* * *** * *********** * *** * ********* ** *** ** * ***** * * ***** * * * * ***** * * * * * ***** * * * * ** *** ** * * * ** ** * ***** * * ', #234567890123456789012345678901234567890 - icon 32 Dust - Thanks Yannzola ' ******* ** ** ** * * * ** ****** * * * ** * * ** * ***** * * * * ** * * * ** ***** * * ** * ****** * * ** * * ** ** * * ** ** * * * * * * * ***** * * * * **** ** * **** * ** ** * ** * * * * * *** ** * * * ****** * * **** * * * * ** ** * ** *** * * * * ****** * * * * * ** * * **** *** ** * ** ****** ** ** ****** ', #234567890123456789012345678901234567890 - icon 33 Fog - Thanks Yannzola ' *********************************** *********************************** *********************************** ********* *********** *********************************** *************** *************** *********************************** *************** *********************************** *********************************** ********* *********************************** *********************************** *********************************** *********************************** *********************************** '); my $TWClogo = ' ************************ ************************ ************************ ************************ ************************ ************************ * ******************* ** * *** ************** ** * * * ************* ** * * * *************** ** * * ** ************* ************************ * * * ****** ** ******** * * * * * * * ** * * * * * ** ** * ** ** * * ** ** * ** ** ** * ** * * * ** ************************ ** **************** ** * ** * * * * ** ** * ** * ** * * * * ** * ** * * * * *** ** ** * * * * * ** * ************************ * * * * * * ** ***** * ** ** * ** * * * **** * * * * *** * * * ** * * ** *** *** * * * * * * * ** * * * * ***** *** * ** * ** ** * * * * '; ################################################## ### Super Functions ### ################################################## sub initPlugin { # Get previous settings or set default if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_city") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_city", $city); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_wunder") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_wunder", $wunderIdent); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_weatherformat1t") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_weatherformat1t", $weatherFormat1t); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_weatherformat1b") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_weatherformat1b", $weatherFormat1b); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_weatherformat2t") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_weatherformat2t", $weatherFormat2t); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_weatherformat2b") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_weatherformat2b", $weatherFormat2b); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_stock1format") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_stock1format", $stockFormat1); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_stock2format") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_stock2format", $stockFormat2); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_refresh") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_refresh", $refreshint); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_time") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_time", $showtime); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_score") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_score", $showgame); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_atime") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_atime", $showactivetime); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_ascore") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_ascore", $showactivegame); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_offset") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_offset", $timeoffset); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_temperature") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_temperature", $temptype); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_windunit") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_windunit", $windspeedUnit); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_averages") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_averages", $show_averages); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_scroll") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_scroll", $scrollType); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_teamlogos") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_teamlogos", $teamLogos); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_stocks") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_stocks", $stocks); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_lweather") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_lweather", $lweather); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_cbballconf") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_cbballconf", $cbballconf); } if (Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_cfballconf") eq "") { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_cfballconf", $cfballconf); } #Set local variables $city = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_city"); $wunderIdent = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_wunder"); $weatherFormat1t = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_weatherformat1t"); $weatherFormat1b = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_weatherformat1b"); $weatherFormat2t = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_weatherformat2t"); $weatherFormat2b = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_weatherformat2b"); $stockFormat1 = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_stock1format"); $stockFormat2 = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_stock2format"); $timeoffset = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_offset"); $temptype = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_temperature"); $windspeedUnit = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_windunit"); $show_averages = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_averages"); $showtime = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_time"); $showactivetime = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_atime"); $showgame = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_score"); $showactivegame = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_ascore"); $lweather = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_lweather"); $refreshint = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_refresh"); $scrollType = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_scroll"); $stocks = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_stocks"); $teamLogos = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_teamlogos"); $cbballconf = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_cbballconf"); $cfballconf = Slim::Utils::Prefs::get("plugin_screensaver_superdatetime_cfballconf"); @MLBteams = Slim::Utils::Prefs::getArray("plugin_screensaver_superdatetime_mlb"); if (scalar(@MLBteams) == 0) { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_mlb", \@MLBteams); } @NBAteams = Slim::Utils::Prefs::getArray("plugin_screensaver_superdatetime_nba"); if (scalar(@NBAteams) == 0) { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_nba", \@NBAteams); } @NHLteams = Slim::Utils::Prefs::getArray("plugin_screensaver_superdatetime_nhl"); if (scalar(@NHLteams) == 0) { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_nhl", \@NHLteams); } @NFLteams = Slim::Utils::Prefs::getArray("plugin_screensaver_superdatetime_nfl"); if (scalar(@NFLteams) == 0) { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_nfl", \@NFLteams); } @CBBteams = Slim::Utils::Prefs::getArray("plugin_screensaver_superdatetime_cbb"); if (scalar(@CBBteams) == 0) { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_cbb", \@CBBteams); } @CFBteams = Slim::Utils::Prefs::getArray("plugin_screensaver_superdatetime_cfb"); if (scalar(@CFBteams) == 0) { Slim::Utils::Prefs::set("plugin_screensaver_superdatetime_cfb", \@CFBteams); } } sub FtoC { my $temp = shift; $temp = ($temp-32)*5/9; $temp = int($temp + .5 * ($temp <=> 0)); #Funky round return $temp; } sub getAverages { #Set up Async HTTP request for averages my $days_advance = shift || 0; my $dayNum = ""; if ($days_advance > 0) { $dayNum = "?dayNum=$days_advance"; } my $url = 'http://www.weather.com/weather/wxdetail/' . $city . $dayNum; # tomorrow ### http://www.weather.com/weather/wxdetail/95616?dayNum=1 my $http = Slim::Networking::SimpleAsyncHTTP->new(\&gotAverages, \&gotErrorViaHTTP, { caller => 'getAverages'}); $::d_plugins && msg("SuperDateTime: async request: $url\n"); $http->get($url); } sub gotAverages { #Average data was received my $http = shift; $::d_plugins && msg("SuperDateTime: got " . $http->url() . "\n"); my $dayNum = 0; if ($http->url() =~ m/\?dayNum=(\d+)/) { $dayNum = $1; } my $content = $http->content(); #Avg. High: #75°F # # #Record High: #95°F (2004)/, split("\n", $content)); #$::d_plugins && msg("SuperDateTime: " . join("\n", @vbgA) . "\n"); if ($content =~ m/CLASS="blueFont10" ALIGN="LEFT">Avg. High:<\/TD>.*?(\d+)°(F|C)<\/B><\/TD>/s) { $averages{$dayNum}{'average_high_F'} = $1; } if ($content =~ m/CLASS="blueFont10" ALIGN="LEFT">Record High:<\/TD>.*?(\d+)°(F|C) \((\d+)\)<\/B><\/TD>/s) { $averages{$dayNum}{'record_high_F'} = $1; $averages{$dayNum}{'record_high_year'} = $3; } if ($content =~ m/CLASS="blueFont10" ALIGN="LEFT">Avg. Low:<\/TD>.*?(\d+)°(F|C)<\/B><\/TD>/s) { $averages{$dayNum}{'average_low_F'} = $1; } if ($content =~ m/CLASS="blueFont10" ALIGN="LEFT">Record Low:<\/TD>.*?(\d+)°(F|C) \((\d+)\)<\/B><\/TD>/s) { $averages{$dayNum}{'record_low_F'} = $1; $averages{$dayNum}{'record_low_year'} = $3; } } sub getWeather { #Set up Async HTTP request for Weather my $timerObj = shift; #Should be undef my $client = shift; my $url = 'http://www.weather.com/weather/local/' . $city; my $http = Slim::Networking::SimpleAsyncHTTP->new(\&gotWeather, \&gotErrorViaHTTP, {caller => 'getWeather', client => $client}); $::d_plugins && msg("SuperDateTime: async request: $url\n"); $http->get($url); } sub gotWeather { #Weather data was received my $http = shift; my $params = $http->params(); my $client = $params->{'client'}; #$::d_plugins && msg("SuperDateTime: GOTWEATHER CLIENT: $client\n"); my $temperatureF; my $temperatureC; my $feelslikeF; my $feelslikeC; my $dewpointF; my $dewpointC; my $humidity; my $pressureIN; my $pressureMB; my $pressureT; #Pressure trend my $windspeed; $::d_plugins && msg("SuperDateTime: got " . $http->url() . "\n"); #$::d_plugins && msg("SuperDateTime: content type is " . $http->headers()->{'Content-Type'} . "\n"); my $content = $http->content(); my @ary=split /\n/,$content; #break large string into array my @forecastTemps = (); #Temperature numeric values my @skyConditions = (); #Cloudy/etc my @forecastTypes = (); #High/low my @forecastNames = (); #Today/tonight/etc my @forecastDescs = (); #Long text forecast my $skyCondition = ''; #Current sky condition (cloudy/etc) @TOPdisplayItems = (); @precipItems = (); #Wipe old precip values @forecastIcon = (); #Wipe old icons @forecastG = (); #Wipe old forecast graphics @btmLinePreSpace = (); #Wipe old bottom line pre spaces (although they probably wont change) for (@ary) { if (/obsTempTextA>(-*\d+)\s*°\;F.+Feels Like
\s*(-*\d+)\s*\&d/) { $temperatureF = $1; $feelslikeF = $2; $temperatureC = FtoC($temperatureF); $feelslikeC = FtoC($feelslikeF); } elsif (/obsTempTextA"*>(-*\d+)\s*°\;F/) { #Some html has actual/feels like separated $temperatureF = $1; $temperatureC = FtoC($temperatureF); } elsif (/Feels Like\s*(-*\d+)\s*\&d/) { #Some html has actual/feels like separated $feelslikeF = $1; $feelslikeC = FtoC($feelslikeF); } elsif (/(\d+%)<\/td>/) { $humidity = $1; } elsif (/class="crowval">(\d+%)<\/div>/) { $humidity = $1; } elsif (/From (.+) at (\d+) mph/) { if ($windspeedUnit == 0) { #miles/hr $windspeed = $1 . $2; } elsif ($windspeedUnit == 1) { #km/hr $windspeed = $2*1.609344; $windspeed = $1 . int($windspeed + .5 * ($windspeed <=> 0)); #Funky round } elsif ($windspeedUnit == 3) { #m/s $windspeed = $2*16.09344/36; $windspeed = $1 . int($windspeed + .5 * ($windspeed <=> 0)); #Funky round } else { #kt/hr $windspeed = $2/1.1515; $windspeed = $1 . int($windspeed + .5 * ($windspeed <=> 0)); #Funky round } } elsif (/CLASS="obsTextA">CALM/) { $windspeed = "Calm"; } elsif (/Wind:<\/div>
CALM/) { $windspeed = "Calm"; } elsif (/wxicons\/52\/(\d+).png.*class="obsTextA">(.+)<\/strong/) { $skyCondition = $2; #Text $forecastIcon[0] = $1; #Date $forecastIcon[1] = $1; #Current } elsif (/wxicons\/52\/(\d+).gif.*
(.+)<\/B><\/TD>/) { $skyCondition = $2; #Text $forecastIcon[0] = $1; #Date $forecastIcon[1] = $1; #Current } elsif (/>(\d+.\d+) \;in..*\/(.*)_pressure/) { #Bar. pressure value $pressureIN = $1; $pressureMB = $1 * 33.8639; $pressureMB = int($pressureMB + .5 * ($pressureMB <=> 0)); #Funky round if ($2 eq 'steady') { $pressureT = '~'; } elsif ($2 eq 'down') { $pressureT = '-'; } else { $pressureT = '+'; } } elsif (/>(\d+.\d+) \;in./) { #Bar. pressure value $pressureIN = $1; $pressureMB = $1 * 33.8639; $pressureMB = int($pressureMB + .5 * ($pressureMB <=> 0)); #Funky round } elsif (/up_pressure/) { #Bar. pressure trend $pressureT = '+'; } elsif (/steady_pressure/) { #Bar. pressure trend $pressureT = '~'; } elsif (/down_pressure/) { #Bar. pressure trend $pressureT = '-'; } elsif (/(\d+)°\;F<\/td>/) { #Dew point $dewpointF = $1; $dewpointC = FtoC($dewpointF); } elsif (/Dew Point:<\/div>
(-?\d+)°\;F/) { #Dew point $dewpointF = $1; $dewpointC = FtoC($1); } elsif (/(\d+)° F<\/nobr><\/font><\/td>/) { if ($temptype == 0) { #Fahrenheit push(@forecastTemps, $1); } else { #Celsius my $temp = ($1-32)*5/9; $temp = int($temp + .5 * ($temp <=> 0)); #Funky round push(@forecastTemps, $temp); } } elsif (/wxicons\/31\/(\d+).gif/) { push(@forecastIcon, $1); } elsif (/(.+)<\/font><\/td>/) { push(@skyConditions, $1); } elsif (/(.+)
/) { push(@forecastTypes, uc($1)); } elsif (/class="whiteArialLink11">(.+)<\/font><\/B><\/A>/) { push(@forecastNames, $1); } elsif (/
(.+ )(\d+)(F|s)(.*\.+)/) { my $tempSymbol; my $firstHalf; #Temperature will either be a specific number (50F) or a group (50s) if ($3 eq 'F') { $tempSymbol = '°'; } else { $tempSymbol = 's'; } if ($temptype == 0) { #Fahrenheit $firstHalf = $1 . $2 . $tempSymbol; #push(@forecastDescs, $1 . $2 . $tempSymbol . $4 . $wind . $7); } else { #Celsius my $temp = ($2-32)*5/9; $temp = int($temp + .5 * ($temp <=> 0)); #Funky round $firstHalf = $1 . $temp . $tempSymbol; #push(@forecastDescs, $1 . $temp . $tempSymbol . $4 . $wind . $7); } if ($4 =~ /(.*at )(\d+) to (\d+) mph(.*\.+)/) { #Wind portion my $wind; if ($windspeedUnit== 0) { #miles/hr $wind = $2 . ' to ' . $3 . ' mph'; } elsif ($windspeedUnit == 1) { #km/hr my $wind1; my $wind2; $wind1 = $2*1.609344; $wind1 = int($wind1 + .5 * ($wind1 <=> 0)); #Funky round $wind2 = $3*1.609344; $wind2 = int($wind2 + .5 * ($wind2 <=> 0)); #Funky round $wind = $wind1 . ' to ' . $wind2 . ' km/hr'; } elsif ($windspeedUnit == 3) { #m/s my $wind1; my $wind2; $wind1 = $2*16.09344/36; $wind1 = int($wind1 + .5 * ($wind1 <=> 0)); #Funky round $wind2 = $3*16.09344/36; $wind2 = int($wind2 + .5 * ($wind2 <=> 0)); #Funky round $wind = $wind1 . ' to ' . $wind2 . ' m/s'; } else { #kt/hr my $wind1; my $wind2; $wind1 = $2/1.1515; $wind1 = int($wind1 + .5 * ($wind1 <=> 0)); #Funky round $wind2 = $3/1.1515; $wind2 = int($wind2 + .5 * ($wind2 <=> 0)); #Funky round $wind = $wind1 . ' to ' . $wind2 . ' kt'; } push(@forecastDescs, $firstHalf . $1 . $wind . $4); } else { #No wind numbers to convert push(@forecastDescs, $firstHalf . $4); } } elsif (/blueVerdanaText.*">(\d+%)<\/td>/) { #Precip if (scalar @precipItems ==0) { $precipItems[0] = 'PREC '.$1; #Date $precipItems[1] = 'PREC '.$1; #Current $precipItems[2] = 'PREC '.$1; } else { push(@precipItems, 'PREC '.$1); } } elsif (/
(.+\.)/) { #Description didn't parse $::d_plugins && msg("SuperDateTime: Error parsing weather forecast desc. \nTEXT:" . $1 . "\n"); push(@forecastDescs, $1 . '*'); } } my @minmax = (); if ($show_averages) { if ($forecastNames[0] ne $averages{'last'}) { $::d_plugins && msg("SuperDateTime: Average data refresh started.\n"); # average data is out of date, refresh getAverages(0); # for today/tonight getAverages(1); # for tomorrow/tomorrow night $averages{'last'} = $forecastNames[0]; } for (my $i = 0; $i <= $#forecastNames; $i++) { $minmax[$i] = ""; my $name = $forecastNames[$i]; sub buildMinMax { my ($average, $record, $record_year, $forecast) = @_; if (!$average || !$record || !$record_year || !$forecast) { return ""; } if ($temptype != 0) { #!Fahrenheit my $average = FtoC($average); my $record = FtoC($record); my $forecast = FtoC($forecast); } my $diff = $forecast - $average; if ($diff > 0) { $diff = "+$diff"; # force a leading + } return " (${diff}°) (${record}° $record_year)" } if ($name eq 'Today') { $minmax[$i] = buildMinMax($averages{0}{'average_high_F'}, $averages{0}{'record_high_F'}, $averages{0}{'record_high_year'}, $forecastTemps[$i]); } elsif ($name eq 'Tonight') { $minmax[$i] = buildMinMax($averages{0}{'average_low_F'}, $averages{0}{'record_low_F'}, $averages{0}{'record_low_year'}, $forecastTemps[$i]); } elsif ($name eq 'Tomorrow') { $minmax[$i] = buildMinMax($averages{1}{'average_high_F'}, $averages{1}{'record_high_F'}, $averages{1}{'record_high_year'}, $forecastTemps[$i]); } elsif ($name eq 'Tomorrow Night') { $minmax[$i] = buildMinMax($averages{1}{'average_low_F'}, $averages{1}{'record_low_F'}, $averages{1}{'record_low_year'}, $forecastTemps[$i]); } else { $::d_plugins && msg("SuperDateTime: ERROR, unknown name: $name\n"); } } } #Draw/cache icons for each top line mode my $hilow; # Top location *0 and 1* if ($forecastTypes[0] eq "LOW") { $hilow = ' LOW '; } else { $hilow = $forecastTypes[0].' '; } clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[0]}]); drawText($client,42,$ymax{$client}-25,$precipItems[0]); drawText($client,42,$ymax{$client}-13,$hilow.$forecastTemps[0].'g'); $btmLinePreSpace[0] = $iconPreSpace; $forecastG[0] = getFramebuf($client,$gxwidth); #Date $forecastG[1] = $forecastG[0]; #Current #push(@TOPdisplayItems, Slim::Utils::Misc::longDateF()); #Long date push(@TOPdisplayItems, Slim::Utils::DateTime::longDateF(undef,Slim::Utils::Prefs::get('dateFormat'))); push(@TOPdisplayItems, 'Currently: '.$skyCondition); #Current conditions $btmLinePreSpace[0] = $iconPreSpace; $btmLinePreSpace[1] = $iconPreSpace; # Top location *2* clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[2]}]); drawText($client,42,$ymax{$client}-25,$precipItems[2]); drawText($client,42,$ymax{$client}-13,$hilow.$forecastTemps[0].'g'); $forecastG[2] = getFramebuf($client,$gxwidth); push(@TOPdisplayItems, $forecastNames[0].': '.$skyConditions[0].$minmax[0]); $btmLinePreSpace[2] = $iconPreSpace; # Top location *3* if ($forecastTypes[1] eq "LOW") { $hilow = ' LOW '; } else { $hilow = $forecastTypes[1].' '; } clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[3]}]); drawText($client,42,$ymax{$client}-25,$precipItems[3]); drawText($client,42,$ymax{$client}-13,$hilow.$forecastTemps[1].'g'); $forecastG[3] = getFramebuf($client,$gxwidth); push(@TOPdisplayItems, $forecastNames[1].': '.$skyConditions[1].$minmax[1]); $btmLinePreSpace[3] = $iconPreSpace; # Top location *4* if ($forecastTypes[2] eq "LOW") { $hilow = ' LOW '; } else { $hilow = $forecastTypes[2].' '; } clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[4]}]); drawText($client,42,$ymax{$client}-25,$precipItems[4]); drawText($client,42,$ymax{$client}-13,$hilow.$forecastTemps[2].'g'); $forecastG[4] = getFramebuf($client,$gxwidth); push(@TOPdisplayItems, $forecastNames[2].': '.$skyConditions[2].$minmax[2]); $btmLinePreSpace[4] = $iconPreSpace; # Top location *5* #Custom top line with icon my $weatherString1t = $weatherFormat1t; for ($weatherString1t) { s/%t/$temperatureF°/; s/%T/$temperatureC°/; s/%w/$windspeed/; s/%h/$humidity/; s/%p/$pressureIN$pressureT/; s/%P/$pressureMB$pressureT/; s/%d/$dewpointF°/; s/%D/$dewpointC°/; s/%f/$feelslikeF°/; s/%F/$feelslikeC°/; } push(@TOPdisplayItems, $weatherString1t); $forecastG[5] = $forecastG[1]; #Custom line forecast is same as current conditions $btmLinePreSpace[5] = $iconPreSpace; # Icon but no 3line text # Top location *6 and 7* if ($forecastTypes[0] eq "LOW") { $hilow = ' LOW '; } else { $hilow = $forecastTypes[0].' '; } clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[0]}]); $btmLinePreSpace[6] = $iconPreSpace; $forecastG[6] = getFramebuf($client,$gxwidth); #Date $forecastG[7] = $forecastG[6]; #Current no 3line #push(@TOPdisplayItems, Slim::Utils::Misc::longDateF()); #Long date push(@TOPdisplayItems, Slim::Utils::DateTime::longDateF(undef,Slim::Utils::Prefs::get('dateFormat'))); push(@TOPdisplayItems, 'Currently: '.$skyCondition); #Current conditions $btmLinePreSpace[6] = $icon2PreSpace; $btmLinePreSpace[7] = $icon2PreSpace; # Top location *8* clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[2]}]); $forecastG[8] = getFramebuf($client,$gxwidth); push(@TOPdisplayItems, $forecastNames[0].': '.$skyConditions[0].$minmax[0]); $btmLinePreSpace[8] = $icon2PreSpace; # Top location *9* if ($forecastTypes[1] eq "LOW") { $hilow = ' LOW '; } else { $hilow = $forecastTypes[1].' '; } clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[3]}]); $forecastG[9] = getFramebuf($client,$gxwidth); push(@TOPdisplayItems, $forecastNames[1].': '.$skyConditions[1].$minmax[1]); $btmLinePreSpace[9] = $icon2PreSpace; # Top location *10* if ($forecastTypes[2] eq "LOW") { $hilow = ' LOW '; } else { $hilow = $forecastTypes[2].' '; } clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[4]}]); $forecastG[10] = getFramebuf($client,$gxwidth); push(@TOPdisplayItems, $forecastNames[2].': '.$skyConditions[2].$minmax[2]); $btmLinePreSpace[10] = $icon2PreSpace; # Top location *11* #Custom top line with no 3line my $weatherString1t = $weatherFormat1t; for ($weatherString1t) { s/%t/$temperatureF°/; s/%T/$temperatureC°/; s/%w/$windspeed/; s/%h/$humidity/; s/%p/$pressureIN$pressureT/; s/%P/$pressureMB$pressureT/; s/%d/$dewpointF°/; s/%D/$dewpointC°/; s/%f/$feelslikeF°/; s/%F/$feelslikeC°/; } push(@TOPdisplayItems, $weatherString1t); clearCanvas($client); drawIcon($client,0,$ymax{$client}-1, $Icons[$Iconmap{$forecastIcon[0]}]); $btmLinePreSpace[11] = $icon2PreSpace; $forecastG[11] = getFramebuf($client,$gxwidth); #Current #Top lines without icons # Top location *12* push(@TOPdisplayItems, $forecastNames[0].': '.$skyConditions[0].' - '.$forecastTypes[0].' '.$forecastTemps[0].'°'.$minmax[0]); # Top location *13* push(@TOPdisplayItems, $forecastNames[1].': '.$skyConditions[1].' - '.$forecastTypes[1].' '.$forecastTemps[1].'°'.$minmax[1]); # Top location *14* push(@TOPdisplayItems, $forecastNames[2].': '.$skyConditions[2].' - '.$forecastTypes[2].' '.$forecastTemps[2].'°'.$minmax[2]); # Top location *15* push(@TOPdisplayItems, $weatherString1t); #Custom top line, no icon @WETdisplayItems2 = (); push(@WETdisplayItems2, $forecastDescs[0]); push(@WETdisplayItems2, $forecastDescs[1]); push(@WETdisplayItems2, $forecastDescs[2]); if ($wunderIdent eq "") { $weatherString1b = $weatherFormat1b; for ($weatherString1b) { s/%t/$temperatureF°/; s/%T/$temperatureC°/; s/%w/$windspeed/; s/%h/$humidity/; s/%p/$pressureIN$pressureT/; s/%P/$pressureMB$pressureT/; s/%d/$dewpointF°/; s/%D/$dewpointC°/; s/%f/$feelslikeF°/; s/%F/$feelslikeC°/; } $weatherString2b = $weatherFormat2b; for ($weatherString2b) { s/%t/$temperatureF°/; s/%T/$temperatureC°/; s/%w/$windspeed/; s/%h/$humidity/; s/%p/$pressureIN$pressureT/; s/%P/$pressureMB$pressureT/; s/%d/$dewpointF°/; s/%D/$dewpointC°/; s/%f/$feelslikeF°/; s/%F/$feelslikeC°/; } $weatherString2t = $weatherFormat2t; for ($weatherString2t) { s/%t/$temperatureF°/; s/%T/$temperatureC°/; s/%w/$windspeed/; s/%h/$humidity/; s/%p/$pressureIN$pressureT/; s/%P/$pressureMB$pressureT/; s/%d/$dewpointF°/; s/%D/$dewpointC°/; s/%f/$feelslikeF°/; s/%F/$feelslikeC°/; } } $refreshCounter--; checkRefreshStatus(); } sub getWunderground { #Set up Async HTTP request for Weather my $url = 'http://www.wunderground.com/weatherstation/WXDailyHistory.asp?ID=' . $wunderIdent . '&format=1'; my $http = Slim::Networking::SimpleAsyncHTTP->new(\&gotWunderground, \&gotErrorViaHTTP, {caller => 'getWunderground'}); $::d_plugins && msg("SuperDateTime: async request: $url\n"); $http->get($url); } sub gotWunderground { #Weather data was received my $http = shift; my $temperatureF; my $temperatureC; my $dewpointF; my $dewpointC; my $humidity; my $pressureIN; my $pressureMB; my $pressureT; #Pressure trend my $windspeed; my $winddir; #Wind from direction $::d_plugins && msg("SuperDateTime: got " . $http->url() . "\n"); my $content = $http->content(); my @ary=split /\n/,$content; #break large string into array #$::d_plugins && msg("WU DATA: ".$ary[scalar(@ary)-3]."\n"); if($ary[scalar(@ary)-3] =~ /.*,(.*),(.*),(.*),(.*),.*,(.*),.*,(.*),.*,(.*),(.*),.*,.*,/) { $temperatureF = $1; $temperatureC = FtoC($temperatureF); $dewpointF = $2; $dewpointC = FtoC($dewpointF); $pressureIN = $3; $pressureMB = $3 * 33.8639; $pressureMB = int($pressureMB + .5 * ($pressureMB <=> 0)); #Funky round if ($5==0) { $windspeed = "Calm"; } else { $winddir = $4; if ($winddir eq "South") { $winddir = "S"; } elsif ($winddir eq "North") { $winddir = "N"; } elsif ($winddir eq "East") { $winddir = "E"; } elsif ($winddir eq "West") { $winddir = "W"; } if ($windspeedUnit == 0) { #miles/hr $windspeed = $winddir . $5; } elsif ($windspeedUnit == 1) { #km/hr $windspeed = $5*1.609344; $windspeed = $winddir . int($windspeed + .5 * ($windspeed <=> 0)); #Funky round } elsif ($windspeedUnit == 3) { #m/s $windspeed = $5*16.09344/36; $windspeed = $winddir . int($windspeed + .5 * ($windspeed <=> 0)); #Funky round } else { #kt/hr $windspeed = $5/1.1515; $windspeed = $winddir . int($windspeed + .5 * ($windspeed <=> 0)); #Funky round } } $humidity = $6 . '%'; #Current conditions is 7, clouds 8 } $weatherString1b = $weatherFormat1b; for ($weatherString1b) { s/%t/$temperatureF°/; s/%T/$temperatureC°/; s/%w/$windspeed/; s/%h/$humidity/; s/%p/$pressureIN$pressureT/; s/%P/$pressureMB$pressureT/; s/%d/$dewpointF°/; s/%D/$dewpointC°/; } $weatherString2b = $weatherFormat2b; for ($weatherString2b) { s/%t/$temperatureF°/; s/%T/$temperatureC°/; s/%w/$windspeed/; s/%h/$humidity/; s/%p/$pressureIN$pressureT/; s/%P/$pressureMB$pressureT/; s/%d/$dewpointF°/; s/%D/$dewpointC°/; } $weatherString2t = $weatherFormat2t; for ($weatherString2t) { s/%t/$temperatureF°/; s/%T/$temperatureC°/; s/%w/$windspeed/; s/%h/$humidity/; s/%p/$pressureIN$pressureT/; s/%P/$pressureMB$pressureT/; s/%d/$dewpointF°/; s/%D/$dewpointC°/; } $refreshCounter--; checkRefreshStatus(); } sub getStocks { #Set up Async HTTP request for Stocks my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday,$isdst) = localtime(time); my $offset = $timeoffset; while ($offset != 0) { if ($offset >0) { $offset = $offset -1; $hour = $hour -1; if ($hour == -1) { $hour = 23; $wday--; } } else { $offset = $offset +1; $hour = $hour +1; if ($hour == 24) { $hour = 0; $wday++; } } } #Market hours #After market hours but no market data from the day if (($stocks ne "" && $wday >0 && $wday <6 && $hour <18 && $hour >8)|| ($stocks ne "" && $wday >0 && $wday <6 && $hour >17 && (scalar @STKdisplayItems1 == 0))) { #Make sure stocks data is needed. Update from 9am to 5pm. my $url = 'http://finance.yahoo.com/d/quotes.csv?s=' . $stocks . '&f=sl1d1t1c1ohgvpn&e=.csv'; my $http = Slim::Networking::SimpleAsyncHTTP->new(\&gotStocks, \&gotErrorViaHTTP, {caller => 'getStocks'}); $::d_plugins && msg("SuperDateTime: async request: $url\n"); $http->get($url); } else { $refreshCounter--; checkRefreshStatus(); if ($hour <9 || $wday == 0 || $wday == 6) { #Make sure stock arrays are empty @STKdisplayItems1 = (); @STKdisplayItems2 = (); @STKdisplayIntervals = (); } } } sub gotStocks { #Stock data was received my $http = shift; @STKdisplayItems1 = (); @STKdisplayItems2 = (); @STKdisplayIntervals = (); $::d_plugins && msg("SuperDateTime: got " . $http->url() . "\n"); my $content = $http->content(); my @ary=split /\n/,$content; #break large string into array #$::d_plugins && msg("STOCK DATA: ".$ary[0]."\n"); for (@ary) { if(/"(.*)",(.*),"(.*)","(.*)",(.*),(.*),(.*),(.*),(.*),(.*),"(.*)"/) { my $ticker; my $name; my $lasttrade; my $lastdate; my $lasttime; my $change; my $open; my $high; my $low; my $volume; my $prev; my $pchange; $ticker = $1; $lasttrade = Slim::Utils::Misc::delimitThousands($2); $lastdate = $3; $lasttime = $4; $change = $5; $open = Slim::Utils::Misc::delimitThousands($6); $high = Slim::Utils::Misc::delimitThousands($7); $low = Slim::Utils::Misc::delimitThousands($8); $volume = $9; $prev = Slim::Utils::Misc::delimitThousands($10); if ($volume >1000000) { $volume = $volume / 1000000; $volume = sprintf("%.2f", $volume); $volume = Slim::Utils::Misc::delimitThousands($volume); $volume = $volume . 'M'; } else { $volume = Slim::Utils::Misc::delimitThousands($volume); } if ($ticker eq "^IXIC") { #Volume is not reported for Nasdaq composite $volume = ''; } if ($10 > 0) { $pchange = ($5/$10)*100; $pchange = sprintf("%.2f%", $pchange); } $name = $11; my $line1 = $stockFormat1; my $line2 = $stockFormat2; for ($line1) { s/%s/$ticker/; s/%l/$lasttrade/; s/%d/$lastdate/; s/%t/$lasttime/; s/%c/$change/; s/%o/$open/; s/%h/$high/; s/%w/$low/; s/%v/$volume/; s/%n/$name/; s/%p/$prev/; s/%z/$pchange/; } for ($line2) { s/%s/$ticker/; s/%l/$lasttrade/; s/%d/$lastdate/; s/%t/$lasttime/; s/%c/$change/; s/%o/$open/; s/%h/$high/; s/%w/$low/; s/%v/$volume/; s/%n/$name/; s/%p/$prev/; s/%z/$pchange/; } push(@STKdisplayItems1, $line1); push(@STKdisplayItems2, $line2); push(@STKdisplayIntervals, 5); } } $refreshCounter--; checkRefreshStatus(); } sub refreshSoon { #Disabled for now my $client = shift; #Clear previous display info #What about clearing line 1? @MLBdisplayItems2 =(); @NFLdisplayItems2 =(); @CBBdisplayItems2 =(); @CFBdisplayItems2 =(); @NBAdisplayItems2 =(); @NHLdisplayItems2 =(); @WETdisplayItems2 =(); @STKdisplayItems1 =(); @STKdisplayItems2 =(); @MLBdisplayIntervals =(); @NFLdisplayIntervals =(); @CBBdisplayIntervals =(); @CFBdisplayIntervals =(); @NBAdisplayIntervals =(); @NHLdisplayIntervals =(); @STKdisplayIntervals = (); #No need to refresh data unless there are active clients if ($activeClients >0) { Slim::Utils::Timers::killTimers(undef, \&refreshData); #Refresh in 7 seconds. Ensures settings are updated... Slim::Utils::Timers::setTimer(undef, Time::HiRes::time() + 7, \&refreshData, $client); } } sub refreshData { $::d_plugins && msg("SuperDateTime: Data refresh in progress...\n"); my $timerObj = shift; #Should be undef my $client = shift; $errorCount = 0; #Reset network error counter for new refresh #Update status indicator to show that a data refresh is in progress $status = '*'; $refreshCounter = 9; #Counter to keep track of how many items could be refreshing my $refreshDelay = 1.5; #Number of seconds to space inbetween timers to prevent hangs. my $cumlativeDelay = Time::HiRes::time() + $refreshDelay; #Incrementer for spacing timers. #Is this okay since old data is still being displayed? $newActiveGames = 0; #Reset active game flag for upcoming sports data refresh #Use timers to spread load to prevent server hangs #Weather.com Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getWeather, $client); #Do we need to take into account $isdst??? How do we figure out if East Coast is observing if located in timezone that doesnt observe? my ($mday,$mon,$year,$hour, $isdst) = (gmtime(time-(60*60*4)))[3,4,5,2,8]; #Figure out EST based on GMT time if ($mday < 10) { $mday = '0' . $mday; } $mon++; #Starts at 0 if ($mon < 10) { $mon = '0' . $mon; } $year = $year + 1900; $::d_plugins && msg("SuperDateTime: Eastern Hour/Date:$hour/$mday\n"); if ((($lastRefresh ne ($year . $mon . $mday)) && $hour >4) || $lastRefresh eq '') { #5AM EST start refreshing a new day @refreshTracker = (); $refreshTracker[0] = 1; #Need to refresh MLB again $refreshTracker[1] = 1; #Need to refresh NBA again $refreshTracker[2] = 1; #Need to refresh NHL again $lastRefresh = $year.$mon.$mday; } #WUnderground if ($wunderIdent ne "") { #Make sure wunderground data is needed $cumlativeDelay = $cumlativeDelay + $refreshDelay; Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getWunderground); } else { $refreshCounter--; } #MLB if (scalar(@MLBteams)>0 && $mon <11 && $mon >3 && $refreshTracker[0] !=0) { #Make sure a baseball team is chosen and its baseball season $cumlativeDelay = $cumlativeDelay + $refreshDelay; Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getMLB, $client); } else { $refreshCounter--; } #NFL if (scalar(@NFLteams)>0) { #Make sure a NFL team is chosen $cumlativeDelay = $cumlativeDelay + $refreshDelay; Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getNFL, $client); } else { $refreshCounter--; } #NBA if (scalar(@NBAteams)>0 && $refreshTracker[1] !=0) { #Make sure a basketball team is chosen $cumlativeDelay = $cumlativeDelay + $refreshDelay; Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getNBA); } else { $refreshCounter--; } #NHL if (scalar(@NHLteams)>0 && $refreshTracker[2] !=0) { #Make sure a hockey team is chosen $cumlativeDelay = $cumlativeDelay + $refreshDelay; Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getNHL); } else { $refreshCounter--; } #CBB if ((scalar(@CBBteams)>0) && ($cbballconf ne '0')) { #Make sure a college basketball team is chosen $cumlativeDelay = $cumlativeDelay + $refreshDelay; Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getCBB); } else { $refreshCounter--; } #CFB if (scalar(@CFBteams)>0 && ($cfballconf ne '0')) { #Make sure a team is chosen $cumlativeDelay = $cumlativeDelay + $refreshDelay; Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getCFB, $client); } else { $refreshCounter--; } #Stocks --Has more complex logic, leave this way for now... $cumlativeDelay = $cumlativeDelay + $refreshDelay; Slim::Utils::Timers::setTimer(undef, $cumlativeDelay, \&getStocks); Slim::Utils::Timers::killTimers(undef, \&refreshData); #Paranoia check Slim::Utils::Timers::setTimer(undef, Time::HiRes::time() + ($refreshint * 60), \&refreshData, $client); checkRefreshStatus(); #See if anything is still refreshing... } sub checkRefreshStatus { if ($newActiveGames == 1) { $activeGames = 1; } if ($refreshCounter == 0) { #Data refresh complete if ($status eq '*') { $::d_plugins && msg("SuperDateTime: Data refresh completed.\n"); $status = ''; } else { $::d_plugins && msg("SuperDateTime: Data refresh completed with errors.\n"); } $activeGames = $newActiveGames; } } sub getMLB { #Set up Async HTTP request for MLB my $timerObj = shift; #Should be undef my $client = shift; #my $url ='http://sports.espn.go.com/mlb/scoreboard?date=20060404'; my $url = 'http://scores.espn.go.com/mlb/scoreboard?date=' . $lastRefresh; #my $url = 'http://sports-ak.espn.go.com/mlb/scoreboard/printable/scoreboard_1_0_0?date=' . $year . $mon . $mday; my $http = Slim::Networking::SimpleAsyncHTTP->new(\&gotMLB, \&gotErrorViaHTTP, {caller => 'getMLB', client => $client}); $::d_plugins && msg("SuperDateTime: async request: $url\n"); $http->get($url); } sub gotMLB { my $http = shift; my $params = $http->params(); my $client = $params->{'client'}; @MLBdisplayItems1 = (); @MLBdisplayItems2 = (); @MLBdisplayIntervals = (); @divideMLB = (); $refreshTracker[0] = 0; $::d_plugins && msg("SuperDateTime: got " . $http->url() . "\n"); #$::d_plugins && msg("SuperDateTime: content type is " . $http->headers()->{'Content-Type'} . "\n"); my $content = $http->content(); #my @ary=split /teamTop/,$content; #break large string into array of games @divideMLB = split /teamTop/,$content; #break large string into array of games Slim::Utils::Timers::killTimers(undef, \&processMLB); #Just in case there's a rogue timer Slim::Utils::Timers::setTimer(undef, Time::HiRes::time() + .1, \&processMLB, $client); } sub processMLB { $::d_plugins && msg("SuperDateTime: Processing MLB game...\n"); my $timerObj = shift; #Should be undef my $client = shift; my $line = pop @divideMLB; my @todaysGames = split /\n/, $line; #break down to speed up regexp processing for (@todaysGames) { if (/>(\d+:\d+ .?M ET)<.+class="teamLine".+\d+">(.+)<\/a>.+teamLine".+id=\d+">(.+)<\/a><\/strong>/) { #Upcoming game #my $gametime = $1; my $team1 = $2; my $team2 = $3; if ((teamCheck($2, \@MLBteams)==1) || (teamCheck($3, \@MLBteams)==1)) { MLBdisplayLines($client,$1, $2, $3, '', ''); } } elsif (/\d">(.+)<\/td><\/tr>(.+)<\/a><\/strong>.+teamLine".+id=\d+">(.+)<\/a><\/strong>.+awayRunsTotal.+".*>(\d+)<\/td>(\d+)<\/td> 0) { #Slim::Utils::Timers::killTimers(undef, \&processMLB); #No way there are any right!?!? Slim::Utils::Timers::setTimer(undef, Time::HiRes::time() + .1, \&processMLB, $client); } else { $refreshCounter--; checkRefreshStatus(); } } sub teamCheck { my $teamToCheck = shift; my $teamArrayRef = shift; #Get rid of any ranking, if present (college). if ($teamToCheck =~ /(\(\d+\)) (.+)/) { $teamToCheck = $2; } my $endingValue = scalar(@$teamArrayRef); for(my $counter=0 ; $counter < $endingValue; $counter++) { if (($teamToCheck eq @$teamArrayRef[$counter]) || (@$teamArrayRef[$counter] eq '1') || (@$teamArrayRef[$counter] eq 'All') || (@$teamArrayRef[$counter] eq 'all')) { return 1; } } return 0; } sub MLBdisplayLines { #Figure out/Format display lines my ($client, $MLBgametime, $MLBteam1, $MLBteam2, $MLBscore1, $MLBscore2) = @_; $MLBgametime = convertTime($MLBgametime); #Clean up time display and convert to local time zone my $team1 = ''; my $team2 = ''; if ($teamLogos == 0) { #No logos $team1 = shortenMLB($MLBteam1); $team2 = shortenMLB($MLBteam2) } elsif ($teamLogos == 1) { #Logo no text if (defined $MLBmap{$MLBteam1}) { #Are there logos for team1? $team1 = $client->symbols('mlb-'.$MLBmap{$MLBteam1}); } else { #No logo available $team1 = shortenMLB($MLBteam1); } if (defined $MLBmap{$MLBteam2}) { #Are there logos for team2 $team2 = $client->symbols('mlb-'.$MLBmap{$MLBteam2}); } else { #No logo available $team2 = shortenMLB($MLBteam2); } } else { #Logo and text if (defined $MLBmap{$MLBteam1}) { #Are there logos for team1? $team1 = $client->symbols('mlb-'.$MLBmap{$MLBteam1}); } if (defined $MLBmap{$MLBteam2}) { #Are there logos for team2 $team2 = $client->symbols('mlb-'.$MLBmap{$MLBteam2}); } $team1 = $team1 . shortenMLB($MLBteam1); $team2 = $team2 . shortenMLB($MLBteam2); } if ($MLBscore1 eq '' && $showgame>0) { #upcoming game $refreshTracker[0] = 1; push(@MLBdisplayItems1, 'MLB'); push(@MLBdisplayItems2, $team1 . ' @ ' . $team2 . '-' . $MLBgametime); push(@MLBdisplayIntervals, $showgame); } elsif ($MLBgametime eq 'F' && $showgame>0) { #Finished game push(@MLBdisplayItems1, 'MLB'); push(@MLBdisplayItems2, $team1 . ' ' . $MLBscore1 . ' @ ' . $team2 . ' ' . $MLBscore2 . ' -' . $MLBgametime); push(@MLBdisplayIntervals, $showgame); } elsif ($MLBgametime ne 'F' && $showactivegame >0 && $MLBscore1 ne '') { #active game $refreshTracker[0] = 1; $newActiveGames = 1; push(@MLBdisplayItems1, 'MLB'); push(@MLBdisplayItems2, $team1 . ' ' . $MLBscore1 . ' @ ' . $team2 . ' ' . $MLBscore2 . ' -' . $MLBgametime); push(@MLBdisplayIntervals, $showactivegame); } } sub getNBA { #Set up Async HTTP request for NBA #my $url ='http://sports.espn.go.com/nba/scoreboard?date=20050623'; #my $url = 'http://sports.espn.go.com/nba/scoreboard?date=' . $year . $mon . $mday; my $url = 'http://sports.espn.go.com/nba/scoreboard?date=' . $lastRefresh; my $http = Slim::Networking::SimpleAsyncHTTP->new(\&gotNBA, \&gotErrorViaHTTP, {caller => 'getNBA'}); $::d_plugins && msg("SuperDateTime: async request: $url\n"); $http->get($url); } sub gotNBA { @NBAdisplayItems1 = (); @NBAdisplayItems2 = (); @NBAdisplayIntervals = (); $refreshTracker[1] = 0; my $team1 = ''; my $team2 = ''; my $gametime = ''; my $team1score =''; my $team2score =''; my $http = shift; #my $params = $http->params(); $::d_plugins && msg("SuperDateTime: got " . $http->url() . "\n"); #$::d_plugins && msg("SuperDateTime: content type is " . $http->headers()->{'Content-Type'} . "\n"); my $content = $http->content(); my @ary=split /\n/,$content; #break large string into array for (@ary) { if (/
.+-clock">(.+)<\/div><\/div>
(\d+)<\/div>
(.*)<\/a><\/div><\/div>