It is currently March 30th, 2020, 12:58 pm

Weather.com WXDATA feed failing again

General topics related to Rainmeter.
User avatar
jsmorley
Developer
Posts: 20425
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Weather.com WXDATA feed failing again

Post by jsmorley »

GTI.H wrote:
January 20th, 2020, 3:34 pm
I think the task is not limited to finding a free feed/API, the information provider has to provide reliable information, so I feel stuck on Weather.com, the others I used do not report accuracy for my location.

I will wait a while longer, but I'm willing to parse the Weather.com html if necessary, and of course, you always help! :)
I think I just need someone to start the job and everyone helped. ;-)

I have been extracting html data for my Moon and Sun information for a long time and so far I have had no problems.
Yes, in spite of the relative complexity, and probable risk, of parsing the HTML at weather.com, I don't think there is any argument that weather.com is the "gold standard" for current and accurate information.
User avatar
GTI.H
Posts: 75
Joined: December 15th, 2018, 3:35 am

Re: Weather.com WXDATA feed failing again

Post by GTI.H »

jsmorley wrote:
January 20th, 2020, 3:54 pm
Yes, in spite of the relative complexity, and probable risk, of parsing the HTML at weather.com, I don't think there is any argument that weather.com is the "gold standard" for current and accurate information.
Yes, you are correct, I know that your observation comes to clarify. :bow:

I have a little weather station and some thermometers here that measure internal and external from where I get my first alerts and always compared my measurements with those obtained by the websites.

As far as I know wheather.com uses weather information from the nearest airport, sometimes even choosing which one, so a small difference is always expected.

Among those I checked, W.C was more accurate for me. This preference for W.C is personal.

One observation is that whenever it Rained/Storm the W.C feed did not show some measurements, interesting not . . . ?
physchem
Posts: 4
Joined: July 30th, 2016, 4:58 pm

Re: Weather.com WXDATA feed failing again

Post by physchem »

This could be a migration of some sort, just like in 2018 when it was down for a while.
User avatar
Cariboudjan
Posts: 61
Joined: May 12th, 2019, 8:55 am

Re: Weather.com WXDATA feed failing again

Post by Cariboudjan »

The weather.com website may change at any moment. Isn't there a better way we could come up with as a community to better parse the weather.com website?

Why don't we host a singular URL location to an XML file (hosted by Rainmeter.net) that the Rainmeter team can update if necessary to accommodate any changes to the Weather Channel website that would otherwise break hundreds of weather skins that would need retooling.

