1
0
mirror of https://github.com/laurent22/joplin.git synced 2024-11-24 08:12:24 +02:00

Clipper: Added Clipper config screen and improved server

This commit is contained in:
Laurent Cozic 2018-05-25 13:30:27 +01:00
parent d11ecd8fac
commit e15f84716a
17 changed files with 303 additions and 29 deletions

View File

@ -1,7 +1,7 @@
{ {
"manifest_version": 2, "manifest_version": 2,
"name": "Joplin Web Clipper", "name": "Joplin Web Clipper",
"version": "1.0", "version": "1.0.1",
"description": "Gets and saves content from your browser to Joplin.", "description": "Gets and saves content from your browser to Joplin.",

View File

@ -4,10 +4,42 @@
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
"fs-extra": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-6.0.1.tgz",
"integrity": "sha512-GnyIkKhhzXZUWFCaJzvyDLEEgDkPfb4/TPvJCJVuS8MWZgoSsErf++QpiAlDnKFcqhRlm+tIOcencCjyJE6ZCA==",
"dev": true,
"requires": {
"graceful-fs": "^4.1.2",
"jsonfile": "^4.0.0",
"universalify": "^0.1.0"
}
},
"graceful-fs": {
"version": "4.1.11",
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
"integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
"dev": true
},
"jsonfile": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz",
"integrity": "sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss=",
"dev": true,
"requires": {
"graceful-fs": "^4.1.6"
}
},
"readability-node": { "readability-node": {
"version": "0.1.0", "version": "0.1.0",
"resolved": "https://registry.npmjs.org/readability-node/-/readability-node-0.1.0.tgz", "resolved": "https://registry.npmjs.org/readability-node/-/readability-node-0.1.0.tgz",
"integrity": "sha1-DUBacMLCFZRKf0qbX3UGzQWpsao=" "integrity": "sha1-DUBacMLCFZRKf0qbX3UGzQWpsao="
},
"universalify": {
"version": "0.1.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.1.tgz",
"integrity": "sha1-+nG63UQ3r0wUiEHjs7Fl+enlkLc=",
"dev": true
} }
} }
} }

View File

@ -10,5 +10,8 @@
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"readability-node": "^0.1.0" "readability-node": "^0.1.0"
},
"devDependencies": {
"fs-extra": "^6.0.1"
} }
} }

View File

