Compare commits
No commits in common. "70ccb8f4fd178881ffd68a4a0358fafd0abaa696" and "54871518fcaeea54d03de9b1dfea61f0b7af479c" have entirely different histories.
70ccb8f4fd
...
54871518fc
@ -1,15 +1,9 @@
|
|||||||
# Transmission RSS Manager v2.0.8
|
# Transmission RSS Manager v2.0.7
|
||||||
|
|
||||||
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.8 (2025-03-07)
|
|
||||||
- **Fixed**: Module import issues on fresh installations with proper file extension handling
|
|
||||||
- **Fixed**: Adding compatibility symlinks for different module naming styles
|
|
||||||
- **Improved**: Server.js now uses consistent module import paths with .js extensions
|
|
||||||
- **Improved**: More robust module file handling in the installer
|
|
||||||
|
|
||||||
### v2.0.7 (2025-03-07)
|
### v2.0.7 (2025-03-07)
|
||||||
- **Fixed**: Installation directory handling with prompt for choosing install path
|
- **Fixed**: Installation directory handling with prompt for choosing install path
|
||||||
- **Fixed**: Bootstrap-installer now defaults to /opt/trans-install with user configuration option
|
- **Fixed**: Bootstrap-installer now defaults to /opt/trans-install with user configuration option
|
||||||
|
@ -136,9 +136,8 @@ const cors = require('cors');
|
|||||||
const Transmission = require('transmission');
|
const Transmission = require('transmission');
|
||||||
|
|
||||||
// Import custom modules
|
// Import custom modules
|
||||||
const PostProcessor = require('./modules/post-processor.js');
|
const PostProcessor = require('./modules/postProcessor');
|
||||||
const RssFeedManager = require('./modules/rss-feed-manager.js');
|
const RssFeedManager = require('./modules/rssFeedManager');
|
||||||
const TransmissionClient = require('./modules/transmission-client.js');
|
|
||||||
|
|
||||||
// Initialize Express app
|
// Initialize Express app
|
||||||
const app = express();
|
const app = express();
|
||||||
@ -1824,20 +1823,6 @@ function copy_module_files() {
|
|||||||
echo "Copying module: $module_name"
|
echo "Copying module: $module_name"
|
||||||
cp "$js_file" "$INSTALL_DIR/modules/$module_name"
|
cp "$js_file" "$INSTALL_DIR/modules/$module_name"
|
||||||
|
|
||||||
# Create symlinks for alternative module names that might be referenced
|
|
||||||
base_name=$(basename "$module_name" .js)
|
|
||||||
case "$base_name" in
|
|
||||||
"rss-feed-manager")
|
|
||||||
ln -sf "$INSTALL_DIR/modules/$module_name" "$INSTALL_DIR/modules/rssFeedManager.js"
|
|
||||||
;;
|
|
||||||
"post-processor")
|
|
||||||
ln -sf "$INSTALL_DIR/modules/$module_name" "$INSTALL_DIR/modules/postProcessor.js"
|
|
||||||
;;
|
|
||||||
"transmission-client")
|
|
||||||
ln -sf "$INSTALL_DIR/modules/$module_name" "$INSTALL_DIR/modules/transmissionClient.js"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# Set permissions
|
# Set permissions
|
||||||
chown "$USER:$USER" "$INSTALL_DIR/modules/$module_name"
|
chown "$USER:$USER" "$INSTALL_DIR/modules/$module_name"
|
||||||
chmod 644 "$INSTALL_DIR/modules/$module_name"
|
chmod 644 "$INSTALL_DIR/modules/$module_name"
|
||||||
|
@ -28,14 +28,8 @@ class TransmissionClient {
|
|||||||
this.dirMappings = config.remoteConfig.directoryMapping;
|
this.dirMappings = config.remoteConfig.directoryMapping;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the connection - but don't throw if it fails initially
|
// Initialize the connection
|
||||||
// This allows the object to be created even if the connection fails
|
this.initializeConnection();
|
||||||
try {
|
|
||||||
this.initializeConnection();
|
|
||||||
} catch (error) {
|
|
||||||
console.error("Failed to initialize Transmission connection:", error.message);
|
|
||||||
// Don't throw - allow methods to handle connection retry logic
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -45,11 +39,8 @@ class TransmissionClient {
|
|||||||
const { host, port, username, password, path: rpcPath } = this.config.transmissionConfig;
|
const { host, port, username, password, path: rpcPath } = this.config.transmissionConfig;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Only default to localhost if host is empty/null/undefined
|
|
||||||
const connectionHost = (host === undefined || host === null || host === '') ? 'localhost' : host;
|
|
||||||
|
|
||||||
this.client = new Transmission({
|
this.client = new Transmission({
|
||||||
host: connectionHost,
|
host: host || 'localhost',
|
||||||
port: port || 9091,
|
port: port || 9091,
|
||||||
username: username || '',
|
username: username || '',
|
||||||
password: password || '',
|
password: password || '',
|
||||||
@ -57,7 +48,7 @@ class TransmissionClient {
|
|||||||
timeout: 30000 // 30 seconds
|
timeout: 30000 // 30 seconds
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log(`Initialized Transmission client connection to ${connectionHost}:${port}${rpcPath}`);
|
console.log(`Initialized Transmission client connection to ${host}:${port}${rpcPath}`);
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to initialize Transmission client:', error);
|
console.error('Failed to initialize Transmission client:', error);
|
||||||
throw error;
|
throw error;
|
||||||
@ -70,17 +61,13 @@ class TransmissionClient {
|
|||||||
*/
|
*/
|
||||||
async getStatus() {
|
async getStatus() {
|
||||||
try {
|
try {
|
||||||
// Use the session-stats method for basic connectivity check
|
|
||||||
const sessionInfo = await this.client.sessionStats();
|
const sessionInfo = await this.client.sessionStats();
|
||||||
|
const version = await this.client.sessionGet();
|
||||||
// Use the session-get method to get version info
|
|
||||||
// Note: In transmission-promise, this is 'session' not 'sessionGet'
|
|
||||||
const session = await this.client.session();
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
connected: true,
|
connected: true,
|
||||||
version: session.version || "Unknown",
|
version: version.version,
|
||||||
rpcVersion: session['rpc-version'] || "Unknown",
|
rpcVersion: version['rpc-version'],
|
||||||
downloadSpeed: sessionInfo.downloadSpeed,
|
downloadSpeed: sessionInfo.downloadSpeed,
|
||||||
uploadSpeed: sessionInfo.uploadSpeed,
|
uploadSpeed: sessionInfo.uploadSpeed,
|
||||||
torrentCount: sessionInfo.torrentCount,
|
torrentCount: sessionInfo.torrentCount,
|
||||||
@ -456,8 +443,7 @@ class TransmissionClient {
|
|||||||
*/
|
*/
|
||||||
async setSessionParams(params) {
|
async setSessionParams(params) {
|
||||||
try {
|
try {
|
||||||
// In transmission-promise, the method is sessionUpdate not sessionSet
|
await this.client.sessionSet(params);
|
||||||
await this.client.sessionUpdate(params);
|
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
message: 'Session parameters updated successfully'
|
message: 'Session parameters updated successfully'
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "transmission-rss-manager",
|
"name": "transmission-rss-manager",
|
||||||
"version": "2.0.8",
|
"version": "2.0.7",
|
||||||
"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": {
|
||||||
|
135
server.js
135
server.js
@ -18,26 +18,37 @@ const bcrypt = require('bcrypt');
|
|||||||
// 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
|
||||||
let RssFeedManager, TransmissionClient, PostProcessor;
|
let RssFeedManager, TransmissionClient, PostProcessor;
|
||||||
|
|
||||||
// Always use explicit .js extension when importing our own modules
|
|
||||||
try {
|
try {
|
||||||
RssFeedManager = require('./modules/rss-feed-manager.js');
|
RssFeedManager = require('./modules/rss-feed-manager.js');
|
||||||
} catch (err) {
|
} catch (e) {
|
||||||
console.error('Failed to load RssFeedManager module:', err);
|
try {
|
||||||
process.exit(1);
|
RssFeedManager = require('./modules/rss-feed-manager');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to load RssFeedManager module:', err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
TransmissionClient = require('./modules/transmission-client.js');
|
TransmissionClient = require('./modules/transmission-client.js');
|
||||||
} catch (err) {
|
} catch (e) {
|
||||||
console.error('Failed to load TransmissionClient module:', err);
|
try {
|
||||||
process.exit(1);
|
TransmissionClient = require('./modules/transmission-client');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to load TransmissionClient module:', err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PostProcessor = require('./modules/post-processor.js');
|
PostProcessor = require('./modules/post-processor.js');
|
||||||
} catch (err) {
|
} catch (e) {
|
||||||
console.error('Failed to load PostProcessor module:', err);
|
try {
|
||||||
process.exit(1);
|
PostProcessor = require('./modules/post-processor');
|
||||||
|
} catch (err) {
|
||||||
|
console.error('Failed to load PostProcessor module:', err);
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Constants and configuration
|
// Constants and configuration
|
||||||
@ -468,45 +479,9 @@ app.post('/api/config', authenticateJWT, async (req, res) => {
|
|||||||
// Merge the new config with the existing one
|
// Merge the new config with the existing one
|
||||||
const newConfig = { ...config, ...req.body };
|
const newConfig = { ...config, ...req.body };
|
||||||
|
|
||||||
// Preserve existing Transmission configuration values when not explicitly provided
|
// Keep passwords if they're not provided
|
||||||
if (newConfig.transmissionConfig && config.transmissionConfig) {
|
if (newConfig.transmissionConfig && !newConfig.transmissionConfig.password && config.transmissionConfig) {
|
||||||
// First create a copy of the existing configuration
|
newConfig.transmissionConfig.password = config.transmissionConfig.password;
|
||||||
const preservedTransConfig = { ...config.transmissionConfig };
|
|
||||||
|
|
||||||
// Only update values that are explicitly provided and not empty
|
|
||||||
if (!req.body.transmissionConfig?.host) {
|
|
||||||
newConfig.transmissionConfig.host = preservedTransConfig.host;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req.body.transmissionConfig?.port) {
|
|
||||||
newConfig.transmissionConfig.port = preservedTransConfig.port;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req.body.transmissionConfig?.path) {
|
|
||||||
newConfig.transmissionConfig.path = preservedTransConfig.path;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!req.body.transmissionConfig?.username) {
|
|
||||||
newConfig.transmissionConfig.username = preservedTransConfig.username;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Always preserve password if not provided
|
|
||||||
if (!newConfig.transmissionConfig.password) {
|
|
||||||
newConfig.transmissionConfig.password = preservedTransConfig.password;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preserve remote configuration settings if not explicitly provided
|
|
||||||
if (newConfig.remoteConfig && config.remoteConfig) {
|
|
||||||
// Make sure isRemote setting is preserved if not explicitly set
|
|
||||||
if (req.body.remoteConfig?.isRemote === undefined) {
|
|
||||||
newConfig.remoteConfig.isRemote = config.remoteConfig.isRemote;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Preserve directory mappings if not provided
|
|
||||||
if (!req.body.remoteConfig?.directoryMapping && config.remoteConfig.directoryMapping) {
|
|
||||||
newConfig.remoteConfig.directoryMapping = { ...config.remoteConfig.directoryMapping };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep user passwords
|
// Keep user passwords
|
||||||
@ -885,15 +860,7 @@ app.post('/api/transmission/remove', authenticateJWT, async (req, res) => {
|
|||||||
|
|
||||||
app.post('/api/transmission/test', authenticateJWT, async (req, res) => {
|
app.post('/api/transmission/test', authenticateJWT, async (req, res) => {
|
||||||
try {
|
try {
|
||||||
const { host, port, username, password, path: rpcPath } = req.body;
|
const { host, port, username, password } = req.body;
|
||||||
|
|
||||||
// Debug info
|
|
||||||
console.log('Testing Transmission connection with params:', {
|
|
||||||
host: host || 'from config',
|
|
||||||
port: port || 'from config',
|
|
||||||
username: username ? 'provided' : 'from config',
|
|
||||||
path: rpcPath || 'from config',
|
|
||||||
});
|
|
||||||
|
|
||||||
// Create a temporary client for testing
|
// Create a temporary client for testing
|
||||||
const testConfig = {
|
const testConfig = {
|
||||||
@ -902,48 +869,26 @@ app.post('/api/transmission/test', authenticateJWT, async (req, res) => {
|
|||||||
port: port || config.transmissionConfig.port,
|
port: port || config.transmissionConfig.port,
|
||||||
username: username || config.transmissionConfig.username,
|
username: username || config.transmissionConfig.username,
|
||||||
password: password || config.transmissionConfig.password,
|
password: password || config.transmissionConfig.password,
|
||||||
path: rpcPath || config.transmissionConfig.path
|
path: config.transmissionConfig.path
|
||||||
},
|
|
||||||
// Also include remoteConfig to ensure proper remote handling
|
|
||||||
remoteConfig: {
|
|
||||||
// If host is provided and different from localhost, set isRemote to true
|
|
||||||
isRemote: host && host !== 'localhost' ? true : config.remoteConfig?.isRemote || false,
|
|
||||||
directoryMapping: config.remoteConfig?.directoryMapping || {}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Log the actual test config (without password)
|
const testClient = new TransmissionClient(testConfig);
|
||||||
console.log('Test configuration:', {
|
const status = await testClient.getStatus();
|
||||||
host: testConfig.transmissionConfig.host,
|
|
||||||
port: testConfig.transmissionConfig.port,
|
|
||||||
path: testConfig.transmissionConfig.path,
|
|
||||||
isRemote: testConfig.remoteConfig.isRemote
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
if (status.connected) {
|
||||||
const testClient = new TransmissionClient(testConfig);
|
res.json({
|
||||||
const status = await testClient.getStatus();
|
success: true,
|
||||||
|
message: 'Successfully connected to Transmission server',
|
||||||
if (status.connected) {
|
data: {
|
||||||
res.json({
|
version: status.version,
|
||||||
success: true,
|
rpcVersion: status.rpcVersion
|
||||||
message: 'Successfully connected to Transmission server',
|
}
|
||||||
data: {
|
});
|
||||||
version: status.version,
|
} else {
|
||||||
rpcVersion: status.rpcVersion
|
res.status(400).json({
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
res.status(400).json({
|
|
||||||
success: false,
|
|
||||||
message: `Failed to connect: ${status.error}`
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error testing Transmission connection:', error);
|
|
||||||
res.status(500).json({
|
|
||||||
success: false,
|
success: false,
|
||||||
message: `Error testing connection: ${error.message}`
|
message: `Failed to connect: ${status.error}`
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user