Ajout d'une page web de suivi
This commit is contained in:
parent
7b238e218f
commit
f78c886c99
@ -3,7 +3,9 @@ source /home/$USER/autopost/conf.sh
|
||||
|
||||
#CONFIG GLOBAL
|
||||
SCREEN_NAME="autopost"
|
||||
WEB_NAME="web"
|
||||
SCRIPT_PATH="/home/$USER/autopost/posteur.sh"
|
||||
WEB_PATH="/home/$USER/autopost/server.js"
|
||||
ANALYZER="/home/$USER/autopost/analyzer.sh"
|
||||
|
||||
# Couleurs de texte
|
||||
|
||||
20
autopost/config.js
Normal file
20
autopost/config.js
Normal file
@ -0,0 +1,20 @@
|
||||
const path = require('path');
|
||||
|
||||
module.exports = {
|
||||
// Port sur lequel le serveur écoute
|
||||
// Attention si vous êtes sur une seedbox de bien choisir un port laisser libre par votre hébergeur
|
||||
// chez ultracc par exemple la commande est app-ports free
|
||||
port: Voir indications ci dessus,
|
||||
|
||||
// Chemin vers le fichier de base de données SQLite
|
||||
dbFile: path.join(__dirname, 'base_autopost.db'),
|
||||
|
||||
// Secret pour la configuration des sessions "curl -L pw.vdx.sh/w/32"
|
||||
sessionSecret: 'Voir commande ci dessus',
|
||||
|
||||
// Informations d'authentification
|
||||
auth: {
|
||||
username: 'user',
|
||||
password: 'pass'
|
||||
}
|
||||
};
|
||||
658
autopost/server.js
Normal file
658
autopost/server.js
Normal file
@ -0,0 +1,658 @@
|
||||
const express = require('express');
|
||||
const session = require('express-session');
|
||||
const sqlite3 = require('sqlite3').verbose();
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const AnsiToHtml = require('ansi-to-html');
|
||||
const convert = new AnsiToHtml();
|
||||
const { exec } = require('child_process');
|
||||
const os = require('os');
|
||||
|
||||
// Import de la configuration depuis config.js
|
||||
const config = require('./config');
|
||||
|
||||
const app = express();
|
||||
const port = config.port;
|
||||
|
||||
// Middleware pour parser les formulaires POST
|
||||
app.use(express.urlencoded({ extended: true }));
|
||||
|
||||
// Configuration des sessions en utilisant le secret depuis la config
|
||||
app.use(session({
|
||||
secret: config.sessionSecret,
|
||||
resave: false,
|
||||
saveUninitialized: false
|
||||
}));
|
||||
|
||||
// Servir des fichiers statiques (CSS, images, etc.)
|
||||
app.use(express.static('public'));
|
||||
|
||||
// Chemin vers la base SQLite défini dans la config
|
||||
const DB_FILE = config.dbFile;
|
||||
|
||||
// Création du routeur pour /autopost
|
||||
const autopostRouter = express.Router();
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Routes non protégées (login, logout) sous /autopost
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
// Affichage du formulaire de login à l'URL /autopost/login
|
||||
autopostRouter.get('/login', (req, res) => {
|
||||
res.send(`
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Login</title>
|
||||
<!-- Inclusion de Tailwind CSS via le CDN -->
|
||||
<script src="https://unpkg.com/@tailwindcss/browser@4"></script>
|
||||
</head>
|
||||
<body class="bg-slate-900 flex items-center justify-center min-h-screen">
|
||||
<div class="bg-slate-700 p-8 rounded-lg shadow-md w-80">
|
||||
<h2 class="text-center text-2xl font-bold text-white mb-4">Authentification</h2>
|
||||
<form method="POST" action="/autopost/login">
|
||||
<input type="text" name="username" placeholder="Identifiant" required
|
||||
class="w-full p-2 mb-4 rounded border border-gray-300"/>
|
||||
<input type="password" name="password" placeholder="Mot de passe" required
|
||||
class="w-full p-2 mb-4 rounded border border-gray-300"/>
|
||||
<button type="submit"
|
||||
class="w-full p-2 bg-blue-600 text-white rounded hover:bg-blue-700">
|
||||
Se connecter
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
`);
|
||||
});
|
||||
|
||||
// Traitement du formulaire de login en utilisant la config pour vérifier les identifiants
|
||||
autopostRouter.post('/login', (req, res) => {
|
||||
const { username, password } = req.body;
|
||||
if (username === config.auth.username && password === config.auth.password) {
|
||||
req.session.authenticated = true;
|
||||
res.redirect('/autopost');
|
||||
} else {
|
||||
res.send('Identifiants invalides. <a href="/autopost/login">Réessayer</a>');
|
||||
}
|
||||
});
|
||||
|
||||
// Déconnexion
|
||||
autopostRouter.get('/logout', (req, res) => {
|
||||
req.session.destroy();
|
||||
res.redirect('/autopost/login');
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Middleware de protection pour les routes suivantes
|
||||
------------------------------------------------------------------------- */
|
||||
function checkAuth(req, res, next) {
|
||||
if (req.session && req.session.authenticated) {
|
||||
next();
|
||||
} else {
|
||||
res.redirect(req.baseUrl + '/login');
|
||||
}
|
||||
}
|
||||
autopostRouter.use(checkAuth);
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Route GET principale pour /autopost avec pagination
|
||||
------------------------------------------------------------------------- */
|
||||
autopostRouter.get('/', (req, res) => {
|
||||
const limit = 100; // enregistrements par page
|
||||
const page = parseInt(req.query.page) || 1;
|
||||
const offset = (page - 1) * limit;
|
||||
|
||||
let db = new sqlite3.Database(DB_FILE, sqlite3.OPEN_READONLY, (err) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return res.status(500).send("Erreur lors de l'ouverture de la base de données.");
|
||||
}
|
||||
});
|
||||
|
||||
// Récupérer le nombre total d'enregistrements
|
||||
const countQuery = "SELECT COUNT(*) as total FROM release";
|
||||
db.get(countQuery, [], (err, countResult) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send("Erreur lors du comptage des enregistrements.");
|
||||
return;
|
||||
}
|
||||
const totalRecords = countResult.total;
|
||||
const totalPages = Math.ceil(totalRecords / limit);
|
||||
|
||||
const query = `
|
||||
SELECT nom, status, id FROM release
|
||||
ORDER BY (status = 2) DESC, id DESC
|
||||
LIMIT ${limit} OFFSET ${offset};
|
||||
`;
|
||||
db.all(query, [], (err, rows) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send("Erreur lors de la requête.");
|
||||
return;
|
||||
}
|
||||
|
||||
let html = `
|
||||
<!DOCTYPE html>
|
||||
<html lang="fr">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Suivi Autopost</title>
|
||||
<!-- Inclusion de Tailwind CSS et jQuery -->
|
||||
<script src="https://unpkg.com/@tailwindcss/browser@4"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
||||
</head>
|
||||
<body class="bg-slate-900 text-white font-sans p-4">
|
||||
<!-- Conteneur "fluid" -->
|
||||
<div class="w-full px-4">
|
||||
<h1 class="text-3xl font-bold mb-4">Suivi Autopost</h1>
|
||||
<p class="mb-4">
|
||||
<a href="/autopost/logout" class="text-blue-400 hover:underline">Déconnexion</a>
|
||||
</p>
|
||||
|
||||
<input type="text" id="searchInput" placeholder="Rechercher..."
|
||||
class="p-2 mb-4 border border-gray-300 rounded w-full"/>
|
||||
<!-- Pagination avec Tailwind -->
|
||||
<nav aria-label="Page navigation" class="mb-4">
|
||||
<ul class="inline-flex items-center -space-x-px">
|
||||
<li>
|
||||
${ page > 1
|
||||
? `<a href="/autopost/?page=${page - 1}" class="px-3 py-2 ml-0 leading-tight text-gray-500 bg-white border border-gray-300 rounded-l-lg hover:bg-gray-100 hover:text-gray-700">Précédent</a>`
|
||||
: `<span class="px-3 py-2 ml-0 leading-tight text-gray-500 bg-gray-200 border border-gray-300 rounded-l-lg">Précédent</span>`
|
||||
}
|
||||
</li>
|
||||
<li>
|
||||
<span class="px-4 py-2 leading-tight text-gray-700 bg-white border border-gray-300">Page ${page} sur ${totalPages}</span>
|
||||
</li>
|
||||
<li>
|
||||
${ page < totalPages
|
||||
? `<a href="/autopost/?page=${page + 1}" class="px-3 py-2 leading-tight text-gray-500 bg-white border border-gray-300 rounded-r-lg hover:bg-gray-100 hover:text-gray-700">Suivant</a>`
|
||||
: `<span class="px-3 py-2 leading-tight text-gray-500 bg-gray-200 border border-gray-300 rounded-r-lg">Suivant</span>`
|
||||
}
|
||||
</li>
|
||||
</ul>
|
||||
</nav>
|
||||
<div class="overflow-x-auto">
|
||||
<table class="min-w-full bg-gray-800">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="px-4 py-2 border border-gray-700 whitespace-nowrap">Name</th>
|
||||
<th class="px-4 py-2 border border-gray-700 whitespace-nowrap">Status</th>
|
||||
<th class="px-4 py-2 border border-gray-700">ID</th>
|
||||
<th class="px-4 py-2 border border-gray-700 whitespace-nowrap">Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
`;
|
||||
|
||||
rows.forEach(row => {
|
||||
let statusText = '';
|
||||
let statusClass = '';
|
||||
switch (row.status) {
|
||||
case 0:
|
||||
statusText = 'EN ATTENTE';
|
||||
statusClass = 'bg-cyan-500 text-black font-bold';
|
||||
break;
|
||||
case 1:
|
||||
statusText = 'ENVOI TERMINÉ';
|
||||
statusClass = 'bg-green-300 text-black font-bold';
|
||||
break;
|
||||
case 2:
|
||||
statusText = 'ERREUR';
|
||||
statusClass = 'bg-red-300 text-black font-bold';
|
||||
break;
|
||||
case 3:
|
||||
statusText = 'DEJA DISPONIBLE';
|
||||
statusClass = 'bg-pink-300 text-black font-bold';
|
||||
break;
|
||||
default:
|
||||
statusText = 'INCONNU';
|
||||
}
|
||||
let logLink = row.status !== 0
|
||||
? ` | <a href="#" class="log-link text-blue-400 hover:underline" data-filename="${row.nom}">Log</a>`
|
||||
: '';
|
||||
let mediainfoLink = ` | <a href="#" class="mediainfo-link text-blue-400 hover:underline" data-filename="${row.nom}">Mediainfo</a>`;
|
||||
let dlLink = row.status === 1
|
||||
? ` | <a href="/autopost/dl?name=${encodeURIComponent(row.nom)}" class="dl-link text-blue-400 hover:underline">DL</a>`
|
||||
: '';
|
||||
|
||||
html += `
|
||||
<tr id="row-${row.id}" class="odd:bg-gray-800 even:bg-gray-700">
|
||||
<td class="px-4 py-2 border border-gray-700">${row.nom}</td>
|
||||
<td class="px-4 py-2 border border-gray-700 status-text whitespace-nowrap ${statusClass}">${statusText}</td>
|
||||
<td class="px-4 py-2 border border-gray-700">${row.id}</td>
|
||||
<td class="px-4 py-2 border border-gray-700 whitespace-nowrap">
|
||||
<a href="#" class="edit-link text-blue-400 hover:underline" data-id="${row.id}" data-status="${row.status}">Editer</a> |
|
||||
<a href="#" class="delete-link text-blue-400 hover:underline" data-id="${row.id}">Supprimer</a>
|
||||
${logLink}
|
||||
${mediainfoLink}
|
||||
${dlLink}
|
||||
</td>
|
||||
</tr>
|
||||
`;
|
||||
});
|
||||
|
||||
html += `
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modale d'édition -->
|
||||
<div id="editModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
|
||||
<div class="bg-gray-800 p-6 rounded relative w-1/2">
|
||||
<span class="absolute top-2 right-2 text-white cursor-pointer close">×</span>
|
||||
<h2 class="text-xl font-semibold mb-4">Editer Release <span id="modalReleaseId"></span></h2>
|
||||
<form id="editForm">
|
||||
<label for="statusSelect" class="block mb-2">Status :</label>
|
||||
<select id="statusSelect" name="status" class="w-full p-2 mb-4 rounded border border-gray-300">
|
||||
<option value="0">EN ATTENTE</option>
|
||||
<option value="1">ENVOI TERMINÉ</option>
|
||||
<option value="2">ERREUR</option>
|
||||
<option value="3">DEJA DISPONIBLE</option>
|
||||
</select>
|
||||
<input type="hidden" id="releaseId" name="id" value=""/>
|
||||
<button type="submit" class="w-full p-2 bg-blue-600 text-white rounded hover:bg-blue-700">
|
||||
Mettre à jour
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modale pour afficher le log -->
|
||||
<div id="logModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
|
||||
<div class="bg-gray-800 p-6 rounded relative w-2/3">
|
||||
<span class="absolute top-2 right-2 text-white cursor-pointer close log-close">×</span>
|
||||
<h2 class="text-xl font-semibold mb-4">Contenu du log</h2>
|
||||
<pre id="logContent" class="max-h-[80vh] overflow-y-auto"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Modale pour afficher le mediainfo -->
|
||||
<div id="mediainfoModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center">
|
||||
<div class="bg-gray-800 p-6 rounded relative w-2/3">
|
||||
<span class="absolute top-2 right-2 text-white cursor-pointer close mediainfo-close">×</span>
|
||||
<h2 class="text-xl font-semibold mb-4">Contenu du mediainfo</h2>
|
||||
<pre id="mediainfoContent" class="max-h-[80vh] overflow-y-auto"></pre>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function updateTable(rows) {
|
||||
let tbody = $("table tbody");
|
||||
tbody.empty();
|
||||
rows.forEach(function(row) {
|
||||
let statusText = '';
|
||||
let statusClass = '';
|
||||
switch (parseInt(row.status)) {
|
||||
case 0:
|
||||
statusText = 'EN ATTENTE';
|
||||
statusClass = 'bg-cyan-500 text-black font-bold';
|
||||
break;
|
||||
case 1:
|
||||
statusText = 'ENVOI TERMINÉ';
|
||||
statusClass = 'bg-green-300 text-black font-bold';
|
||||
break;
|
||||
case 2:
|
||||
statusText = 'ERREUR';
|
||||
statusClass = 'bg-red-300 text-black font-bold';
|
||||
break;
|
||||
case 3:
|
||||
statusText = 'DEJA DISPONIBLE';
|
||||
statusClass = 'bg-pink-300 text-black font-bold';
|
||||
break;
|
||||
default:
|
||||
statusText = 'INCONNU';
|
||||
}
|
||||
let logLink = parseInt(row.status) !== 0
|
||||
? ' | <a href="#" class="log-link text-blue-400 hover:underline" data-filename="'+row.nom+'">Log</a>'
|
||||
: '';
|
||||
let mediainfoLink = ' | <a href="#" class="mediainfo-link text-blue-400 hover:underline" data-filename="'+row.nom+'">Mediainfo</a>';
|
||||
let dlLink = parseInt(row.status) === 1
|
||||
? ' | <a href="/autopost/dl?name='+encodeURIComponent(row.nom)+'" class="dl-link text-blue-400 hover:underline">DL</a>'
|
||||
: '';
|
||||
let tr = \`
|
||||
<tr id="row-\${row.id}" class="odd:bg-gray-800 even:bg-gray-700">
|
||||
<td class="px-4 py-2 border border-gray-700 whitespace-nowrap">\${row.nom}</td>
|
||||
<td class="px-4 py-2 border border-gray-700 status-text whitespace-nowrap \${statusClass}">\${statusText}</td>
|
||||
<td class="px-4 py-2 border border-gray-700">\${row.id}</td>
|
||||
<td class="px-4 py-2 border border-gray-700">
|
||||
<a href="#" class="edit-link text-blue-400 hover:underline" data-id="\${row.id}" data-status="\${row.status}">Editer</a> |
|
||||
<a href="#" class="delete-link text-blue-400 hover:underline" data-id="\${row.id}">Supprimer</a>\${logLink}\${mediainfoLink}\${dlLink}
|
||||
</td>
|
||||
</tr>\`;
|
||||
tbody.append(tr);
|
||||
});
|
||||
}
|
||||
|
||||
$(document).ready(function(){
|
||||
$("#searchInput").on("keyup", function() {
|
||||
let q = $(this).val();
|
||||
$.ajax({
|
||||
url: '/autopost/search',
|
||||
type: 'GET',
|
||||
data: { q: q },
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
updateTable(data);
|
||||
},
|
||||
error: function() {
|
||||
alert("Erreur lors de la recherche.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on("click", ".edit-link", function(e) {
|
||||
e.preventDefault();
|
||||
let releaseId = $(this).data('id');
|
||||
let currentStatus = $(this).data('status');
|
||||
$('#releaseId').val(releaseId);
|
||||
$('#modalReleaseId').text(releaseId);
|
||||
$('#statusSelect').val(currentStatus);
|
||||
$('#editModal').removeClass('hidden').fadeIn();
|
||||
});
|
||||
|
||||
$(document).on("click", ".delete-link", function(e) {
|
||||
e.preventDefault();
|
||||
if (confirm("Êtes-vous sûr de vouloir supprimer cet enregistrement ?")) {
|
||||
let releaseId = $(this).data('id');
|
||||
$.ajax({
|
||||
url: '/autopost/delete/' + releaseId,
|
||||
type: 'POST',
|
||||
success: function(data) {
|
||||
$('#row-' + releaseId).fadeOut('slow', function(){
|
||||
$(this).remove();
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
alert("Erreur lors de la suppression.");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$(document).on("click", ".log-link", function(e) {
|
||||
e.preventDefault();
|
||||
let filename = $(this).data("filename");
|
||||
$.ajax({
|
||||
url: '/autopost/log',
|
||||
type: 'GET',
|
||||
data: { name: filename },
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$("#logContent").html(data.content);
|
||||
$("#logModal").removeClass('hidden').fadeIn();
|
||||
},
|
||||
error: function() {
|
||||
alert("Erreur lors du chargement du fichier log.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$(document).on("click", ".mediainfo-link", function(e) {
|
||||
e.preventDefault();
|
||||
let filename = $(this).data("filename");
|
||||
$.ajax({
|
||||
url: '/autopost/mediainfo',
|
||||
type: 'GET',
|
||||
data: { name: filename },
|
||||
dataType: 'json',
|
||||
success: function(data) {
|
||||
$("#mediainfoContent").text(data.content);
|
||||
$("#mediainfoModal").removeClass('hidden').fadeIn();
|
||||
},
|
||||
error: function() {
|
||||
alert("Erreur lors du chargement du fichier mediainfo.");
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$('.close').click(function(){
|
||||
$(this).closest('.fixed').fadeOut(function(){
|
||||
$(this).addClass('hidden');
|
||||
});
|
||||
});
|
||||
|
||||
$('.fixed').click(function(e) {
|
||||
if (e.target === this) {
|
||||
$(this).fadeOut(function(){
|
||||
$(this).addClass('hidden');
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
$('#editForm').submit(function(e){
|
||||
e.preventDefault();
|
||||
let releaseId = $('#releaseId').val();
|
||||
let newStatus = $('#statusSelect').val();
|
||||
$.ajax({
|
||||
url: '/autopost/edit/' + releaseId,
|
||||
type: 'POST',
|
||||
data: { status: newStatus },
|
||||
success: function(data) {
|
||||
let statusText = '';
|
||||
let statusClass = '';
|
||||
switch(parseInt(newStatus)) {
|
||||
case 0:
|
||||
statusText = 'EN ATTENTE';
|
||||
statusClass = 'bg-cyan-500 text-black font-bold';
|
||||
break;
|
||||
case 1:
|
||||
statusText = 'ENVOI TERMINÉ';
|
||||
statusClass = 'bg-green-300 text-black font-bold';
|
||||
break;
|
||||
case 2:
|
||||
statusText = 'ERREUR';
|
||||
statusClass = 'bg-red-300 text-black font-bold';
|
||||
break;
|
||||
case 3:
|
||||
statusText = 'DEJA DISPONIBLE';
|
||||
statusClass = 'bg-pink-300 text-black font-bold';
|
||||
break;
|
||||
default:
|
||||
statusText = 'INCONNU';
|
||||
}
|
||||
let row = $('#row-' + releaseId);
|
||||
// Mise à jour uniquement de la cellule status
|
||||
row.find('.status-text')
|
||||
.removeClass('bg-cyan-500 bg-green-300 bg-red-300 bg-pink-300')
|
||||
.addClass(statusClass)
|
||||
.text(statusText);
|
||||
$('#editModal').fadeOut(function(){
|
||||
$(this).addClass('hidden');
|
||||
});
|
||||
},
|
||||
error: function() {
|
||||
alert("Erreur lors de la mise à jour.");
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`;
|
||||
res.send(html);
|
||||
db.close();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Route GET pour la recherche côté serveur
|
||||
------------------------------------------------------------------------- */
|
||||
autopostRouter.get('/search', (req, res) => {
|
||||
const q = req.query.q || "";
|
||||
const searchQuery = "%" + q + "%";
|
||||
let db = new sqlite3.Database(DB_FILE, sqlite3.OPEN_READONLY, (err) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return res.status(500).json({ error: "Erreur lors de l'ouverture de la base de données." });
|
||||
}
|
||||
});
|
||||
db.all("SELECT nom, status, id FROM release WHERE nom LIKE ? ORDER BY id DESC LIMIT 500", [searchQuery], (err, rows) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).json({ error: "Erreur lors de la requête." });
|
||||
return;
|
||||
}
|
||||
res.json(rows);
|
||||
db.close();
|
||||
});
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Route GET pour récupérer le contenu d'un fichier log
|
||||
------------------------------------------------------------------------- */
|
||||
autopostRouter.get('/log', (req, res) => {
|
||||
const filename = req.query.name;
|
||||
if (!filename) {
|
||||
return res.status(400).json({ error: "Nom du fichier non spécifié." });
|
||||
}
|
||||
let base = filename.includes('.') ? filename.split('.').slice(0, -1).join('.') : filename;
|
||||
const logFilePath = path.join(__dirname, 'logs', base + '.log');
|
||||
fs.readFile(logFilePath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return res.status(500).json({ error: "Erreur lors du chargement du fichier log." });
|
||||
}
|
||||
const htmlContent = convert.toHtml(data);
|
||||
res.json({ content: htmlContent });
|
||||
});
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Route GET pour récupérer le contenu d'un fichier mediainfo
|
||||
------------------------------------------------------------------------- */
|
||||
autopostRouter.get('/mediainfo', (req, res) => {
|
||||
const filename = req.query.name;
|
||||
if (!filename) {
|
||||
return res.status(400).json({ error: "Nom du fichier non spécifié." });
|
||||
}
|
||||
let base = filename.includes('.') ? filename.split('.').slice(0, -1).join('.') : filename;
|
||||
const mediainfoFilePath = path.join(__dirname, 'mediainfo', base + '.json');
|
||||
fs.readFile(mediainfoFilePath, 'utf8', (err, data) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return res.status(500).json({ error: "Erreur lors du chargement du fichier mediainfo." });
|
||||
}
|
||||
try {
|
||||
const obj = JSON.parse(data);
|
||||
const pretty = JSON.stringify(obj, null, 2);
|
||||
res.json({ content: pretty });
|
||||
} catch(e) {
|
||||
res.json({ content: data });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Route GET pour télécharger le fichier NZB
|
||||
------------------------------------------------------------------------- */
|
||||
autopostRouter.get('/dl', (req, res) => {
|
||||
const filename = req.query.name;
|
||||
if (!filename) {
|
||||
return res.status(400).send("Nom du fichier non spécifié.");
|
||||
}
|
||||
// Extraire le nom de base sans extension
|
||||
let base = filename.includes('.') ? filename.split('.').slice(0, -1).join('.') : filename;
|
||||
const subfolder = base.charAt(0).toUpperCase();
|
||||
// L'archive est en .7z maintenant
|
||||
const archiveFilePath = path.join(__dirname, 'FINIS', subfolder, base + '.7z');
|
||||
console.log("Tentative de téléchargement (archive 7z) :", archiveFilePath);
|
||||
|
||||
// Utilisation du répertoire temporaire
|
||||
const tmpDir = os.tmpdir();
|
||||
// Le fichier extrait attendu (sans dossier interne grâce à "7z e")
|
||||
const extractedFilePath = path.join(tmpDir, base + '.nzb');
|
||||
|
||||
// Utiliser "7z e" pour extraire sans recréer la structure de dossiers
|
||||
const command = `7z e "${archiveFilePath}" -o"${tmpDir}" -y`;
|
||||
|
||||
exec(command, (error, stdout, stderr) => {
|
||||
if (error) {
|
||||
console.error(`Erreur lors de la décompression: ${error.message}`);
|
||||
return res.status(500).send("Erreur lors de la décompression.");
|
||||
}
|
||||
// On vérifie que le fichier extrait existe
|
||||
res.download(extractedFilePath, base + '.nzb', (err) => {
|
||||
if (err) {
|
||||
console.error("Erreur lors du téléchargement :", err);
|
||||
res.status(500).send("Erreur lors du téléchargement.");
|
||||
}
|
||||
// Suppression du fichier temporaire après téléchargement (optionnel)
|
||||
fs.unlink(extractedFilePath, (err) => {
|
||||
if (err) {
|
||||
console.error("Erreur lors de la suppression du fichier temporaire :", err);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Route POST pour mettre à jour le statut (édition)
|
||||
------------------------------------------------------------------------- */
|
||||
autopostRouter.post('/edit/:id', (req, res) => {
|
||||
const id = req.params.id;
|
||||
const newStatus = req.body.status;
|
||||
let db = new sqlite3.Database(DB_FILE, sqlite3.OPEN_READWRITE, (err) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return res.status(500).send("Erreur lors de l'ouverture de la base de données.");
|
||||
}
|
||||
});
|
||||
db.run("UPDATE release SET status = ? WHERE id = ?", [newStatus, id], function(err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send("Erreur lors de la mise à jour.");
|
||||
return;
|
||||
}
|
||||
if (req.xhr || req.headers.accept.indexOf('json') > -1) {
|
||||
res.json({ success: true });
|
||||
} else {
|
||||
res.redirect("/autopost/");
|
||||
}
|
||||
db.close();
|
||||
});
|
||||
});
|
||||
|
||||
/* -------------------------------------------------------------------------
|
||||
Route POST pour supprimer un enregistrement
|
||||
------------------------------------------------------------------------- */
|
||||
autopostRouter.post('/delete/:id', (req, res) => {
|
||||
const id = req.params.id;
|
||||
let db = new sqlite3.Database(DB_FILE, sqlite3.OPEN_READWRITE, (err) => {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return res.status(500).send("Erreur lors de l'ouverture de la base de données.");
|
||||
}
|
||||
});
|
||||
db.run("DELETE FROM release WHERE id = ?", [id], function(err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
res.status(500).send("Erreur lors de la suppression.");
|
||||
return;
|
||||
}
|
||||
if (req.xhr || req.headers.accept.indexOf('json') > -1) {
|
||||
res.json({ success: true });
|
||||
} else {
|
||||
res.redirect("/autopost/");
|
||||
}
|
||||
db.close();
|
||||
});
|
||||
});
|
||||
|
||||
// Redirection de la route GET d'édition si accès direct
|
||||
autopostRouter.get('/edit/:id', (req, res) => {
|
||||
res.redirect("/autopost/");
|
||||
});
|
||||
|
||||
// Monter le routeur sur le chemin /autopost
|
||||
app.use('/autopost', autopostRouter);
|
||||
|
||||
app.listen(port, () => {
|
||||
console.log(`Serveur démarré sur http://localhost:${port}/autopost`);
|
||||
});
|
||||
15
bin/postauto
15
bin/postauto
@ -18,6 +18,13 @@ do_start() {
|
||||
screen -dmS "$SCREEN_NAME" bash -c "$SCRIPT_PATH"
|
||||
echo "Screen '$SCREEN_NAME' démarré avec '$SCRIPT_PATH'."
|
||||
fi
|
||||
|
||||
if screen -list | grep -q "$WEB_NAME"; then
|
||||
echo "Le screen '$WEB_NAME' est déjà en cours d'exécution."
|
||||
else
|
||||
screen -dmS "$WEB_NAME" node "$WEB_PATH"
|
||||
echo "Screen '$WEB_NAME' démarré avec '$WEB_PATH'."
|
||||
fi
|
||||
}
|
||||
|
||||
do_stop() {
|
||||
@ -27,6 +34,14 @@ do_stop() {
|
||||
else
|
||||
echo "Aucun screen '$SCREEN_NAME' en cours d'exécution."
|
||||
fi
|
||||
|
||||
if screen -list | grep -q "$WEB_NAME"; then
|
||||
screen -S "$WEB_NAME" -X quit
|
||||
echo "Screen '$WEB_NAME' arrêté."
|
||||
else
|
||||
echo "Aucun screen '$WEB_NAME' en cours d'exécution."
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
do_restart() {
|
||||
|
||||
80
install.sh
80
install.sh
@ -213,5 +213,85 @@ else
|
||||
echo "Mise à jour effectuée."
|
||||
fi
|
||||
|
||||
|
||||
echo "Vérification de l'environnement pour la page de suivi..."
|
||||
|
||||
# Fonction pour afficher les messages en vert
|
||||
log() {
|
||||
echo -e "\033[1;32m$1\033[0m"
|
||||
}
|
||||
|
||||
# Définition du répertoire AUTOPOST_DIR (ajuster si nécessaire)
|
||||
AUTOPOST_DIR="$HOME/autopost"
|
||||
|
||||
# Création du dossier si inexistant
|
||||
mkdir -p "$AUTOPOST_DIR"
|
||||
|
||||
# Vérification et installation de NVM
|
||||
if ! command -v nvm &> /dev/null; then
|
||||
log "nvm non trouvé, installation de nvm..."
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
log "NVM installé."
|
||||
else
|
||||
log "nvm est déjà installé."
|
||||
fi
|
||||
|
||||
# Vérification de Node.js
|
||||
if command -v node &> /dev/null; then
|
||||
current_version=$(node -v | sed 's/^v//')
|
||||
major_version=$(echo "$current_version" | cut -d. -f1)
|
||||
if [ "$major_version" -lt 22 ]; then
|
||||
log "Node.js version $current_version détectée (inférieure à 22). Mise à jour en cours..."
|
||||
nvm install 22
|
||||
nvm use 22
|
||||
else
|
||||
log "Node.js version $current_version détectée, compatible."
|
||||
fi
|
||||
else
|
||||
log "Node.js non trouvé, installation de Node.js 22..."
|
||||
nvm install 22
|
||||
nvm use 22
|
||||
fi
|
||||
|
||||
# Charger nvm après installation
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
|
||||
# Vérification des modules npm nécessaires
|
||||
log "Vérification des modules npm requis..."
|
||||
|
||||
modules=("express" "express-session" "sqlite3" "ansi-to-html")
|
||||
missing_modules=()
|
||||
|
||||
for module in "${modules[@]}"; do
|
||||
if ! npm list -g "$module" &> /dev/null; then
|
||||
missing_modules+=("$module")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing_modules[@]} -gt 0 ]; then
|
||||
log "Modules manquants détectés : ${missing_modules[*]}"
|
||||
npm install "${missing_modules[@]}"
|
||||
else
|
||||
log "Tous les modules requis sont déjà installés."
|
||||
fi
|
||||
|
||||
# Vérification et téléchargement des fichiers de configuration
|
||||
log "Vérification des fichiers de configuration..."
|
||||
|
||||
if [ ! -f "$AUTOPOST_DIR/config.js" ]; then
|
||||
log "Téléchargement de config.js..."
|
||||
wget -q -O "$AUTOPOST_DIR/config.js" "https://tig.unfr.pw/UNFR/postauto/raw/branch/main/autopost/config.js"
|
||||
fi
|
||||
|
||||
if [ ! -f "$AUTOPOST_DIR/server.js" ]; then
|
||||
log "Téléchargement de server.js..."
|
||||
wget -q -O "$AUTOPOST_DIR/server.js" "https://tig.unfr.pw/UNFR/postauto/raw/branch/main/autopost/server.js"
|
||||
fi
|
||||
|
||||
log "Installation terminée. Vous pouvez maintenant configurer $AUTOPOST_DIR/config.js."
|
||||
|
||||
echo "Suppression du script après exécution..."
|
||||
rm -- "$0"
|
||||
|
||||
91
update.sh
91
update.sh
@ -26,6 +26,8 @@ CLIGNOTANT='\e[5m'
|
||||
INVERSE='\e[7m'
|
||||
NORMAL='\e[0m'
|
||||
|
||||
updated="0"
|
||||
|
||||
#Vérification des prérequis
|
||||
echo -e "$BLEU""Vérification si les prérequis sont disponibles""$NORMAL"
|
||||
LISTE_APPLIS="curl basename php"
|
||||
@ -50,6 +52,7 @@ FILES["$HOME/autopost/analyzer.sh"]="https://tig.unfr.pw/UNFR/postauto/raw/branc
|
||||
FILES["$HOME/autopost/posteur.sh"]="https://tig.unfr.pw/UNFR/postauto/raw/branch/main/autopost/posteur.sh"
|
||||
FILES["$HOME/autopost/common.sh"]="https://tig.unfr.pw/UNFR/postauto/raw/branch/main/autopost/common.sh"
|
||||
FILES["$HOME/bin/postauto"]="https://tig.unfr.pw/UNFR/postauto/raw/branch/main/bin/postauto"
|
||||
FILES["$HOME/autopost/server.js"]="https://tig.unfr.pw/UNFR/postauto/raw/branch/main/autopost/server.js"
|
||||
|
||||
# Vérification et mise à jour des fichiers
|
||||
for LOCAL_FILE in "${!FILES[@]}"; do
|
||||
@ -65,6 +68,7 @@ for LOCAL_FILE in "${!FILES[@]}"; do
|
||||
echo "Mise à jour de $LOCAL_FILE..."
|
||||
mv "$TMP_FILE" "$LOCAL_FILE"
|
||||
chmod +x "$LOCAL_FILE"
|
||||
updated="1"
|
||||
else
|
||||
echo "Aucune mise à jour nécessaire pour $LOCAL_FILE."
|
||||
rm "$TMP_FILE"
|
||||
@ -132,6 +136,7 @@ if grep -q "$DEBUT_MARKER" "$BASHRC_FILE"; then
|
||||
# Ajouter le nouveau code de complétion
|
||||
echo "$COMPLETION_CODE" >> "$BASHRC_FILE"
|
||||
echo "Mise à jour effectuée."
|
||||
updated="1"
|
||||
else
|
||||
echo "Aucune modification nécessaire, le bloc est déjà à jour."
|
||||
fi
|
||||
@ -141,8 +146,89 @@ else
|
||||
echo "" >> "$BASHRC_FILE"
|
||||
echo "$COMPLETION_CODE" >> "$BASHRC_FILE"
|
||||
echo "Ajout terminé."
|
||||
updated="1"
|
||||
fi
|
||||
|
||||
echo "Vérification de l'environnement pour la page de suivi..."
|
||||
|
||||
# Fonction pour afficher les messages en vert
|
||||
log() {
|
||||
echo -e "\033[1;32m$1\033[0m"
|
||||
}
|
||||
|
||||
# Définition du répertoire AUTOPOST_DIR (ajuster si nécessaire)
|
||||
AUTOPOST_DIR="$HOME/autopost"
|
||||
|
||||
# Création du dossier si inexistant
|
||||
mkdir -p "$AUTOPOST_DIR"
|
||||
|
||||
# Vérification et installation de NVM
|
||||
if ! command -v nvm &> /dev/null; then
|
||||
log "nvm non trouvé, installation de nvm..."
|
||||
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.3/install.sh | bash
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
log "NVM installé."
|
||||
else
|
||||
log "nvm est déjà installé."
|
||||
fi
|
||||
|
||||
# Vérification de Node.js
|
||||
if command -v node &> /dev/null; then
|
||||
current_version=$(node -v | sed 's/^v//')
|
||||
major_version=$(echo "$current_version" | cut -d. -f1)
|
||||
if [ "$major_version" -lt 22 ]; then
|
||||
log "Node.js version $current_version détectée (inférieure à 22). Mise à jour en cours..."
|
||||
nvm install 22
|
||||
nvm use 22
|
||||
else
|
||||
log "Node.js version $current_version détectée, compatible."
|
||||
fi
|
||||
else
|
||||
log "Node.js non trouvé, installation de Node.js 22..."
|
||||
nvm install 22
|
||||
nvm use 22
|
||||
fi
|
||||
|
||||
# Charger nvm après installation
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
|
||||
# Vérification des modules npm nécessaires
|
||||
log "Vérification des modules npm requis..."
|
||||
|
||||
modules=("express" "express-session" "sqlite3" "ansi-to-html")
|
||||
missing_modules=()
|
||||
|
||||
for module in "${modules[@]}"; do
|
||||
if ! npm list -g "$module" &> /dev/null; then
|
||||
missing_modules+=("$module")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing_modules[@]} -gt 0 ]; then
|
||||
log "Modules manquants détectés : ${missing_modules[*]}"
|
||||
npm install "${missing_modules[@]}"
|
||||
else
|
||||
log "Tous les modules requis sont déjà installés."
|
||||
fi
|
||||
|
||||
# Vérification et téléchargement des fichiers de configuration
|
||||
log "Vérification des fichiers de configuration..."
|
||||
|
||||
if [ ! -f "$AUTOPOST_DIR/config.js" ]; then
|
||||
log "Téléchargement de config.js..."
|
||||
wget -q -O "$AUTOPOST_DIR/config.js" "https://tig.unfr.pw/UNFR/postauto/raw/branch/main/autopost/config.js"
|
||||
fi
|
||||
|
||||
if [ ! -f "$AUTOPOST_DIR/server.js" ]; then
|
||||
log "Téléchargement de server.js..."
|
||||
wget -q -O "$AUTOPOST_DIR/server.js" "https://tig.unfr.pw/UNFR/postauto/raw/branch/main/autopost/server.js"
|
||||
fi
|
||||
|
||||
log "Installation terminée. Vous pouvez maintenant configurer $AUTOPOST_DIR/config.js."
|
||||
|
||||
|
||||
# Vérifier et installer 7z si manquant
|
||||
if command -v 7z > /dev/null 2>&1; then
|
||||
LISTE_APPLIS+=("7z")
|
||||
@ -160,6 +246,11 @@ else
|
||||
LISTE_APPLIS+=("$BIN_DIR/7z")
|
||||
fi
|
||||
|
||||
echo "Merci d'aller lire le readme pour compresser vos anciens NZB"
|
||||
|
||||
if [$updated == "1"]; then
|
||||
echo -e "${ROUGE}Mise à jour effectué merci de relancer la commande 'postauto restart'${NORMAL}"
|
||||
fi
|
||||
|
||||
echo "Suppression du script après exécution..."
|
||||
rm -- "$0"
|
||||
Loading…
x
Reference in New Issue
Block a user