@ -2,7 +2,6 @@ import React, { Component } from 'react';
import './App.css'; import './App.css';
const { connect } = require('react-redux'); const { connect } = require('react-redux');
const Global = require('./Global');
const { bridge } = require('./bridge'); const { bridge } = require('./bridge');
class AppComponent extends Component { class AppComponent extends Component {

View File

@ -3,7 +3,7 @@ import ReactDOM from 'react-dom';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
const { connect, Provider } = require('react-redux'); const { Provider } = require('react-redux');
const { bridge } = require('./bridge'); const { bridge } = require('./bridge');
const { createStore } = require('redux'); const { createStore } = require('redux');

View File

@ -34,9 +34,6 @@ const reservedPorts = [1024, 1027, 1028, 1029, 1058, 1059, 1080, 1085, 1098, 109
// From https://github.com/coverslide/node-alea // From https://github.com/coverslide/node-alea
const AleaModule = function () { const AleaModule = function () {
'use strict';
// importState to sync generator states // importState to sync generator states
Alea.importState = function(i){ Alea.importState = function(i){
var random = new Alea(); var random = new Alea();
@ -54,8 +51,8 @@ const AleaModule = function () {
var s2 = 0; var s2 = 0;
var c = 1; var c = 1;
if (args.length == 0) { if (args.length === 0) {
args = [+new Date]; args = [+new Date()];
} }
var mash = Mash(); var mash = Mash();
s0 = mash(' '); s0 = mash(' ');

View File

@ -23,6 +23,7 @@ const DecryptionWorker = require('lib/services/DecryptionWorker');
const InteropService = require('lib/services/InteropService'); const InteropService = require('lib/services/InteropService');
const InteropServiceHelper = require('./InteropServiceHelper.js'); const InteropServiceHelper = require('./InteropServiceHelper.js');
const ResourceService = require('lib/services/ResourceService'); const ResourceService = require('lib/services/ResourceService');
const ClipperServer = require('lib/ClipperServer');
const { bridge } = require('electron').remote.require('./bridge'); const { bridge } = require('electron').remote.require('./bridge');
const Menu = bridge().Menu; const Menu = bridge().Menu;
@ -459,6 +460,14 @@ class Application extends BaseApplication {
}, { }, {
type: 'separator', type: 'separator',
screens: ['Main'], screens: ['Main'],
},{
label: _('Web clipper options'),
click: () => {
this.dispatch({
type: 'NAV_GO',
routeName: 'ClipperConfig',
});
}
},{ },{
label: _('Encryption options'), label: _('Encryption options'),
click: () => { click: () => {
@ -662,6 +671,17 @@ class Application extends BaseApplication {
DecryptionWorker.instance().scheduleStart(); DecryptionWorker.instance().scheduleStart();
}); });
} }
const clipperLogger = new Logger();
clipperLogger.addTarget('file', { path: Setting.value('profileDir') + '/log-clipper.txt' });
clipperLogger.addTarget('console');
ClipperServer.instance().setLogger(clipperLogger);
ClipperServer.instance().setDispatch(this.store().dispatch);
if (Setting.value('clipperServer.autoStart')) {
ClipperServer.instance().start();
}
} }
} }

File diff suppressed because one or more lines are too long

View File

@ -13,6 +13,7 @@ const { StatusScreen } = require('./StatusScreen.min.js');
const { ImportScreen } = require('./ImportScreen.min.js'); const { ImportScreen } = require('./ImportScreen.min.js');
const { ConfigScreen } = require('./ConfigScreen.min.js'); const { ConfigScreen } = require('./ConfigScreen.min.js');
const { EncryptionConfigScreen } = require('./EncryptionConfigScreen.min.js'); const { EncryptionConfigScreen } = require('./EncryptionConfigScreen.min.js');
const { ClipperConfigScreen } = require('./ClipperConfigScreen.min.js');
const { Navigator } = require('./Navigator.min.js'); const { Navigator } = require('./Navigator.min.js');
const { app } = require('../app'); const { app } = require('../app');
@ -86,6 +87,7 @@ class RootComponent extends React.Component {
Config: { screen: ConfigScreen, title: () => _('Options') }, Config: { screen: ConfigScreen, title: () => _('Options') },
Status: { screen: StatusScreen, title: () => _('Synchronisation Status') }, Status: { screen: StatusScreen, title: () => _('Synchronisation Status') },
EncryptionConfig: { screen: EncryptionConfigScreen, title: () => _('Encryption Options') }, EncryptionConfig: { screen: EncryptionConfigScreen, title: () => _('Encryption Options') },
ClipperConfig: { screen: ClipperConfigScreen, title: () => _('Clipper Options') },
}; };
return ( return (

View File

@ -5452,6 +5452,11 @@
"semver": "5.4.1" "semver": "5.4.1"
} }
}, },
"server-destroy": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz",
"integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0="
},
"set-blocking": { "set-blocking": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",

View File

@ -114,6 +114,7 @@
"read-chunk": "^2.1.0", "read-chunk": "^2.1.0",
"readability-node": "^0.1.0", "readability-node": "^0.1.0",
"redux": "^3.7.2", "redux": "^3.7.2",
"server-destroy": "^1.0.1",
"smalltalk": "^2.5.1", "smalltalk": "^2.5.1",
"sprintf-js": "^1.1.1", "sprintf-js": "^1.1.1",
"sqlite3": "^3.1.13", "sqlite3": "^3.1.13",

View File

@ -34,7 +34,6 @@ const SyncTargetDropbox = require('lib/SyncTargetDropbox.js');
const EncryptionService = require('lib/services/EncryptionService'); const EncryptionService = require('lib/services/EncryptionService');
const DecryptionWorker = require('lib/services/DecryptionWorker'); const DecryptionWorker = require('lib/services/DecryptionWorker');
const BaseService = require('lib/services/BaseService'); const BaseService = require('lib/services/BaseService');
const ClipperServer = require('lib/ClipperServer');
SyncTargetRegistry.addClass(SyncTargetFilesystem); SyncTargetRegistry.addClass(SyncTargetFilesystem);
SyncTargetRegistry.addClass(SyncTargetOneDrive); SyncTargetRegistry.addClass(SyncTargetOneDrive);
@ -493,13 +492,6 @@ class BaseApplication {
// await this.testing();process.exit(); // await this.testing();process.exit();
const clipperLogger = new Logger();
clipperLogger.addTarget('file', { path: profileDir + '/log-clipper.txt' });
clipperLogger.addTarget('console');
this.clipperServer_ = new ClipperServer();
this.clipperServer_.setLogger(clipperLogger);
this.clipperServer_.start();
return argv; return argv;
} }

