Binderhub: Browser backed storage of notebook contents

Created on 21 Nov 2019  路  15Comments  路  Source: jupyterhub/binderhub

Following on from https://github.com/jupyterhub/binderhub/issues/1003#issuecomment-555726161

This issue is for discussions specific to the idea of creating a notebook extension that also stores the content of the notebook in "browser storage" and later offers the user a way to download the notebook 9if the binder has gone away) and even later offers the user the option to relaunch the binder with this notebook.

As a first version this is a "nice to have" so if we can get something that works "now" for 80% of users that is better than waiting longer to get it to work for 95%. This means cross domain issues are out for the moment as are storing files that aren't notebooks. Let's tackle those after we have some experience with the more basic thing.

I think this is something to be implemented as a notebook extension because it is JS. So JS skills will be required to work on this.

cc @manics


General ideas about "persistence" should go in #1003.

Most helpful comment

I think the latest version is in a pretty good state: https://github.com/manics/jupyter-offlinenotebook/tree/0.0.8:

  • Uses IndexedDB via Dexie.js instead of localstorage (notebooks previously saved into localstorage won't be accessible)
  • Repo and Binder link buttons in the notebook toolbar
  • Works in Firefox and Chrome on Fedora Linux

Screenshot from 2019-12-01 21-03-18

How about give it a few days, if there are no issues tag it as 0.1.0 and then roll out?

All 15 comments

I think Kaggle kernels does this "store stuff in the browser" trick too. Need to double check.

Jupyter.notebook.toJSON() turns the current notebook into JSON without using the contents API (which makes a network request).

Unfortunately Jupyter.notebook.fromJSON() isn't the direct inverse. Need to rearrange some of the JSON field names and get. additional metadata.

Looks promising...

function getNotebookFromBrowser() {
    return {
        "content": Jupyter.notebook.toJSON(),
        "name": Jupyter.notebook.notebook_name,
        "path": Jupyter.notebook.notebook_path,
        "format": "json",
        "type": "notebook"
    };
}

function localstoreSaveNotebook() {
    var nb = getNotebookFromBrowser();
    localStorage.setItem(nb["path"], JSON.stringify(nb));
    console.log("local-storage saved: " + nb["path"])
}

function localstoreLoadNotebook(path) {
    var path = path || Jupyter.notebook.notebook_path;
    var nb = localStorage.getItem(path);
    if (nb) {
        Jupyter.notebook.fromJSON(JSON.parse(nb));
        console.log("local-storage loaded " + path)
    }
    else {
        console.log("local-storage not found: " + path)
    }
}

// Download (size limited) https://stackoverflow.com/a/18197341
function downloadNotebookFromBrowser() {
    var nb = getNotebookFromBrowser();
    var element = document.createElement("a");
    element.setAttribute("href", "data:text/plain;charset=utf-8," + encodeURIComponent(JSON.stringify(nb)));
    element.setAttribute("download", nb["name"]);
    element.style.display = "none";
    document.body.appendChild(element);
    element.click();  
    document.body.removeChild(element);
}

Next step: convert to an extension

Give this a go! https://github.com/manics/jupyter-offlinenotebook
Only tested on firefox

Kapture 2019-11-22 at 17 51 08

Bam! How cool is this??? (also are there browsers that aren't firefox :p)

I tried out the extension in Firefox and Chrome. Works in both.

I've just merged https://github.com/manics/jupyter-offlinenotebook/pull/4 so it'll use BINDER_REPO_URL from https://github.com/jupyterhub/binderhub/pull/1010 (open the javascript console to see what's going on). If it's not set you won't see the buttons.

I was thinking that once #1010 has been merged and deployed: should we add the offlinenotebook extension to repo2docker by default and see if anyone notices/comments on it? I think getting it out there with some real users would be good to get feedback/bug reports/test on weird browsers.

After a while of it being used and worked on we can make an announcement to direct attention to it.

After reading through the notebook docs source code I figured out how to add dialogs on success/failure which I think was the main blocker for usability.

Also had a go at adding binder links, at the moment they're displayed as URLs:

Is there a way to enable it for a subset of repos (e.g. jupyter*/* GitHub repos only) instead of everything at once?

We don't have the ability to use a different version of repo2docker for different repos (yet). I think in practice enabling it for all will lead to a gradual rollout because most users don't rebuild a repo, they use one that was already built and hence won't show this extension.

If we wanted to make it a really small rollout I think we'd either have to build the infrastructure for switching repos to different versions of r2d or make the extension so that it rolls a random number and only turns itself on for a small fraction of builds.

Past experience suggests that most people don't notice when we do little things like this and only take note/use a feature after some marketing effort. -> I'd add it for all rebuilds and wait for feedback.

I think the latest version is in a pretty good state: https://github.com/manics/jupyter-offlinenotebook/tree/0.0.8:

  • Uses IndexedDB via Dexie.js instead of localstorage (notebooks previously saved into localstorage won't be accessible)
  • Repo and Binder link buttons in the notebook toolbar
  • Works in Firefox and Chrome on Fedora Linux

Screenshot from 2019-12-01 21-03-18

How about give it a few days, if there are no issues tag it as 0.1.0 and then roll out?

Sounds like a good plan!

I was also wondering if we could use the repo2docker appendix to install this in a few repos (something like random.seed(repo_name); if random.random() < 0.1). Maybe that is too much effort compare to adding it to repo2docker directly.

For my education: what does IndexDB get you over local storage? Bigger files?

localstorage is limited to 5-10 MB total per origin. As soon as you embed resources in a notebook such as images you can easily hit it. IndexedDB provides a lot more space, up to 2GB in Firefox https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API/Browser_storage_limits_and_eviction_criteria#Storage_limits

@betatim I've invited you to be a collaborator on https://github.com/manics/jupyter-offlinenotebook/ so it's not dependent on one person.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

choldgraf picture choldgraf  路  6Comments

davidanthoff picture davidanthoff  路  4Comments

melaniewalsh picture melaniewalsh  路  4Comments

yuvipanda picture yuvipanda  路  3Comments

raffadrummer picture raffadrummer  路  4Comments