If Rainmeter hosted an XML file, containing all of the necessary RegExp information for the webparser, (that standardizes the way StringIndex is organized, of course, example: Tomorrow's wind speed is always and permanently set as a specific number)

That way authors can use the content of that XML file (is this even possible?) as the value of RegExp for the WebParser. When Rainmeter.net changes the XML file according to any changes made to the Weather Channel website, it cycles down to all of the skins currently out there active in the world.

Is this something the Rainmeter team can do? It may offer a permanent solution to this problem?

It seems like as it currently is, the existing solutions (using the Weather Channel website) is only temporary and will inevitably break all skins that use it once a small change is made to the Weather Channel's website. If we had some singular, universal, accessible, and changeable resource to pull from directly from Rainmeter, this could even be solved whenever changes are necessary by a simple Rainmeter update or an update to a hosted XML file from a singular source.

Is it possible to use a URL as an @Include= location (Like @Inlcude=https://www.rainmeter.net/hostfile/weatherregexp.inc), maybe host an online INC file, and have it contain:

Code: Select all

[Variables]

WeatherRegExp=(?siU)(?(?=.*<h1 class="h4 today_nowcard-location"#xx# className="h4 today_nowcard-location">(.*)<span class=".*" className=".*"></span></h1>)
NOW=(?siU)(?(?=.*</div></span><p class="today_nowcard-#xx#timestamp"><span>(.*)<!----> </span><span>(.*)</span>).*(?(?=.*<div class="today_nowcard-section today_nowcard-condition"><div class="condition-icon wx-weather-icon vector#xx#"><icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon icon-svg icon-svg-.* .* icon-.*">.*</icon></div>)(?(?=.*<div class="today_nowcard-temp"#xx#><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<div class="today_nowcard-phrase#xx#">(.*)</div>)(?(?=.*<div class="today_nowcard-feels#xx#"><span class="btn-text">(.*)<!----> </span><span class="deg-feels" className="deg-feels">(.*)<sup>(.*)</sup></span>).*(?(?=.*<div class="today_nowcard-hilo"#xx#><span class="btn-text">.*<!----> </span><span class="deg-hilo-nowcard"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<span class="btn-text">.*<!---->#xx# </span><span class="deg-hilo-nowcard"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<div class="today_nowcard-sidecar component panel"><table><caption>(.*)</caption><tbody>#xx#<tr><th>(.*)</th><td><span class="">(.*)</span></td></tr><tr><th>(.*)</th><td><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span></span></span></td></tr><tr><th>.*</th><td><span class="">.*<sup>.*</sup></span></td></tr><tr><th>(.*)</th><td><span class="">(.*)<!---->.*</span></td></tr><tr><th>(.*)</th><td><span class="">(.*)</span></td>)
UV=(?siU)"vt1observation":(?(?=.*{"altimeter":.*,.*#xx#"uvIndex":(.*),"uvDescription":"(.*)",.*})
UVText=(?siU)(?(?=.*</script><script charSet="UTF-8">window.i18n=#xx#"Wind":".*",.*,"UV Index":"(.*)")
36HOURS=(?siU)(?(?=.*<div class="today-daypart daypart-0#xx#  selected" id="daypart-0" data-track-string="today-looking-ahead_lookingAhead0hours" className="today-daypart daypart-0  selected"><div class="today-daypart-content" className="today-daypart-content"><div class="today-daypart-top"><span class="today-daypart-title" id="dp0-daypartName">(.*)</span>)(?(?=.*<span class="today-daypart-wxphrase"#xx# id="dp0-phrase">(.*)</span></div>)(?(?=.*<div class="condition-icon wx-weather-icon"#xx# aria-hidden="true" id="la-part0-icon"><icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon icon-svg icon-svg-.* .* icon-.*">.*</icon></div>)(?(?=.*<div class="today-daypart-hilo" id="dp0-#xx#highLow">(.*)</div>)(?(?=.*<div class="today-daypart-temp"#xx#><span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*<div class="today-daypart-precip"#xx#><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class="precip-val" className="precip-val"><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="today-daypart daypart-1"#xx# id="daypart-1" data-track-string="today-looking-ahead_lookingAhead12hours" className="today-daypart daypart-1"><div class="today-daypart-content" className="today-daypart-content"><div class="today-daypart-top"><span class="today-daypart-title" id="dp1-daypartName">(.*)</span>)(?(?=.*<span class="today-daypart-wxphrase"#xx# id="dp1-phrase">(.*)</span></div>)(?(?=.*<div class="condition-icon wx-weather-icon"#xx# aria-hidden="true" id="la-part1-icon"><icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon icon-svg icon-svg-.* .* icon-.*">.*</icon></div>)(?(?=.*<div class="today-daypart-hilo" id="dp1-#xx#highLow">(.*)</div>)(?(?=.*<div class="today-daypart-temp"#xx#><span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*<div class="today-daypart-precip"#xx#><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class="precip-val" className="precip-val"><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="today-daypart daypart-2"#xx# id="daypart-2" data-track-string="today-looking-ahead_lookingAhead24hours" className="today-daypart daypart-2"><div class="today-daypart-content" className="today-daypart-content"><div class="today-daypart-top"><span class="today-daypart-title" id="dp2-daypartName">(.*)</span>)(?(?=.*<span class="today-daypart-wxphrase"#xx# id="dp2-phrase">(.*)</span></div>)(?(?=.*<div class="condition-icon wx-weather-icon"#xx# aria-hidden="true" id="la-part2-icon"><icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon icon-svg icon-svg-.* .* icon-.*">.*</icon></div>)(?(?=.*<div class="today-daypart-hilo" id="dp2-#xx#highLow">(.*)</div>)(?(?=.*<div class="today-daypart-temp"#xx#><span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*<div class="today-daypart-precip"#xx#><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class="precip-val" className="precip-val"><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="today-daypart daypart-3"#xx# id="daypart-3" data-track-string="today-looking-ahead_lookingAhead36hours" className="today-daypart daypart-3"><div class="today-daypart-content" className="today-daypart-content"><div class="today-daypart-top"><span class="today-daypart-title" id="dp3-daypartName">(.*)</span>)(?(?=.*<span class="today-daypart-wxphrase"#xx# id="dp3-phrase">(.*)</span></div>)(?(?=.*<div class="condition-icon wx-weather-icon"#xx# aria-hidden="true" id="la-part3-icon"><icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon icon-svg icon-svg-.* .* icon-.*">.*</icon></div>)(?(?=.*<div class="today-daypart-hilo" id="dp3-#xx#highLow">(.*)</div>)(?(?=.*<div class="today-daypart-temp"#xx#><span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*<div class="today-daypart-precip"#xx#><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class="precip-val" className="precip-val"><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="today-daypart daypart-4"#xx# id="daypart-4" data-track-string="today-looking-ahead_lookingAhead48hours" className="today-daypart daypart-4"><div class="today-daypart-content" className="today-daypart-content"><div class="today-daypart-top"><span class="today-daypart-title" id="dp4-daypartName">(.*)</span>)(?(?=.*<span class="today-daypart-wxphrase"#xx# id="dp4-phrase">(.*)</span></div>)(?(?=.*<div class="condition-icon wx-weather-icon"#xx# aria-hidden="true" id="la-part4-icon"><icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon icon-svg icon-svg-.* .* icon-.*">.*</icon></div>)(?(?=.*<div class="today-daypart-hilo" id="dp4-#xx#highLow">(.*)</div>)(?(?=.*<div class="today-daypart-temp"#xx#><span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*<div class="today-daypart-precip"#xx#><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class="precip-val" className="precip-val"><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>)
Hourly=(?siU)(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*<div class="hourly-time"#xx#><span class="dsx-date">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky"#xx# className="twc-table-shadow sticky"></div></div><div class="hourly-date">(.*)</div>).*(?(?=.*<td class="hidden-cell-sm description" headers="description"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="hidden-cell-sm description"><span>(.*)</span>)(?(?=.*</td><td class="temp" headers="temp"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="temp"><span class="">(.*)<sup>(.*)</sup></span>).*(?(?=.*<td class="precip" headers="precip"#xx# data-track-string="ls_hourly_ls_hourly_toggle" className="precip"><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*
Forecast=(?siU)(?(?=.*</td><td class="twc-sticky-col" headers="day" .* className="twc-sticky-col"#xx#><div><div><span class="date-time">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky" className="twc-table-shadow sticky"#xx#></div></div><span class="day-detail clearfix">(.*)</span></div>)(?(?=.*</td><td class="description" .* className="description"#xx#><span>(.*)</span>).*(?(?=.*</td><td class="precip" .* className="precip"#xx#><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*</td><td class="twc-sticky-col" headers="day" .* className="twc-sticky-col"#xx#><div><div><span class="date-time">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky" className="twc-table-shadow sticky"#xx#></div></div><span class="day-detail clearfix">(.*)</span></div>)(?(?=.*</td><td class="description" .* className="description"#xx#><span>(.*)</span>)(?(?=.*</td><td class="temp" .* className="temp"#xx#><div><span class="">(.*)<sup>(.*)</sup></span>.*<span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*</td><td class="precip" .* className="precip"#xx#><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*</td><td class="twc-sticky-col" headers="day" .* className="twc-sticky-col"#xx#><div><div><span class="date-time">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky" className="twc-table-shadow sticky"#xx#></div></div><span class="day-detail clearfix">(.*)</span></div>)(?(?=.*</td><td class="description" .* className="description"#xx#><span>(.*)</span>)(?(?=.*</td><td class="temp" .* className="temp"#xx#><div><span class="">(.*)<sup>(.*)</sup></span>.*<span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*</td><td class="precip" .* className="precip"#xx#><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*</td><td class="twc-sticky-col" headers="day" .* className="twc-sticky-col"#xx#><div><div><span class="date-time">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky" className="twc-table-shadow sticky"#xx#></div></div><span class="day-detail clearfix">(.*)</span></div>)(?(?=.*</td><td class="description" .* className="description"#xx#><span>(.*)</span>)(?(?=.*</td><td class="temp" .* className="temp"#xx#><div><span class="">(.*)<sup>(.*)</sup></span>.*<span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*</td><td class="precip" .* className="precip"#xx#><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*</td><td class="twc-sticky-col" headers="day" .* className="twc-sticky-col"#xx#><div><div><span class="date-time">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky" className="twc-table-shadow sticky"#xx#></div></div><span class="day-detail clearfix">(.*)</span></div>)(?(?=.*</td><td class="description" .* className="description"#xx#><span>(.*)</span>)(?(?=.*</td><td class="temp" .* className="temp"#xx#><div><span class="">(.*)<sup>(.*)</sup></span>.*<span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*</td><td class="precip" .* className="precip"#xx#><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*</td><td class="twc-sticky-col" headers="day" .* className="twc-sticky-col"#xx#><div><div><span class="date-time">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky" className="twc-table-shadow sticky"#xx#></div></div><span class="day-detail clearfix">(.*)</span></div>)(?(?=.*</td><td class="description" .* className="description"#xx#><span>(.*)</span>)(?(?=.*</td><td class="temp" .* className="temp"#xx#><div><span class="">(.*)<sup>(.*)</sup></span>.*<span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*</td><td class="precip" .* className="precip"#xx#><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*</td><td class="twc-sticky-col" headers="day" .* className="twc-sticky-col"#xx#><div><div><span class="date-time">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky" className="twc-table-shadow sticky"#xx#></div></div><span class="day-detail clearfix">(.*)</span></div>)(?(?=.*</td><td class="description" .* className="description"#xx#><span>(.*)</span>)(?(?=.*</td><td class="temp" .* className="temp"#xx#><div><span class="">(.*)<sup>(.*)</sup></span>.*<span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*</td><td class="precip" .* className="precip"#xx#><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*(?(?=.*</td><td class="twc-sticky-col" headers="day" .* className="twc-sticky-col"#xx#><div><div><span class="date-time">(.*)</span>)(?(?=.*<icon class="icon icon-svg icon-svg-.* .* icon-(.*)" className="icon#xx# icon-svg icon-svg-.* .* icon-.*">.*</icon>)(?(?=.*<div class="twc-table-shadow sticky" className="twc-table-shadow sticky"#xx#></div></div><span class="day-detail clearfix">(.*)</span></div>)(?(?=.*</td><td class="description" .* className="description"#xx#><span>(.*)</span>)(?(?=.*</td><td class="temp" .* className="temp"#xx#><div><span class="">(.*)<sup>(.*)</sup></span>.*<span class="">(.*)<sup>(.*)</sup></span></div>)(?(?=.*</td><td class="precip" .* className="precip"#xx#><div><span class="icon icon-font iconset-weather-data icon-drop-1" className="icon icon-font iconset-weather-data icon-drop-1"></span><span class=""><span>(.*)<span class="Percentage__percentSymbol__2Q_AR">(.*)</span>).*
SUN=(?siU)(?(?=.*<span class="wx-detail-label show-sm">.*</span#xx#<span class="wx-dsxdate" id="dp0-details-(.*)">(.*)</span>.*<span class="wx-dsxdate" id="dp0-details-(.*)">(.*)</span>)
MOON=(?siU)"vt1dailyForecast":(?(?=.*{"validDate":".*").*,.*"moonIcon":".*","moonPhrase":"(.*)","moonrise":"(.*)","moonset":"(.*)",.*).*(?(?=.*{"validDate":".*").*,.*"moonIcon":".*","moonPhrase":".*","moonrise":"(.*)","moonset":"(.*)",.*)
Details=(?siU)(?(?=.*<td class="twc-sticky-col" headers="day" title="(.*)"#xx# .* className="twc-sticky-col"><div>).*(?(?=.*<td class="twc-sticky-col" headers="day" title="(.*)"#xx# .* className="twc-sticky-col"><div>).*(?(?=.*<td class="twc-sticky-col" headers="day" title="(.*)"#xx# .* className="twc-sticky-col"><div>).*(?(?=.*<td class="twc-sticky-col" headers="day" title="(.*)"#xx# .* className="twc-sticky-col"><div>).*(?(?=.*<td class="twc-sticky-col" headers="day" title="(.*)"#xx# .* className="twc-sticky-col"><div>).*(?(?=.*<td class="twc-sticky-col" headers="day" title="(.*)"#xx# .* className="twc-sticky-col"><div>).*(?(?=.*<td class="twc-sticky-col" headers="day" title="(.*)"#xx# .* className="twc-sticky-col"><div>).*(?(?=.*<td class="twc-sticky-col" headers="day" title="(.*)"#xx# .* className="twc-sticky-col"><div>)
Details36H=(?siU)(?(?=.*{"dayPartName":"(.*)","precipPct":.*,"precipAmt":.*#xx#,"narrative":"(.*)").*(?(?=.*{"dayPartName":"(.*)","precipPct":.*,"precipAmt":.*#xx#,"narrative":"(.*)").*(?(?=.*{"dayPartName":"(.*)","precipPct":.*,"precipAmt":.*#xx#,"narrative":"(.*)").*(?(?=.*{"dayPartName":"(.*)","precipPct":.*,"precipAmt":.*#xx#,"narrative":"(.*)").*(?(?=.*{"dayPartName":"(.*)","precipPct":.*,"precipAmt":.*#xx#,"narrative":"(.*)").*
PressArrow=(?siU)<div class="today_nowcard-sidecar component panel"><table><caption>.*</caption><tbody>.*(?(?=.*<th>.*</th><td><span class="">.*<!----> <span class="icon icon-font iconset-arrows#xx# icon-arrow-.*-line" className="icon icon-font iconset-arrows icon-(.*)-line"></span>)
SevereAlert=(?siU)(?(?=.*<a class="priority bg-alert-.*" href="#Lang#/weather/alerts/localalerts/l/.*"#xx# title=".*" data-from-string=".*" className="priority bg-alert-.*"><div class="title text text-overflow" className="title text text-overflow"><span class="warning-text" className="warning-text">.*</span><span class="timestamp" className="timestamp">.*</span>)
PriorityAlert=(?siU)(?(?=.*<div class="gm-alerts-time#xx#"><a class="priority bg-alert-.*" href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*
ALERT=(?siU)(?(?=.*<div id=".*-SevereAlertBar#xx#-.*"><div><div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*(?(?=.*<a class="priority bg-alert-.*"#xx# href="#Lang#/weather/alerts/localalerts/.* className="priority bg-alert-(.*)">.*<span class="warning-text" className="warning-text">(.*)</span>).*(?(?=.*<span class="timestamp"#xx# className="timestamp">(.*)</span></div>).*
IconAlert=(?siU)(?(?=.*<div id=".*-SevereAlertBar#xx#-.*"><div><div>)(?(?=.*<div class="SevereAlertBar" role="banner" aria-label=".*" className="SevereAlertBar">.*<div class="priority bg-alert-.*"#xx# className="priority bg-alert-.*">).*
And then just change that variable when necessary to adjust for any changes?

ADDITIONALLY...

I think an ideal solution would be to have a built-in Rainmeter plugin that is included with all Rainmeter installs, that allows you to select from a few sources (Weather Channel, Weather Underground, etc.) and use child measures to get specific weather data...

Such as...

Code: Select all

[WeatherPlugin]
Measure=Plugin
Plugin=WeatherPlugin
Source=WeatherChannel

[WeatherData1]
Measure=WeatherPlugin
Day=1
Type=WindSpeed

[WeatherData2]
Measure=WeatherPlugin
Day=3
Type=HighTemp

[WeatherData2]
Measure=WeatherPlugin
Day=2
Type=Condition

If it worked this way we wouldn't need to use ridiculously long webparsers for weather data, can easily switch between different sources, and if the source HTML or RSS data changes, the plugin can be altered accordingly and pushed out in an update.

Maybe something to think about including in the next 4.4 update?? :) :)
User avatar
SilverAzide
Posts: 716
Joined: March 23rd, 2015, 5:26 pm

Re: Weather.com WXDATA feed failing again

Post by SilverAzide »

Cariboudjan wrote:
January 30th, 2020, 7:53 am
The weather.com website may change at any moment. Isn't there a better way we could come up with as a community to better parse the weather.com website?

Why don't we host a singular URL location to an XML file (hosted by Rainmeter.net) that the Rainmeter team can update if necessary to accommodate any changes to the Weather Channel website that would otherwise break hundreds of weather skins that would need retooling.
See this:
https://forum.rainmeter.net/viewtopic.php?f=118&t=34470

I think it addresses most if not all your concerns.
DeviantArt Gadgets More...
User avatar
jsmorley
Developer
Posts: 20425
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Weather.com WXDATA feed failing again

Post by jsmorley »

There is no way that we can host an XML file that contains the regular expression needed to parse weather.com, and have a million Rainmeter users write or use skins that are hitting our website every 10 minutes to get the XML.

I'll try to work with xenium and others to keep the regular expression here:

https://forum.rainmeter.net/viewtopic.php?f=118&t=34470

and or here:

https://forum.rainmeter.net/viewtopic.php?f=118&t=34470

working, and in theory you would just have to replace WeatherComRegExp.inc, and any skin using it should start working again.

That's my intent for how I did the .inc files. They may change, but in theory, since you write the skin to be abstracted from their contents with a "back-end / front-end" approach, just replacing them should be all that is needed.

If you write a skin that doesn't just @Include WeatherComRegExp.inc and the other .inc files that create the child StringIndex measures, then that's on you. If the regular expression changes, you are going to be editing your skin. The regular expression is going to change, and the StringIndex numbers are going to change.

It may be tempting to just use some part of the regular expression directly in a very simple weather skin, and just create your own parent and child measures. This has some charm with a skin that simply displays the current temperature and some conditions text, but I caution against it. You are better off in the long run to use the minimum @Include files required. Keep in mind that while doing that will create a bunch of measures you might never use, child measures in WebParser take almost no resources. They will be there in About/Skins, but won't run up the cost of your skin.

If you do use the @Include files, then with any luck, [@CurrentTemperature] will always reflect the same data in your skin, no matter how the include files change.

I personally don't think this is a good candidate for a plugin or code baked into Rainmeter. We are just not really interested in taking ownership of one or more weather service providers, that change and come and go with some regularity. I think it is better for the community in the long run if access to the information is as easy as possible to change as needed and desired by regular skin authors and users. WebParser is a good fit for this.

There were painful lessons learned from NowPlaying that I have not forgotten...
User avatar
SilverAzide
Posts: 716
Joined: March 23rd, 2015, 5:26 pm

Re: Weather.com WXDATA feed failing again

Post by SilverAzide »

So, is it time to change the title of this thread to "Weather.com WXDATA feed is DEAD"? :)
DeviantArt Gadgets More...
User avatar
jsmorley
Developer
Posts: 20425
Joined: April 19th, 2009, 11:02 pm
Location: Fort Hunt, Virginia, USA

Re: Weather.com WXDATA feed failing again

Post by jsmorley »

SilverAzide wrote:
January 30th, 2020, 5:49 pm
So, is it time to change the title of this thread to "Weather.com WXDATA feed is DEAD"? :)
I think "failing" is a state that can possibly change. There is no coming back from "dead". I'm all for leaving wiggle-room... ;-)
User avatar
Nightblade
Posts: 13
Joined: August 21st, 2012, 5:17 am

Re: Weather.com WXDATA feed failing again

Post by Nightblade »

If we could use named capture groups we could use regex's for different weather sites without having to rewrite (the numbered captures in) each skin. Could also make future regex updates easier too.

(Sorry if that's is hard to digest, best I can do atm, major brain fog.)
User avatar
Cariboudjan
Posts: 61
Joined: May 12th, 2019, 8:55 am

Re: Weather.com WXDATA feed failing again

Post by Cariboudjan »

There is no way that we can host an XML file that contains the regular expression needed to parse weather.com, and have a million Rainmeter users write or use skins that are hitting our website every 10 minutes to get the XML.
I mean, an XML file is pretty small and would only need to be accessed/updated on Rainmeter load. Rainmeter could conceivably have this information baked into Rainmeter and change with a Rainmeter version update, or it could access the information from an XML file from Rainmeter.net and only do this when Rainmeter loads. It doesn't need to ping this data on each skin update/refresh/load. It only needs to do so when Rainmeter starts. If the information changes, a simple Rainmeter reboot would correct the error.

I don't think it would require updating very regularly. I just can't think of a way to do this otherwise without risking breaking hundreds or thousands of skins already out there in the wild to be downloaded. Having a "mothership" for the weather info would be really, really handy.

Just for clarification -- Rainmeter users would not be pinging Rainmeter.net for their weather data. Only for the information needed to ping the weather websites for weather data. This information doesn't update often and would not need to be updated unless an update is necessary.

Like, Rainmeter already pings the website to check if a new version is available. This wouldn't be any different. A new copy of the XML file would only be accessed by users if the XML's version number changes.

Weather skins are among the most popular uses for Rainmeter right now. I don't think it's a good idea to expect authors to update and reupload their skins each time regexp data changes. There will be thousands of skins out there that will just break and become useless on a routine basis. A mothership for the data is a really good option here imho.
Last edited by Cariboudjan on January 31st, 2020, 2:40 am, edited 6 times in total.