View File

@ -12,11 +12,21 @@ const { Logger } = require('lib/logger.js');
const markdownUtils = require('lib/markdownUtils'); const markdownUtils = require('lib/markdownUtils');
const mimeUtils = require('lib/mime-utils.js').mime; const mimeUtils = require('lib/mime-utils.js').mime;
const randomClipperPort = require('lib/randomClipperPort'); const randomClipperPort = require('lib/randomClipperPort');
const enableServerDestroy = require('server-destroy');
class ClipperServer { class ClipperServer {
constructor() { constructor() {
this.logger_ = new Logger(); this.logger_ = new Logger();
this.startState_ = 'idle';
this.server_ = null;
this.port_ = null;
}
static instance() {
if (this.instance_) return this.instance_;
this.instance_ = new ClipperServer();
return this.instance_;
} }
setLogger(l) { setLogger(l) {
@ -27,6 +37,41 @@ class ClipperServer {
return this.logger_; return this.logger_;
} }
setDispatch(d) {
this.dispatch_ = d;
}
dispatch(action) {
if (!this.dispatch_) throw new Error('dispatch not set!');
this.dispatch_(action);
}
setStartState(v) {
if (this.startState_ === v) return;
this.startState_ = v;
this.dispatch({
type: 'CLIPPER_SERVER_SET',
startState: v,
});
}
setPort(v) {
if (this.port_ === v) return;
this.port_ = v;
this.dispatch({
type: 'CLIPPER_SERVER_SET',
port: v,
});
}
// startState() {
// return this.startState_;
// }
// port() {
// return this.port_;
// }
htmlToMdParser() { htmlToMdParser() {
if (this.htmlToMdParser_) return this.htmlToMdParser_; if (this.htmlToMdParser_) return this.htmlToMdParser_;
this.htmlToMdParser_ = new HtmlToMd(); this.htmlToMdParser_ = new HtmlToMd();
@ -167,18 +212,22 @@ class ClipperServer {
} }
async start() { async start() {
let port = null; this.setPort(null);
this.setStartState('starting');
try { try {
port = await this.findAvailablePort(); const p = await this.findAvailablePort();
this.setPort(p);
} catch (error) { } catch (error) {
this.setStartState('idle');
this.logger().error(error); this.logger().error(error);
return; return;
} }
const server = require('http').createServer(); this.server_ = require('http').createServer();
server.on('request', (request, response) => { this.server_.on('request', (request, response) => {
const writeCorsHeaders = (code) => { const writeCorsHeaders = (code) => {
response.writeHead(code, { response.writeHead(code, {
@ -253,13 +302,24 @@ class ClipperServer {
} }
}); });
server.on('close', () => { this.server_.on('close', () => {
}); });
this.logger().info('Starting Clipper server on port ' + port); enableServerDestroy(this.server_);
server.listen(port); this.logger().info('Starting Clipper server on port ' + this.port_);
this.server_.listen(this.port_);
this.setStartState('started');
}
async stop() {
this.server_.destroy();
this.server_ = null;
this.setStartState('idle');
this.setPort(null);
} }
} }

View File

@ -102,6 +102,7 @@ class Setting extends BaseModel {
'style.zoom': {value: "100", type: Setting.TYPE_INT, public: true, appTypes: ['desktop'], label: () => _('Global zoom percentage'), minimum: "50", maximum: "500", step: "10"}, 'style.zoom': {value: "100", type: Setting.TYPE_INT, public: true, appTypes: ['desktop'], label: () => _('Global zoom percentage'), minimum: "50", maximum: "500", step: "10"},
'style.editor.fontFamily': {value: "", type: Setting.TYPE_STRING, public: true, appTypes: ['desktop'], label: () => _('Editor font family'), description: () => _('The font name will not be checked. If incorrect or empty, it will default to a generic monospace font.')}, 'style.editor.fontFamily': {value: "", type: Setting.TYPE_STRING, public: true, appTypes: ['desktop'], label: () => _('Editor font family'), description: () => _('The font name will not be checked. If incorrect or empty, it will default to a generic monospace font.')},
'autoUpdateEnabled': { value: true, type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Automatically update the application') }, 'autoUpdateEnabled': { value: true, type: Setting.TYPE_BOOL, public: true, appTypes: ['desktop'], label: () => _('Automatically update the application') },
'clipperServer.autoStart': { value: false, type: Setting.TYPE_BOOL, public: false },
'sync.interval': { value: 300, type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation interval'), options: () => { 'sync.interval': { value: 300, type: Setting.TYPE_INT, isEnum: true, public: true, label: () => _('Synchronisation interval'), options: () => {
return { return {
0: _('Disabled'), 0: _('Disabled'),

View File

@ -34,9 +34,6 @@ const reservedPorts = [1024, 1027, 1028, 1029, 1058, 1059, 1080, 1085, 1098, 109
// From https://github.com/coverslide/node-alea // From https://github.com/coverslide/node-alea
const AleaModule = function () { const AleaModule = function () {
'use strict';
// importState to sync generator states // importState to sync generator states
Alea.importState = function(i){ Alea.importState = function(i){
var random = new Alea(); var random = new Alea();
@ -54,8 +51,8 @@ const AleaModule = function () {
var s2 = 0; var s2 = 0;
var c = 1; var c = 1;
if (args.length == 0) { if (args.length === 0) {
args = [+new Date]; args = [+new Date()];
} }
var mash = Mash(); var mash = Mash();
s0 = mash(' '); s0 = mash(' ');

View File

@ -27,6 +27,10 @@ const defaultState = {
hasDisabledSyncItems: false, hasDisabledSyncItems: false,
newNote: null, newNote: null,
collapsedFolderIds: [], collapsedFolderIds: [],
clipperServer: {
startState: 'idle',
port: null,
},
}; };
const stateUtils = {}; const stateUtils = {};
@ -525,7 +529,16 @@ const reducer = (state = defaultState, action) => {
newState = Object.assign({}, state); newState = Object.assign({}, state);
newState.newNote = action.item; newState.newNote = action.item;
break; break;
case 'CLIPPER_SERVER_SET':
newState = Object.assign({}, state);
const clipperServer = Object.assign({}, newState.clipperServer);
if ('startState' in action) clipperServer.startState = action.startState;
if ('port' in action) clipperServer.port = action.port;
newState.clipperServer = clipperServer;
break;
} }
} catch (error) { } catch (error) {

46
Tools/release-clipper.js Normal file
View File

@ -0,0 +1,46 @@
const fs = require('fs-extra');
const { execCommand } = require('./tool-utils.js');
const clipperDir = __dirname + '/../Clipper/joplin-webclipper';
async function copyDir(baseSourceDir, sourcePath, baseDestDir) {
await fs.mkdirp(baseDestDir + '/' + sourcePath);
await fs.copy(baseSourceDir + '/' + sourcePath, baseDestDir + '/' + sourcePath);
}
async function copyToDist(distDir) {
await copyDir(clipperDir, 'popup/build', distDir);
await copyDir(clipperDir, 'content_scripts', distDir);
await copyDir(clipperDir, 'icons', distDir);
await fs.copy(clipperDir + '/background.js', distDir + '/background.js');
await fs.copy(clipperDir + '/main.js', distDir + '/main.js');
await fs.copy(clipperDir + '/manifest.json', distDir + '/manifest.json');
await fs.remove(distDir + '/popup/build/manifest.json');
}
async function main() {
process.chdir(clipperDir + '/popup');
console.info(await execCommand('npm run build'));
const dists = [
{
dir: clipperDir + '/dist/chrometest',
name: 'chrome',
}
];
for (let i = 0; i < dists.length; i++) {
const dist = dists[i];
await copyToDist(dist.dir);
process.chdir(dist.dir);
console.info(await execCommand('7z a -tzip ' + dist.name + '.zip *'));
}
}
main().catch((error) => {
console.error('Fatal error');
console.error(error);
process.exit(1);
});