0

I have developed a web-based tool, and currently trying to make it python-launchable. I figured using CEFpython is probably the way to do it. I followed the tutorial here and wrote the following code:

from cefpython3 import cefpython as cef
import base64
import platform
import sys
import threading
import os

HTML_code = """
<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0">
        <link href="static/css/main.css" rel="stylesheet" />
    </head>
    <body>
        <div id="UI">
        </div>
        <div id="container"></div>

        <script src="static/main.js"></script>
        <script type="text/javascript">
            function defineData(datainput){

                console.log("start")
                data = datainput;
                var loc = window.location.pathname;
                var dir = loc.substring(0, loc.lastIndexOf('/'));
                console.log(loc);
                console.log(dir);
                Main();
            }
        </script>

    </body>
</html>

"""
def html_to_data_uri(html):
    html = html.encode("utf-8", "replace")
    b64 = base64.b64encode(html).decode("utf-8", "replace")
    ret = "data:text/html;base64,{data}".format(data=b64)
    return ret


def main(config):

    sys.excepthook = cef.ExceptHook  # To shutdown all CEF processes on error
    settings = {}
    cef.Initialize(settings=settings)

    browser = cef.CreateBrowserSync(url=html_to_data_uri(HTML_code),window_title="Test")

    browser.SetClientHandler(LoadHandler(config))
    cef.MessageLoop()
    cef.Shutdown()
    return 

class LoadHandler(object):

    def __init__(self, config):
        self.config = config
    def OnLoadingStateChange(self, browser, is_loading, **_):
        """Called when the loading state has changed."""
        if not is_loading:
            # Loading is complete. DOM is ready.
            browser.ExecuteFunction("defineData", self.config)

unfortunately, unlike in the tutorial, my tool has to load a local .js file where the main function is defined (), and it seems if I code the html file this way, my working directory is not actually the directory where I call the script, but some strange place

the output of these lines are:

var loc = window.location.pathname;
var dir = loc.substring(0, loc.lastIndexOf('/'));
console.log(loc);
console.log(dir);

output:

text/html;base64,CjwhRE9DVFlQRSBodG1sPgo8aHRtbCBsYW5nPSJlbiI+Cgk8aGVhZD4KCQk8bWV0YSBjaGFyc2V0PSJ1dGYtOCI+CgkJPG1ldGEgbmFtZT0idmlld3BvcnQiIGNvbnRlbnQ9IndpZHRoPWRldmljZS13aWR0aCwgdXNlci1zY2FsYWJsZT1ubywgbWluaW11bS1zY2FsZT0xLjAsIG1heGltdW0tc2NhbGU9MS4wIj4KCQk8bGluayBocmVmPSJzdGF0aWMvY3NzL21haW4uY3NzIiByZWw9InN0eWxlc2hlZXQiIC8+CgkJPHN0eWxlIHR5cGU9InRleHQvY3NzIj4KCQkJKiB7CgkJCQkuYm9yZGV....

text

Could you help me finding the correct way of hard coding html code in python with the correct path? maybe I need to somehow set the path?

PS: I did try including the html code in a separate .html file, and it worked on Windows machines, but it seems MacOS doesn't like it. Since this tutorial did work on MAC, I'm trying to hard code the html part into the python script and hope it would work on both Windows and Mac

lxiangyun93
  • 77
  • 1
  • 7
  • 1
    You could load the contents of main.css and main.js files programmatically and put them inline in the HTML_code. Just basic file reading, string replace and string escaping needed. – Czarek Tomczak May 25 '20 at 11:38

1 Answers1

0

Well, the HTML document has been converted to the body of a data URI by html_to_data_uri, so the U[niversal]R[esource]L[ocator] (window.location) of the document isn't a location on a server, but the data URI itself (the "strange place" you mention).

Remember that URLs are a subset of URIs, and you passed the URI as a URL to CEF with:

    browser = cef.CreateBrowserSync(url=html_to_data_uri(HTML_code),window_title="Test")

So, as long as you are using a data URI/URL, I don't think that window.location will be helpful. Instead, you could extract the HTML code into a separate .html file, and change that line to:

    browser = cef.CreateBrowserSync(url="/path/to/that_html_file.html", window_title="Test")
  • Thanks for your reply! I did try write the html part in a separate file and it worked on Windows, but somehow it seems Mac doesn't like this, and that's why I'm trying to find a way to integrate them into a single file. I guess for this I don't really need to change the path, but just a way to import an external .js in the html part, is there a way to do that by any chance? Thanks! – lxiangyun93 May 23 '20 at 06:50
  • Glad to help! But that's interesting, was there a particular error you got on Mac? Because I think fixing that is probably the best bet of making it work. Otherwise, I think you'd have to use the absolute path of any other files (since I don't think anything can be relative to a data URL) – Christian Reall-Fluharty May 23 '20 at 10:05