Compare commits

...

9 Commits

Author SHA1 Message Date
Antoine WEBER f72206156d maj de nwjs 2017-07-10 13:51:00 +02:00
WEBER Antoine 858c5bd713 si la conf n'existe pas on l'ouvre 2015-10-12 19:16:48 +02:00
WEBER Antoine 36838263a3 modification pour build 2015-10-12 19:03:28 +02:00
WEBER Antoine 7f52b8b8a4 modif du chargement 2015-10-12 09:44:48 +02:00
WEBER Antoine 38759dc9d4 modif du chargement 2015-10-11 22:21:01 +02:00
WEBER Antoine 83c11eaa96 mode application clusterisé 2015-10-11 22:15:49 +02:00
WEBER Antoine a9205daf7e mode application clusterisé 2015-10-11 22:13:49 +02:00
WEBER Antoine b3e2fe85bc creation du menu avec tray icon 2015-10-09 21:12:23 +02:00
Antoine WEBER 9e01dd3724 modification de la TODOLIST 2015-10-08 12:19:05 +02:00
11 changed files with 2912 additions and 178 deletions

View File

@ -7,11 +7,18 @@ Ce projet permet de créer une liste de vos fichiers vidéo plex et de les parta
INSTALLATION
--------------------
il existe des version packagé pour window et mac, où vous n'avez plus qu'à éditer votre configuration avant de lancer le serveur
voir ici:
INSTALLATION MANUELLE
--------------------
**Sur Windows**
pré requis, installer git ( https://git-scm.com/download/win )
pré requis, installer nodejs 0.12.x ( https://nodejs.org/dist/v0.12.7/ )
pré requis, installer nodewebkit (http://dl.nwjs.io/v0.12.3/nwjs-v0.12.3-win-ia32.zip)
ouvrir l'invite de commande 'cmb', puis se deplacer dans un repertoire où vous voulez installer
@ -32,15 +39,7 @@ INSTALLATION
**Sous MacOS**
pré requis, nodejs
sinon installer homebrew
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
et :
brew install node
pré requis, nodewebkit ( http://dl.nwjs.io/v0.12.3/nwjs-v0.12.3-osx-ia32.zip )
git clone https://github.com/TwanoO67/plex-web-downloader.git
@ -57,29 +56,7 @@ INSTALLATION
puis ouvrir dans votre navigateur l'adresse http://localhost:3000
**Sous Ubuntu**
pré requis nodejs, ou
apt-get install nodejs
ln -s /usr/bin/nodejs /usr/local/bin/node
puis, se déplacer dans votre repertoire pour l'install et :
git clone https://github.com/TwanoO67/plex-web-downloader.git
cd plex-web-downloader
npm install
modifier le fichier config.js, pour y mettre le chemin de la base de données plex
exemple: /home/yourUsername/plex-config/Plex Media Server/Plug-in Support/Databases/com.plexapp.plugins.library.db
npm start
puis ouvrir dans votre navigateur l'adresse http://localhost:3000
@ -115,19 +92,21 @@ DEVELOPPEMENT
puis configurer vos chaines sur: http://localhost:32400/web/index.html
COMPILATION
PACKAGING
--------------------
voir ici: https://github.com/nwjs/nw.js/wiki/Using-Node-modules
npm install enclose -g
sudo npm install
enclose -o bin/mac_bin --loglevel info -c enclose_config.js -v 0.12.7 ./bin/www
sudo npm install nw-gyp -g
sudo nw-gyp rebuild --target=0.12.3
TODO Liste
--------------------
* Ajouter une présentation sur l'index, configurable dans config.js
* Gérer les images des vignettes
* Faire une page spéciales pour les séries
* Mutualisé les sources avec un mirroir centralisé
* Gérer les téléchargements multi-source en proposant un lien aria2 (voir aria2.sourceforge.net)
* Intégré web ui: http://ziahamza.github.io/webui-aria2/
* Mettre en place une limite d'upload activable à la demande

114
bin/www
View File

@ -1,114 +0,0 @@
#!/usr/bin/env node
//On commence par la mise en cluster
var cluster = require('cluster');
// Code to run if we're in the master process
if (cluster.isMaster) {
// Count the machine's CPUs
var cpuCount = require('os').cpus().length;
// Create a worker for each CPU
for (var i = 0; i < cpuCount; i += 1) {
console.log('Création du fork ' + i);
cluster.fork();
}
// Listen for dying workers
cluster.on('exit', function (worker) {
// Replace the dead worker, we're not sentimental
console.log('Worker ' + worker.id + ' died :(');
cluster.fork();
console.log('Remplacement du worker ');
});
// Code to run if we're in a worker process
} else {
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('plex_webdown:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
}
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}

13
index.html Normal file
View File

@ -0,0 +1,13 @@
<!DOCTYPE html>
<html>
<head>
<title>PLEX Web Downloader</title>
<script src="./js/startup.js"></script>
</head>
<body>
<section>
Chargement en cours...
</section>
</body>
</html>

View File

@ -4,17 +4,17 @@ var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var config = require('./config');
var config = require('../config');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('views', path.join(__dirname, '../views'));
app.set('view engine', 'jade');
//protection par mot de passe
if( typeof config.auth_user !== 'undefined' && typeof config.auth_password !== 'undefined' ){
console.log("SAFE MODE: votre serveur est protégé par mot de passe.");
//console.log("SAFE MODE: votre serveur est protégé par mot de passe.");
var basicAuth = require('basic-auth');
app.use(function(req, res, next) {
var user = basicAuth(req);
@ -27,9 +27,9 @@ if( typeof config.auth_user !== 'undefined' && typeof config.auth_password !== '
}
});
}
else{
/*else{
console.log("UNSAFE MODE: configurez un auth_user et auth_password dans le fichier config.js");
}
}*/
//envoyer config a tout le monde
app.use(function(req, res, next) {
@ -37,22 +37,22 @@ app.use(function(req, res, next) {
next();
});
app.use(favicon(path.join(__dirname, 'public', 'iconarchive_plex.ico')));
app.use(favicon(path.join(__dirname, '../public', 'iconarchive_plex.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.static(path.join(__dirname, '../public')));
app.use('/', require('./routes/index'));
app.use('/users', require('./routes/users'));
app.use('/file', require('./routes/file'));
app.use('/channel', require('./routes/channel'));
app.use('/movie', require('./routes/movie'));
app.use('/show_list', require('./routes/show_list'));
app.use('/show', require('./routes/show'));
app.use('/divers', require('./routes/divers'));
app.use('/', require('../routes/index'));
app.use('/users', require('../routes/users'));
app.use('/file', require('../routes/file'));
app.use('/channel', require('../routes/channel'));
app.use('/movie', require('../routes/movie'));
app.use('/show_list', require('../routes/show_list'));
app.use('/show', require('../routes/show'));
app.use('/divers', require('../routes/divers'));
// catch 404 and forward to error handler
app.use(function(req, res, next) {

113
js/clustering.js Normal file
View File

@ -0,0 +1,113 @@
//On commence par la mise en cluster
var cluster = require('cluster');
// Code to run if we're in the master process
if (cluster.isMaster) {
// Count the machine's CPUs
var cpuCount = require('os').cpus().length;
// Create a worker for each CPU
for (var i = 0; i < cpuCount; i += 1) {
//console.log('Création du fork ' + i);
cluster.fork();
}
console.log('Création de '+cpuCount+' thread');
// Listen for dying workers
cluster.on('exit', function (worker) {
// Replace the dead worker, we're not sentimental
cluster.fork();
console.log('Remplacement du worker ' + worker.id);
});
// Code to run if we're in a worker process
} else {
/**
* Module dependencies.
*/
var app = require('./build_server');
var debug = require('debug')('plex_webdown:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
/**
* Create HTTP server.
*/
var server = http.createServer(app);
/**
* Listen on provided port, on all network interfaces.
*/
server.listen(port);
server.on('error', onError);
server.on('listening', onListening);
}
/**
* Normalize a port into a number, string, or false.
*/
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
/**
* Event listener for HTTP server "error" event.
*/
function onError(error) {
if (error.syscall !== 'listen') {
throw error;
}
var bind = typeof port === 'string'
? 'Pipe ' + port
: 'Port ' + port;
// handle specific listen errors with friendly messages
switch (error.code) {
case 'EACCES':
console.error(bind + ' requires elevated privileges');
process.exit(1);
break;
case 'EADDRINUSE':
console.error(bind + ' is already in use');
process.exit(1);
break;
default:
throw error;
}
}
/**
* Event listener for HTTP server "listening" event.
*/
function onListening() {
var addr = server.address();
var bind = typeof addr === 'string'
? 'pipe ' + addr
: 'port ' + addr.port;
debug('Listening on ' + bind);
}

112
js/custom-tray-menu.js Normal file
View File

@ -0,0 +1,112 @@
"use strict";
var gui = window.require('nw.gui');
var util = require('util');
class CustomTrayMenu {
constructor(windowPath, trayIcon, windowOptions) {
this.shown = false;
this.iconWidth = 12;
//valeur par défaut
this.trayIcon = trayIcon || 'tray2.png';
this.menuWindowPath = windowPath || 'custom-tray-menu.html';
this.menuWndowOptions = windowOptions || {
width: 185,
height: 143
};
this._initTray();
this._initMenuWindow();
this.tray.on('click', this.toggleTrayMenuAt.bind(this));
}
// remove tray, cose custom menu window
remove() {
this.tray.remove();
this.tray = null;
this.trayMenu.close();
}
_initTray() {
this.tray = new gui.Tray({
title: '',
icon: this.trayIcon,
alticon: '',
tooltip: window.document.title,
iconsAreTemplates: false
});
}
_initMenuWindow() {
var windowOptions = util._extend({
width: 200,
height: 100,
frame: false,
transparent: true,
resizable: false,
show: false,
'show_in_taskbar': process.platform == "darwin"
}, this.menuWndowOptions);
this.trayMenu = gui.Window.open(this.menuWindowPath, windowOptions);
// add class to new window's body to apply platform specific css
this.trayMenu.on('document-end', function() {
this.trayMenu.window.document.body.className += ' ' + process.platform;
//console.log("Adding class " + process.platform);
}.bind(this));
this.trayMenu.on('blur', function () {
this.trayMenu.hide();
this.shown = false;
//console.log('Hide custom menu');
}.bind(this));
}
// called when user click on tray icon
toggleTrayMenuAt(position) {
/*if (this.shown) {
this.trayMenu.hide(); // this will trigger listener added above
this.shown = false;
} else {*/
this.translate(position);
this.trayMenu.moveTo(position.x, position.y);
//global.main_win.show();
//global.main_win.focus();
this.trayMenu.show();
//this.trayMenu.focus();
this.shown = true;
//console.log('Show custom menu');
//}
}
// calculdate position for window to appear
translate(pos) {
//console.log("Click position: " + util.inspect(pos));
if (process.platform == 'darwin') {
pos.x -= Math.floor(this.trayMenu.width / 2 - this.iconWidth);
} else {
pos.x -= Math.floor(this.trayMenu.width / 2);
// for windows can not make exac position, because we have position of click. Just move it 5px up
pos.y -= this._trayAreaIsTop(pos) ? 0 : this.trayMenu.height + this.iconWidth / 2 + 5;
}
}
_trayAreaIsTop(pos) {
var screen;
if (gui.Screen.Init) gui.Screen.Init();
function posInBounds(s) {
return pos.y > s.bounds.y && pos.y < (s.bounds.y + s.bounds.height) &&
pos.x > s.bounds.x && pos.x < (s.bounds.x + s.bounds.width);
}
screen = gui.Screen.screens.filter(posInBounds)[0];
return pos.y < (screen.bounds.y + screen.bounds.height) / 2;
}
}
module.exports = CustomTrayMenu;

92
js/startup.js Normal file
View File

@ -0,0 +1,92 @@
//sur le master on cree l'interface
"use strict";
var gui = require('nw.gui');
var CustomTrayMenu = require('./js/custom-tray-menu');
var win = gui.Window.get();
global.main_win = win;
//Test la presence du fichier de config
var fs = require('fs.extra');
fs.exists('config.js', function(exists) {
if (!exists) {
console.log('Config.js a été ré-initialisé');
fs.copy('config.js_example','config.js');
var child_process = require('child_process');
// exec: spawns a shell.
var cp = child_process.exec('open config.js', function(error, stdout, stderr){
//var gui = require('nw.gui');
//gui.App.closeAllWindows();
//global.main_server.kill();
//gui.App.quit();
});
cp.on('exit',function(stream){
var gui = require('nw.gui');
gui.App.closeAllWindows();
//global.main_server.kill();
gui.App.quit();
});
}
else{
//lancement normal
var config = require('./config');
//Prevenir des informations de config
if( typeof config.auth_user !== 'undefined' && typeof config.auth_password !== 'undefined' ){
console.log("SAFE MODE: votre serveur est protégé par mot de passe.");
}
else{
console.log("UNSAFE MODE: configurez un auth_user et auth_password dans le fichier config.js");
}
if( typeof config.database !== undefined){
fs.exists(config.database, function(exists) {
if (!exists) {
console.log("La base plex n'existe pas. Mettez à jour le champ DATABASE du fichier config.js");
}
else{
console.log("La base plex a bien été trouvée.");
}
});
}
else{
console.log("La base plex n'est pas définie. Mettez à jour le champ DATABASE du fichier config.js");
}
// Extend application menu for Mac OS
if (process.platform == "darwin") {
var menu = new gui.Menu({type: "menubar"});
menu.createMacBuiltin && menu.createMacBuiltin(window.document.title);
win.menu = menu;
}
var $ = function (selector) {
return document.querySelector(selector);
}
var customTray;
customTray = new CustomTrayMenu('views/custom-tray-menu.html', 'public/icon.png', {
width: 200,
height: 180
});
//lancement du serveur
var child_process = require('child_process');
global.main_server = child_process.exec('./bin/node ./js/clustering.js');
//on tue le serveur quand on quite l'interface
process.on('exit', function (exitCode) {
child_process.kill();
});
}
});
win.hide();

View File

@ -1,20 +1,33 @@
{
"name": "plex_webdown",
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node ./bin/www"
"version": "0.1.0",
"main": "index.html",
"window": {
"show": true,
"frame": true,
"toolbar": false,
"focus": true,
"icon": "public/iconarchive_plex.ico",
"width": 550,
"height": 348
},
"scripts": {
"start": "nw .",
"vers": "nw --version"
},
"private": true,
"dependencies": {
"basic-auth": "^1.0.3",
"body-parser": "~1.13.2",
"basic-auth": "^1.1.0",
"body-parser": "~1.17.2",
"cluster": "~0.7.7",
"cookie-parser": "~1.3.5",
"debug": "~2.2.0",
"express": "~4.13.1",
"cookie-parser": "~1.4.3",
"debug": "~2.6.8",
"express": "~4.15.3",
"fs.extra": "^1.3.2",
"jade": "~1.11.0",
"morgan": "~1.6.1",
"serve-favicon": "~2.3.0",
"sqlite3": "~3"
"morgan": "~1.8.2",
"nw": "0.20.1",
"serve-favicon": "~2.4.3",
"sqlite3": "~3.1.8"
}
}

BIN
public/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

106
views/custom-tray-menu.html Normal file
View File

@ -0,0 +1,106 @@
<html>
<script>
var gui = require('nw.gui');
var win = gui.Window.get();
function open_conf(){
var child_process = require('child_process');
// exec: spawns a shell.
child_process.exec('open config.js', function(error, stdout, stderr){
console.log(stdout);
});
}
function proper_quit(){
gui.App.closeAllWindows();
global.main_server.kill();
gui.App.quit();
}
</script>
<style>
body, html {
margin: 0;
font-size: 12px;
font-family: Helvetica Neue, Lucida Grande, Segoe UI, Tahoma, sans;
overflow: hidden !important;
color: #333;
}
section {
background: #fff;
margin: 10px 13px 13px 13px;
padding: 9px;
border-radius: 7px;
border: 1px solid #A9A9A9;
/*overflow: hidden;*/
box-shadow: 0px 3px 13px rgba(0, 0, 0, 0.25);
position: relative;
text-align: center;
}
section::after, section::before {
position: absolute;
content: '';
display: block;
width: 0;
height: 0;
}
section::before {
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-bottom: 10px solid #A9A9A9;
top: -10px;
left: calc(50% - 11px);
}
section::after {
border-left: 9px solid transparent;
border-right: 9px solid transparent;
border-bottom: 9px solid #fff;
top: -9px;
left: calc(50% - 10px);
}
h4 {
color: #555555;
height: 33px;
line-height: 33px;
margin: -9px -9px 10px -9px;
background: linear-gradient(180deg, #fff, #E9E9E9);
border-top-left-radius: 7px;
border-top-right-radius: 7px;
text-align: center;
font-size: 12px;
border-bottom: 1px solid #adadad;
}
/* FOR WINDOWS */
body.win32 section::before, body.win64 section::before {
border-bottom: none;
border-left: 10px solid transparent;
border-right: 10px solid transparent;
border-top: 10px solid #A9A9A9;
top: auto;
bottom: -10px;
left: calc(50% - 11px);
}
body.win32 section::after, body.win64 section::after {
border-bottom: none;
border-left: 9px solid transparent;
border-right: 9px solid transparent;
border-top: 9px solid #fff;
top: auto;
bottom: -9px;
left: calc(50% - 10px);
}
body.win32, body.win64 {{
section {
border-color: red;
}
}}
</style>
<body>
<section>
<h4>Plex Web Downloader</h4>
<p><button onclick="win.hide();">Minimiser le Menu</button></p>
<p><button onclick="open_conf();">Ouvrir la configuration</button></p>
<p><button onclick="proper_quit();">Arreter le Serveur</button></p>
</section>
</body>
</html>

2420
yarn.lock Normal file

File diff suppressed because it is too large Load Diff