Compare commits
No commits in common. "302c75c534e4c2d360cab64438f1d3edb80efe3f" and "70ccb8f4fd178881ffd68a4a0358fafd0abaa696" have entirely different histories.
302c75c534
...
70ccb8f4fd
10
README.md
10
README.md
@ -1,17 +1,9 @@
|
|||||||
# Transmission RSS Manager v2.0.9
|
# Transmission RSS Manager v2.0.8
|
||||||
|
|
||||||
A comprehensive web-based tool to automate and manage your Transmission torrent downloads with RSS feed integration, intelligent media organization, and enhanced security features. Now with automatic updates and easy installation!
|
A comprehensive web-based tool to automate and manage your Transmission torrent downloads with RSS feed integration, intelligent media organization, and enhanced security features. Now with automatic updates and easy installation!
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
### v2.0.9 (2025-03-07)
|
|
||||||
- **Fixed**: Update button now appears properly on dashboard
|
|
||||||
- **Fixed**: Remote Transmission connection issues resolved
|
|
||||||
- **Fixed**: Improved connection test with better error handling
|
|
||||||
- **Added**: System status and update endpoints for version checking
|
|
||||||
- **Improved**: Update detection and notification on dashboard
|
|
||||||
- **Improved**: Better error handling for git operations
|
|
||||||
|
|
||||||
### v2.0.8 (2025-03-07)
|
### v2.0.8 (2025-03-07)
|
||||||
- **Fixed**: Module import issues on fresh installations with proper file extension handling
|
- **Fixed**: Module import issues on fresh installations with proper file extension handling
|
||||||
- **Fixed**: Adding compatibility symlinks for different module naming styles
|
- **Fixed**: Adding compatibility symlinks for different module naming styles
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "transmission-rss-manager",
|
"name": "transmission-rss-manager",
|
||||||
"version": "2.0.9",
|
"version": "2.0.8",
|
||||||
"description": "A comprehensive web-based tool to automate and manage your Transmission torrent downloads with RSS feed integration and intelligent media organization",
|
"description": "A comprehensive web-based tool to automate and manage your Transmission torrent downloads with RSS feed integration and intelligent media organization",
|
||||||
"main": "server.js",
|
"main": "server.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
174
server.js
174
server.js
@ -13,10 +13,6 @@ const http = require('http');
|
|||||||
const https = require('https');
|
const https = require('https');
|
||||||
const jwt = require('jsonwebtoken');
|
const jwt = require('jsonwebtoken');
|
||||||
const bcrypt = require('bcrypt');
|
const bcrypt = require('bcrypt');
|
||||||
const { exec } = require('child_process');
|
|
||||||
const util = require('util');
|
|
||||||
const execAsync = util.promisify(exec);
|
|
||||||
const semver = require('semver'); // For semantic version comparison
|
|
||||||
|
|
||||||
// Import custom modules
|
// Import custom modules
|
||||||
// Try to import with .js extension first, then fallback to no extension for better compatibility
|
// Try to import with .js extension first, then fallback to no extension for better compatibility
|
||||||
@ -1200,176 +1196,6 @@ app.get('/api/auth/validate', authenticateJWT, (req, res) => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
// System status and update endpoints
|
|
||||||
app.get('/api/system/status', authenticateJWT, async (req, res) => {
|
|
||||||
try {
|
|
||||||
// Get system uptime
|
|
||||||
const uptimeSeconds = Math.floor(process.uptime());
|
|
||||||
const hours = Math.floor(uptimeSeconds / 3600);
|
|
||||||
const minutes = Math.floor((uptimeSeconds % 3600) / 60);
|
|
||||||
const seconds = uptimeSeconds % 60;
|
|
||||||
const uptime = `${hours}h ${minutes}m ${seconds}s`;
|
|
||||||
|
|
||||||
// Check transmission connection
|
|
||||||
let transmissionStatus = 'Connected';
|
|
||||||
try {
|
|
||||||
const status = await transmissionClient.getStatus();
|
|
||||||
if (!status.connected) {
|
|
||||||
transmissionStatus = 'Disconnected';
|
|
||||||
}
|
|
||||||
} catch (err) {
|
|
||||||
transmissionStatus = 'Disconnected';
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({
|
|
||||||
status: 'success',
|
|
||||||
data: {
|
|
||||||
version: APP_VERSION,
|
|
||||||
uptime,
|
|
||||||
transmissionStatus
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error getting system status:', error);
|
|
||||||
res.status(500).json({
|
|
||||||
status: 'error',
|
|
||||||
message: 'Failed to get system status'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Check for updates
|
|
||||||
app.get('/api/system/check-updates', authenticateJWT, async (req, res) => {
|
|
||||||
try {
|
|
||||||
// Check if git is available and if this is a git repository
|
|
||||||
const isGitRepo = fs.existsSync(path.join(__dirname, '.git'));
|
|
||||||
if (!isGitRepo) {
|
|
||||||
return res.json({
|
|
||||||
status: 'error',
|
|
||||||
message: 'This installation is not set up for updates. Please use the bootstrap installer.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get current version
|
|
||||||
const currentVersion = APP_VERSION;
|
|
||||||
|
|
||||||
// Check for test mode flag which forces update availability for testing
|
|
||||||
const testMode = req.query.test === 'true';
|
|
||||||
|
|
||||||
if (testMode) {
|
|
||||||
// In test mode, always return that an update is available
|
|
||||||
return res.json({
|
|
||||||
status: 'success',
|
|
||||||
data: {
|
|
||||||
updateAvailable: true,
|
|
||||||
currentVersion,
|
|
||||||
remoteVersion: '2.1.0-test',
|
|
||||||
commitsBehind: 1,
|
|
||||||
testMode: true
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
// Normal mode - fetch latest updates without applying them
|
|
||||||
await execAsync('git fetch');
|
|
||||||
|
|
||||||
// Check if we're behind the remote repository
|
|
||||||
const { stdout } = await execAsync('git rev-list HEAD..origin/main --count');
|
|
||||||
const behindCount = parseInt(stdout.trim());
|
|
||||||
|
|
||||||
if (behindCount > 0) {
|
|
||||||
// Get the new version from the remote package.json
|
|
||||||
const { stdout: remotePackageJson } = await execAsync('git show origin/main:package.json');
|
|
||||||
const remotePackage = JSON.parse(remotePackageJson);
|
|
||||||
const remoteVersion = remotePackage.version;
|
|
||||||
|
|
||||||
// Compare versions semantically - only consider it an update if remote version is higher
|
|
||||||
const isNewerVersion = semver.gt(remoteVersion, currentVersion);
|
|
||||||
|
|
||||||
return res.json({
|
|
||||||
status: 'success',
|
|
||||||
data: {
|
|
||||||
updateAvailable: isNewerVersion,
|
|
||||||
currentVersion,
|
|
||||||
remoteVersion,
|
|
||||||
commitsBehind: behindCount,
|
|
||||||
newerVersion: isNewerVersion
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
return res.json({
|
|
||||||
status: 'success',
|
|
||||||
data: {
|
|
||||||
updateAvailable: false,
|
|
||||||
currentVersion
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (gitError) {
|
|
||||||
console.error('Git error checking for updates:', gitError);
|
|
||||||
|
|
||||||
// Even if git commands fail, return a valid response with error information
|
|
||||||
return res.json({
|
|
||||||
status: 'error',
|
|
||||||
message: 'Error checking git repository: ' + gitError.message,
|
|
||||||
data: {
|
|
||||||
updateAvailable: false,
|
|
||||||
currentVersion,
|
|
||||||
error: true,
|
|
||||||
errorDetails: gitError.message
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error checking for updates:', error);
|
|
||||||
res.status(500).json({
|
|
||||||
status: 'error',
|
|
||||||
message: 'Failed to check for updates: ' + error.message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Apply updates
|
|
||||||
app.post('/api/system/update', authenticateJWT, async (req, res) => {
|
|
||||||
try {
|
|
||||||
// Check if git is available and if this is a git repository
|
|
||||||
const isGitRepo = fs.existsSync(path.join(__dirname, '.git'));
|
|
||||||
if (!isGitRepo) {
|
|
||||||
return res.status(400).json({
|
|
||||||
status: 'error',
|
|
||||||
message: 'This installation is not set up for updates. Please use the bootstrap installer.'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Run the update script
|
|
||||||
const updateScriptPath = path.join(__dirname, 'scripts', 'update.sh');
|
|
||||||
|
|
||||||
// Make sure the update script is executable
|
|
||||||
await execAsync(`chmod +x ${updateScriptPath}`);
|
|
||||||
|
|
||||||
// Execute the update script
|
|
||||||
const { stdout, stderr } = await execAsync(updateScriptPath);
|
|
||||||
|
|
||||||
// If we get here, the update was successful
|
|
||||||
// The service will be restarted by the update script
|
|
||||||
res.json({
|
|
||||||
status: 'success',
|
|
||||||
message: 'Update applied successfully. The service will restart.',
|
|
||||||
data: {
|
|
||||||
output: stdout,
|
|
||||||
errors: stderr
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error applying update:', error);
|
|
||||||
res.status(500).json({
|
|
||||||
status: 'error',
|
|
||||||
message: 'Failed to apply update: ' + error.message
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Catch-all route for SPA
|
// Catch-all route for SPA
|
||||||
app.get('*', (req, res) => {
|
app.get('*', (req, res) => {
|
||||||
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
res.sendFile(path.join(__dirname, 'public', 'index.html'));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user