electron app:
- add file association for .wacz - support opening wacz, warc, har files via double-click from os (fixes #24) - command line: support opening files via command line, as well as specifying --url and --ts - support cmdline args via 'yarn run start-electron <file> --url <url> --ts <ts>'
This commit is contained in:
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
v1.2.1
|
v1.2.1
|
||||||
- Loading/UI: Fix Google Drive Loading/Reauthorization: Only trigger when reauth is needed. For rate-limit errors, attempt reloading more slowly (exponential backoff)
|
- Loading/UI: Fix Google Drive Loading/Reauthorization: Only trigger when reauth is needed. For rate-limit errors, attempt reloading more slowly (exponential backoff)
|
||||||
|
- Loading: ReplayWeb.page App supports opening WACZ, WARC and HAR files via double-clicking from OS and via command-line.
|
||||||
|
|
||||||
v1.2.0
|
v1.2.0
|
||||||
- UI: Location bar fixes: Enter reloads same URL, Escape restores current URL, properly updated on navigation, Favicon displayed in location bar if available
|
- UI: Location bar fixes: Enter reloads same URL, Escape restores current URL, properly updated on navigation, Favicon displayed in location bar if available
|
||||||
|
|||||||
+8
-1
@@ -17,6 +17,7 @@
|
|||||||
"lit-element": "^2.3.1",
|
"lit-element": "^2.3.1",
|
||||||
"marked": "^1.0.0",
|
"marked": "^1.0.0",
|
||||||
"mime-types": "^2.1.27",
|
"mime-types": "^2.1.27",
|
||||||
|
"minimist": "^1.2.5",
|
||||||
"pretty-bytes": "^5.3.0",
|
"pretty-bytes": "^5.3.0",
|
||||||
"register-service-worker": "^1.7.1",
|
"register-service-worker": "^1.7.1",
|
||||||
"split.js": "^1.6.2"
|
"split.js": "^1.6.2"
|
||||||
@@ -52,7 +53,7 @@
|
|||||||
"start-prod": "http-server -p 9990",
|
"start-prod": "http-server -p 9990",
|
||||||
"pack": "CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --publish never",
|
"pack": "CSC_IDENTITY_AUTO_DISCOVERY=false electron-builder --publish never",
|
||||||
"pack-signed": "electron-builder",
|
"pack-signed": "electron-builder",
|
||||||
"start-electron": "NODE_ENV=development electron ./dist/electron.js",
|
"start-electron": "NODE_ENV=development electron ./dist/electron.js $1",
|
||||||
"start-jekyll": "yarn run build-docs && bundle exec jekyll serve",
|
"start-jekyll": "yarn run build-docs && bundle exec jekyll serve",
|
||||||
"dist": "yarn run build && yarn run pack",
|
"dist": "yarn run build && yarn run pack",
|
||||||
"release": "yarn run build && electron-builder"
|
"release": "yarn run build && electron-builder"
|
||||||
@@ -130,6 +131,12 @@
|
|||||||
"name": "HAR File",
|
"name": "HAR File",
|
||||||
"description": "HAR File",
|
"description": "HAR File",
|
||||||
"role": "Viewer"
|
"role": "Viewer"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ext": "wacz",
|
||||||
|
"name": "WACZ File",
|
||||||
|
"description": "Web Archive Collection Zipped (WACZ)",
|
||||||
|
"role": "Viewer"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -374,6 +374,15 @@ class App extends LitElement
|
|||||||
}
|
}
|
||||||
this.loadInfo.customColl = this.pageParams.get("customColl");
|
this.loadInfo.customColl = this.pageParams.get("customColl");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (IS_APP && this.sourceUrl.startsWith("file://")) {
|
||||||
|
const url = new URL(__APP_FILE_SERVE_PREFIX__);
|
||||||
|
url.searchParams.set("filename", this.sourceUrl.slice("file://".length));
|
||||||
|
this.loadInfo = {
|
||||||
|
sourceUrl: this.sourceUrl,
|
||||||
|
loadUrl: url.href,
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onStartLoad(event) {
|
onStartLoad(event) {
|
||||||
|
|||||||
+133
-104
@@ -3,7 +3,7 @@
|
|||||||
import fetch from 'node-fetch';
|
import fetch from 'node-fetch';
|
||||||
import { Headers } from 'node-fetch';
|
import { Headers } from 'node-fetch';
|
||||||
|
|
||||||
import {app, session, BrowserWindow, ipcMain, shell} from 'electron';
|
import {app, session, BrowserWindow, ipcMain, shell, dialog } from 'electron';
|
||||||
|
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
@@ -13,6 +13,7 @@ import { ArchiveResponse, Rewriter } from '@webrecorder/wabac/src/rewrite';
|
|||||||
import { PassThrough } from 'stream';
|
import { PassThrough } from 'stream';
|
||||||
|
|
||||||
import mime from 'mime-types';
|
import mime from 'mime-types';
|
||||||
|
import { url } from 'inspector';
|
||||||
|
|
||||||
global.Headers = Headers;
|
global.Headers = Headers;
|
||||||
|
|
||||||
@@ -30,55 +31,100 @@ const staticContentPath = path.join(__dirname, "../");
|
|||||||
|
|
||||||
let pluginPath = "";
|
let pluginPath = "";
|
||||||
|
|
||||||
switch (process.platform) {
|
|
||||||
case 'win32':
|
|
||||||
pluginPath = path.join(projPath, "plugins-win", `pepflashplayer-x86${process.arch === 'x64' ? '_64' : ''}.dll`);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'darwin':
|
|
||||||
pluginPath = path.join(projPath, "plugins-mac", "PepperFlashPlayer.plugin");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'linux':
|
|
||||||
pluginPath = path.join(projPath, "plugins-mac", "libpepflashplayer.so");
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
console.log('platform unsupported: ' + process.platform);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
console.log('app path', appPath);
|
|
||||||
console.log('dir name', __dirname);
|
|
||||||
console.log('proj path', projPath);
|
|
||||||
console.log('plugin path', pluginPath);
|
|
||||||
|
|
||||||
|
|
||||||
console.log('app data', app.getPath('appData'));
|
|
||||||
|
|
||||||
app.setPath('userData', path.join(app.getPath('appData'), 'replaywebpage'));
|
|
||||||
|
|
||||||
console.log('user data', app.getPath('userData'));
|
|
||||||
|
|
||||||
app.commandLine.appendSwitch('ppapi-flash-path', pluginPath);
|
|
||||||
|
|
||||||
|
|
||||||
var proxyColl;
|
var proxyColl;
|
||||||
var proxyTS;
|
var proxyTS;
|
||||||
|
|
||||||
var mainWindow;
|
var mainWindow;
|
||||||
|
|
||||||
// Single instance lock
|
let openNextFile = null;
|
||||||
const gotTheLock = app.requestSingleInstanceLock();
|
|
||||||
|
|
||||||
if (!gotTheLock) {
|
|
||||||
console.log("App already running, opening new window in first instance and quitting");
|
function main() {
|
||||||
app.quit();
|
switch (process.platform) {
|
||||||
} else {
|
case 'win32':
|
||||||
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
pluginPath = path.join(projPath, "plugins-win", `pepflashplayer-x86${process.arch === 'x64' ? '_64' : ''}.dll`);
|
||||||
// Just create a new window in case of second instance request
|
break;
|
||||||
createWindow();
|
|
||||||
|
case 'darwin':
|
||||||
|
pluginPath = path.join(projPath, "plugins-mac", "PepperFlashPlayer.plugin");
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'linux':
|
||||||
|
pluginPath = path.join(projPath, "plugins-mac", "libpepflashplayer.so");
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
console.log('platform unsupported: ' + process.platform);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
console.log('app path', appPath);
|
||||||
|
console.log('dir name', __dirname);
|
||||||
|
console.log('proj path', projPath);
|
||||||
|
console.log('plugin path', pluginPath);
|
||||||
|
|
||||||
|
|
||||||
|
console.log('app data', app.getPath('appData'));
|
||||||
|
|
||||||
|
app.setPath('userData', path.join(app.getPath('appData'), 'replaywebpage'));
|
||||||
|
|
||||||
|
console.log('user data', app.getPath('userData'));
|
||||||
|
|
||||||
|
app.commandLine.appendSwitch('ppapi-flash-path', pluginPath);
|
||||||
|
|
||||||
|
app.on('will-finish-launching', function() {
|
||||||
|
app.on('open-file', function(event, filePath) {
|
||||||
|
openNextFile = filePath;
|
||||||
|
if (mainWindow) {
|
||||||
|
createWindow(process.argv)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Single instance lock
|
||||||
|
const gotTheLock = app.requestSingleInstanceLock();
|
||||||
|
|
||||||
|
if (!gotTheLock) {
|
||||||
|
console.log("App already running, opening new window in first instance and quitting");
|
||||||
|
app.quit();
|
||||||
|
} else {
|
||||||
|
app.on('second-instance', (event, commandLine, workingDirectory) => {
|
||||||
|
// Just create a new window in case of second instance request
|
||||||
|
dialog.showErrorBox("new window", JSON.stringify(commandLine));
|
||||||
|
createWindow(commandLine);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
app.on('web-contents-created', (event, contents) => {
|
||||||
|
contents.on('new-window', async (event, navigationUrl) => {
|
||||||
|
|
||||||
|
// load docs in native browser for now
|
||||||
|
if (navigationUrl === STATIC_PREFIX + "docs") {
|
||||||
|
event.preventDefault();
|
||||||
|
await shell.openExternal("https://replayweb.page/docs/");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
app.whenReady().then(() => {
|
||||||
|
mainWindow = createWindow(process.argv);
|
||||||
|
|
||||||
|
app.on('activate', function () {
|
||||||
|
// On macOS it's common to re-create a window in the app when the
|
||||||
|
// dock icon is clicked and there are no other windows open.
|
||||||
|
if (BrowserWindow.getAllWindows().length === 0) {
|
||||||
|
mainWindow = createWindow();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
// Quit when all windows are closed.
|
||||||
|
app.on('window-all-closed', function () {
|
||||||
|
// On macOS it is common for applications and their menu bar
|
||||||
|
// to stay active until the user quits explicitly with Cmd + Q
|
||||||
|
//if (process.platform !== 'darwin')
|
||||||
|
app.quit();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -90,9 +136,6 @@ function bufferToStream(data) {
|
|||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
async function doIntercept(request, callback) {
|
async function doIntercept(request, callback) {
|
||||||
console.log(`${request.method} ${request.url} from ${request.referrer}`);
|
console.log(`${request.method} ${request.url} from ${request.referrer}`);
|
||||||
|
|
||||||
@@ -270,15 +313,17 @@ function parseRange(reqHeaders, headers, size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
function createWindow () {
|
function createWindow(argv, secondWindow) {
|
||||||
const sesh = session.defaultSession;
|
const sesh = session.defaultSession;
|
||||||
|
|
||||||
//sesh.protocol.interceptStreamProtocol("file", doIntercept);
|
if (!secondWindow) {
|
||||||
sesh.protocol.interceptStreamProtocol("http", doIntercept);
|
sesh.protocol.interceptStreamProtocol("http", doIntercept);
|
||||||
//sesh.protocol.interceptStreamProtocol("https", doIntercept);
|
}
|
||||||
|
|
||||||
|
const sourceString = getOpenUrl(argv);
|
||||||
|
|
||||||
// Create the browser window.
|
// Create the browser window.
|
||||||
mainWindow = new BrowserWindow({
|
const theWindow = new BrowserWindow({
|
||||||
width: 1024,
|
width: 1024,
|
||||||
height: 768,
|
height: 768,
|
||||||
isMaximized: true,
|
isMaximized: true,
|
||||||
@@ -291,66 +336,50 @@ function createWindow () {
|
|||||||
enableRemoteModule: false
|
enableRemoteModule: false
|
||||||
}
|
}
|
||||||
}).once('ready-to-show', () => {
|
}).once('ready-to-show', () => {
|
||||||
|
theWindow.show();
|
||||||
//const sesh = session.fromPartition("persist:replay");
|
theWindow.maximize();
|
||||||
|
|
||||||
//const filter = {"urls": ['*://*/*']};
|
|
||||||
//sesh.webRequest.onBeforeRequest(filter, (request, callback) => {
|
|
||||||
// console.log("got onBeforeRequest");
|
|
||||||
// callback({cancel: false});
|
|
||||||
//});
|
|
||||||
|
|
||||||
//sesh.protocol.interceptStreamProtocol("http", doIntercept);
|
|
||||||
//sesh.protocol.interceptStreamProtocol("https", doIntercept);
|
|
||||||
|
|
||||||
mainWindow.show();
|
|
||||||
mainWindow.maximize();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
mainWindow.loadURL(STATIC_PREFIX + "index.html");
|
theWindow.loadURL(STATIC_PREFIX + "index.html" + sourceString);
|
||||||
if (process.env.NODE_ENV === "development") {
|
if (process.env.NODE_ENV === "development") {
|
||||||
mainWindow.webContents.openDevTools();
|
theWindow.webContents.openDevTools();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return theWindow;
|
||||||
}
|
}
|
||||||
|
|
||||||
app.on('web-contents-created', (event, contents) => {
|
function getOpenUrl(argv) {
|
||||||
contents.on('new-window', async (event, navigationUrl) => {
|
argv = require('minimist')(argv.slice(process.defaultApp ? 2 : 1));
|
||||||
|
|
||||||
// load docs in native browser for now
|
const filename = openNextFile || argv.filename || argv.f || (argv._.length && argv._[0]);
|
||||||
if (navigationUrl === STATIC_PREFIX + "docs") {
|
|
||||||
event.preventDefault();
|
let sourceString = "";
|
||||||
await shell.openExternal("https://replayweb.page/docs/");
|
|
||||||
|
if (filename) {
|
||||||
|
const sourceParams = new URLSearchParams();
|
||||||
|
sourceParams.set("source", "file://" + filename);
|
||||||
|
sourceString = "?" + sourceParams.toString();
|
||||||
|
|
||||||
|
const urlParams = new URLSearchParams();
|
||||||
|
|
||||||
|
const openUrl = argv.url;
|
||||||
|
|
||||||
|
const openTS = argv.ts || argv.timestamp;
|
||||||
|
|
||||||
|
if (openUrl) {
|
||||||
|
urlParams.set("url", openUrl);
|
||||||
}
|
}
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// This method will be called when Electron has finished
|
if (openTS) {
|
||||||
// initialization and is ready to create browser windows.
|
urlParams.set("ts", openTS);
|
||||||
// Some APIs can only be used after this event occurs.
|
}
|
||||||
app.whenReady().then(() => {
|
|
||||||
createWindow();
|
|
||||||
|
|
||||||
app.on('activate', function () {
|
|
||||||
// On macOS it's common to re-create a window in the app when the
|
|
||||||
// dock icon is clicked and there are no other windows open.
|
|
||||||
if (BrowserWindow.getAllWindows().length === 0) createWindow()
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
// Quit when all windows are closed.
|
sourceString += "#" + urlParams.toString();
|
||||||
app.on('window-all-closed', function () {
|
|
||||||
// On macOS it is common for applications and their menu bar
|
|
||||||
// to stay active until the user quits explicitly with Cmd + Q
|
|
||||||
//if (process.platform !== 'darwin')
|
|
||||||
app.quit();
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
console.log(`Opening Source: ${sourceString}`);
|
||||||
app.on('web-contents-created', (event, contents) => {
|
|
||||||
if (contents.getType() === "webview") {
|
|
||||||
contents.openDevTools();
|
|
||||||
} else if (contents.getType() === "window") {
|
|
||||||
console.log("main contents set")
|
|
||||||
mainContents = contents;
|
|
||||||
}
|
}
|
||||||
});*/
|
|
||||||
|
return sourceString;
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
||||||
|
|||||||
+1
-1
@@ -35,7 +35,7 @@ const electronMainConfig = (env, argv) => {
|
|||||||
__APP_FILE_SERVE_PREFIX__ : JSON.stringify(APP_FILE_SERVE_PREFIX),
|
__APP_FILE_SERVE_PREFIX__ : JSON.stringify(APP_FILE_SERVE_PREFIX),
|
||||||
__HELPER_PROXY__ : JSON.stringify(HELPER_PROXY)
|
__HELPER_PROXY__ : JSON.stringify(HELPER_PROXY)
|
||||||
})
|
})
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user