It is currently May 8th, 2024, 10:51 pm

PluginWebView - Make skin using web technology

Share and get help with Plugins and Addons
User avatar
Yincognito
Rainmeter Sage
Posts: 7211
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: PluginWebView - Make skin using web technology

Post by Yincognito »

Kotofanchik wrote: April 2nd, 2024, 3:21 pm Something isn't working. Rainmeter\Skins\test3\DownloadFile\Data.txt file is empty
It also started causing the entire Rainmeter to freeze. I didn’t do anything, I see it froze, now it constantly freezes with test3
!WriteKeyValue: File not found: C:\Users\RmicroN\Documents\Rainmeter\Skins\test3\ + f +
Yes, it's partially my fault, I mentioned that the Javascript from the WebView variant (i.e. the 2nd variant) was untested code - I wrote it from my phone and had a few typos (not that easy to type from a phone compared to a laptop). I edited the above post and corrected them, so technically, both variants should work.

HOWEVER, in practice, many times the 2nd variant you tried to use will NOT work and Rainmeter will freeze / hang (even after unloading the variant with the WebView measure!). The code is correct and you can see that if you first try to load the skin with the RainmeterAPI.Bang(bang); part commented out to <!-- RainmeterAPI.Bang(bang); -->, then uncomment that part and refresh or reload the skin (which will provide the data and will not cause Rainmeter to freeze while the skin is loaded, although it will freeze once you unload it). Frankly, this doesn't really depend on me since I did my part, but it's clear something else than the code itself is not going smoothly here (doesn't seem to be about the length of the string or the funky characters in it, since the freeze happens even I set the "page" variable to "blah blah" in Javascript).
Kotofanchik wrote: April 2nd, 2024, 8:29 pm I think about everything. why is api.allorigins.win here? I don’t understand the capabilities of Webwiev, but isn’t it easier to save a file using its ability to save to a file?
Maybe it’s simpler as I originally suggested:
Webwiev opens the specified site and receives a command to save its contents or overwrite it and that's it. and do it at intervals. Or is this impossible?
Well, and by the way, once again why webparser is not suitable. He cannot get to the desired site, but webwiev can.
Perhaps the option with api.allorigins.win will also work. But it hasn't been possible to check yet. Now the site works without human verification and I don’t know how the different ways will work.
I already explained the role of api.allorigins.win in the other thread:
Getting the response makes use of this nice and free API to bypass CORS and get the response even if ran from the above local webpage.
This is again because of the security required here. You can't access an only address from a local page, because of CORS (google it). You can't save automatically the contents of a webpage (which is why I used Rainmeter bangs to do it from Javascript), only manually by interacting with the browser. Microsoft's WebView's only capability is to facilitate displaying webpages in a desktop program, and the only capability of khanhas's WebView plugin for Rainmeter is to facilitate Microsoft's WebView interaction with Rainmeter, that's all there is to it. The code is still subject to the same limitations a "normal" webpage code has (in the case of the page used by the WebView measure), or a "normal" skin code has (in the case of Rainmeter code).

So, there isn't any command to save a webpage contents to a local file, overwrite that file, or EVEN freely chosing that file's path (!) - yeah, I know, kind of stupid, but it's what it is. The most I could do is to come up with a minor alternative like:
[SkinFolder]\@Resources\Page.html:

Code: Select all

<!DOCTYPE html>
<html>
  <body style="margin: 0; background-color: red;">
    <script>
      var r = new XMLHttpRequest();
      r.onreadystatechange = function()
      {
        if (r.readyState == 4 && r.status == 200)
        {
          let page = r.response, file = 'Data.txt', a = document.createElement('a'), blob = new Blob([page]), bang = '[!EnableMeasure Data][!UpdateMeasure Data][!CommandMeasure Data "Update"]';
          a.href = URL.createObjectURL(blob);
          a.download = file;
          a.click();
          RainmeterAPI.Bang(bang);
        };
      };
      r.open('GET', 'https://api.allorigins.win/get?url=' + encodeURIComponent('https://www.google.com'), true); r.responseType = 'text'; r.send();
    </script>
  </body>
</html>
[SkinFolder]\Skin.ini:

Code: Select all

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1
BackgroundMode=2
SolidColor=0,0,0,128

---Measures---

[Page]
Measure=Plugin
Plugin=WebView
X=0
Y=0
W=5
H=5
URL=file:///#@#Page.html
UpdateDivider=600

[Data]
Disabled=1
Measure=WebParser
URL=file://%USERPROFILE%\Downloads\Data.txt
RegExp=(?siU)^(.*)$
StringIndex=1
UpdateRate=-1
FinishAction=[!UpdateMeter PageData][!Redraw]

---Meters---

[PageData]
Meter=String
X=(600/2)
Y=(350/2)
W=600
H=350
FontFace=Consolas
FontSize=12
FontColor=255,255,255,255
FontEffectColor=0,0,0,255
StringEffect=Shadow
StringAlign=CenterCenter
AntiAlias=1
ClipString=2
MeasureName=Data
Text=Data: %1
There are several disadvantages regarding this one, like:
- the path where the file is saved is restricted to the one in the WebView environment (for me, it is C:\Users\[User]\Downloads, as seen in [Data])
- a download popup always shows after downloading / saving the resource, see here for details (me, I'm not going to explore that further)
- the previous saved file needs to be deleted after it's no longer needed, otherwise the subsequent saves will be appended with (1), (2) and so on
- although initially I thought this alternative was safe, it will still freeze / hang Rainmeter, so clearly something is wrong with the plugin or such

Anyways, I'll stop here with this. You already have plenty of routes to follow, albeit not many convenient ones. Maybe others have better ideas, I don't know... :confused:
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
Kotofanchik
Posts: 99
Joined: March 15th, 2024, 7:30 pm

Re: PluginWebView - Make skin using web technology

Post by Kotofanchik »

Now the data is being added to the file and it is constantly growing. How can I make new data overwrite old data?
In general, the work is unstable, but the data in the file arrives correctly every time. But further... Webparser may or may not read what I’m looking for. Most of the time he doesn’t read. :)
User avatar
Yincognito
Rainmeter Sage
Posts: 7211
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: PluginWebView - Make skin using web technology

Post by Yincognito »

Kotofanchik wrote: April 3rd, 2024, 11:09 am Now the data is being added to the file and it is constantly growing. How can I make new data overwrite old data?
In general, the work is unstable, but the data in the file arrives correctly every time. But further... Webparser may or may not read what I’m looking for. Most of the time he doesn’t read. :)
All implementations above overwrite the data on the file. However, !WriteKeyValue only does it if the section (i.e. [Variables]) and the key (i.e. Page, or what's before the = symbol) already exist in the file being written to, with the value part (i.e. what's after the = symbol) being automatically overwritten:
https://docs.rainmeter.net/manual/bangs/#WriteKeyValue
which normally happens every time except when the file is empty, because writing happens to the same section and key as per the code. The file growing might be an effect of either:
- the process being unstable
- newline characters potentially existing in the value part that was or is written to the file (value parts cannot contain newlines in the .ini format used by Rainmeter, but then, typically they shouldn't exist in a minified webpage contents either)
- other occurences of the said section and key in the value part that was or is written to the file (causing Rainmeter to overwrite only one such occurrence and leave any other untouched)

What you can try is gradually add more pairs of " quotes to the 3 already existing before and after the page variable in the [!WriteKeyValue Variables Page """' + page + '""" "' + file + '"] part of the Page.html code, and see if that leads to an improvement.



So, again, there is no direct way to automatically / programmatically write to files from a webpage outside the interactive user controlled download system (and the much more complicated process of creating a CORS free NodeJS local server on your machine), it's a security risk. Therefore, in this case, you have to do it through the plugin's RainmeterAPI object, which allows running Rainmeter bangs as if they were run from Rainmeter itself.

That being said, there might be other ways, like using a RunCommand measure (or even Lua, IF the file encoding is suited) to do it:
https://docs.rainmeter.net/manual/plugins/runcommand/
https://docs.rainmeter.net/manual/lua-scripting/
https://docs.rainmeter.net/snippets/read-write-file/

That would be a job for someone else, you, or another day to try. Me, I already provided way too many ways already, with 2 of them (the String measure and the 2 WebParsers) working just fine, and the others having issues that don't really depend on the code I wrote but on things I cannot control.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
Kotofanchik
Posts: 99
Joined: March 15th, 2024, 7:30 pm

Re: PluginWebView - Make skin using web technology

Post by Kotofanchik »

Four pairs of quotation marks avoided rewriting. And the skin sometimes works as it should. That is, it not only writes data, but can read it later. I think some kind of inconsistency in the timing of operations is preventing stable operation, thank you :)
Or five quotes. There was also a problem with four pairs.
Kotofanchik
Posts: 99
Joined: March 15th, 2024, 7:30 pm

Re: PluginWebView - Make skin using web technology

Post by Kotofanchik »

In general there is no stability.
But I noticed. what if
Comment out
[Data]
;Disabled=1
Then everything starts to work quickly and stably with one nuance. the data file begins to be appended again. But nothing freezes.
User avatar
Yincognito
Rainmeter Sage
Posts: 7211
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: PluginWebView - Make skin using web technology

Post by Yincognito »

Kotofanchik wrote: April 3rd, 2024, 2:59 pm Four pairs of quotation marks avoided rewriting. And the skin sometimes works as it should. That is, it not only writes data, but can read it later. I think some kind of inconsistency in the timing of operations is preventing stable operation, thank you :)
Or five quotes. There was also a problem with four pairs.
Kotofanchik wrote: April 3rd, 2024, 3:44 pm In general there is no stability.
But I noticed. what if
Comment out
[Data]
;Disabled=1
Then everything starts to work quickly and stably with one nuance. the data file begins to be appended again. But nothing freezes.
Hmmm... maybe. Try this slightly adjusted variant, see if it works properly (for me, until now, no Rainmeter freezing or any other issues):

[SkinFolder]\@Resources\Page.js:

Code: Select all

(function loop()
{
  let site = 'https://api.allorigins.win/get?url=' + encodeURIComponent('https://www.google.com');
  let file = RainmeterAPI.GetVariable('CURRENTPATH') + 'DownloadFile\\Data.txt';
  fetch(site)
    .then(function(data) {if (data.ok) return data.text(); throw new Error('Network response problem');})
    .then(function(page) {console.log('Fetch operation complete'); RainmeterAPI.Bang('[!WriteKeyValue Variables Page """"' + page + '"""" "' + file + '"][!CommandMeasure Data "Reset"][!CommandMeasure Data "Update"]');})
    .catch(function(err) {console.log('Fetch operation problem:', err);});
  setTimeout(() => {loop();}, 600000);
})();
[SkinFolder]\@Resources\Page.html:

Code: Select all

<!DOCTYPE html>
<html>
  <body style="margin: 0; background-color: red;">
    <script src="Page.js" defer></script>
  </body>
</html>
[SkinFolder]\Skin.ini:

Code: Select all

[Rainmeter]
Update=1000
AccurateText=1
DynamicWindowSize=1
BackgroundMode=2
SolidColor=0,0,0,128

---Measures---

[Page]
Measure=Plugin
Plugin=WebView
X=0
Y=0
W=5
H=5
URL=file:///#@#Page.html
UpdateDivider=-1

[Data]
Measure=WebParser
URL=file://#CURRENTPATH#DownloadFile\Data.txt
RegExp=(?siU)^(.*)$
StringIndex=1
UpdateRate=-1
FinishAction=[!Log "File contents retrieved"][!UpdateMeter PageData][!Redraw]

---Meters---

[PageData]
Meter=String
X=(600/2)
Y=(350/2)
W=600
H=350
FontFace=Consolas
FontSize=12
FontColor=255,255,255,255
FontEffectColor=0,0,0,255
StringEffect=Shadow
StringAlign=CenterCenter
AntiAlias=1
ClipString=2
MeasureName=Data
Text=Data: %1
LeftMouseUpAction=[!SetOption Page W 5][!SetOption Page H 5][!UpdateMeasure Page]
Ideally, for the above to not throw any error in the Rainmeter log, the [SkinFolder]\DownloadFile\Data.txt should already exist (irrespective if it's empty or not). Let me know if you still have issues with this, e.g. Rainmeter hanging / freezing, or the file growing after writing to it. The changes are minor, just another way of doing things, but since "the devil is in the details", maybe these details mattered...

Note: Because the Data measure is not initially disabled, the skin will briefly show the "latest" contents of Data.txt at refresh time, before replacing it with the currently retrieved response contents. Anyway, if it works, this is just a minor inconvenience.

EDIT: Added looping the retrieval of the response through Javascript, instead of through the UpdateDivider of [Page] from Rainmeter. Added logging.
EDIT2: Added retrieving the response on demand via left mouse click on the meter.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
Kotofanchik
Posts: 99
Joined: March 15th, 2024, 7:30 pm

Re: PluginWebView - Make skin using web technology

Post by Kotofanchik »

At first glance, everything works correctly, the file does not grow, there are no errors in the log.
User avatar
Yincognito
Rainmeter Sage
Posts: 7211
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: PluginWebView - Make skin using web technology

Post by Yincognito »

Kotofanchik wrote: April 3rd, 2024, 5:10 pm At first glance, everything works correctly, the file does not grow, there are no errors in the log.
Excellent - make sure you test it extensively, and for other sites than google.com too.
Of course, without polling the api.allorigins.win site excessively and get banned or something.

EDIT: In case other sites have newlines characters in their response (somewhat unlikely, given the fact that most of them minify their HTML code for performance reasons), you might consider removing or replacing the newline characters from the page variable, before calling RainmeterAPI.Bang() in the Javascript above.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth
Kotofanchik
Posts: 99
Joined: March 15th, 2024, 7:30 pm

Re: PluginWebView - Make skin using web technology

Post by Kotofanchik »

But there are problems with my problematic site. Once a new option received a stub response with code 502 and that was all. gets nothing at all. The previous version, which received information from that site, also now receives nothing. True, a regular browser is very slow, but the page opens in it. :D
Google works well.
User avatar
Yincognito
Rainmeter Sage
Posts: 7211
Joined: February 27th, 2015, 2:38 pm
Location: Terra Yincognita

Re: PluginWebView - Make skin using web technology

Post by Yincognito »

Kotofanchik wrote: April 3rd, 2024, 5:40 pm But there are problems with my problematic site. Once a new option received a stub response with code 502 and that was all. gets nothing at all. The previous version, which received information from that site, also now receives nothing. True, a regular browser is very slow, but the page opens in it. :D
Google works well.
Well, like I said, I didn't guarantee bypassing Cloudflare, now did I? All I did was to ehlp in saving the response. :D
I'm not sure it's even possible, otherwise they wouldn't be who they are - but hey, you're welcome to try. If you want a more argumented stance from my side, you'd have to provide me with a Cloudflare protected address example so I can see for myself what happens. Preferably, a Latin alphabet based site, for conveniency.
Profiles: Rainmeter ProfileDeviantArt ProfileSuites: MYiniMeterSkins: Earth