Compare commits

..

No commits in common. "70ccb8f4fd178881ffd68a4a0358fafd0abaa696" and "54871518fcaeea54d03de9b1dfea61f0b7af479c" have entirely different histories.

5 changed files with 52 additions and 142 deletions

View File

@ -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

View File

@ -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"

View File

@ -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
try {
this.initializeConnection(); 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'

View File

@ -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": {

View File

@ -18,27 +18,38 @@ 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 (e) {
try {
RssFeedManager = require('./modules/rss-feed-manager');
} catch (err) { } catch (err) {
console.error('Failed to load RssFeedManager module:', err); console.error('Failed to load RssFeedManager module:', err);
process.exit(1); process.exit(1);
} }
}
try { try {
TransmissionClient = require('./modules/transmission-client.js'); TransmissionClient = require('./modules/transmission-client.js');
} catch (e) {
try {
TransmissionClient = require('./modules/transmission-client');
} catch (err) { } catch (err) {
console.error('Failed to load TransmissionClient module:', err); console.error('Failed to load TransmissionClient module:', err);
process.exit(1); process.exit(1);
} }
}
try { try {
PostProcessor = require('./modules/post-processor.js'); PostProcessor = require('./modules/post-processor.js');
} catch (e) {
try {
PostProcessor = require('./modules/post-processor');
} catch (err) { } catch (err) {
console.error('Failed to load PostProcessor module:', err); console.error('Failed to load PostProcessor module:', err);
process.exit(1); process.exit(1);
} }
}
// Constants and configuration // Constants and configuration
const DEFAULT_CONFIG_PATH = '/etc/transmission-rss-manager/config.json'; const DEFAULT_CONFIG_PATH = '/etc/transmission-rss-manager/config.json';
@ -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,25 +869,10 @@ 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)
console.log('Test configuration:', {
host: testConfig.transmissionConfig.host,
port: testConfig.transmissionConfig.port,
path: testConfig.transmissionConfig.path,
isRemote: testConfig.remoteConfig.isRemote
});
try {
const testClient = new TransmissionClient(testConfig); const testClient = new TransmissionClient(testConfig);
const status = await testClient.getStatus(); const status = await testClient.getStatus();
@ -939,13 +891,6 @@ app.post('/api/transmission/test', authenticateJWT, async (req, res) => {
message: `Failed to connect: ${status.error}` message: `Failed to connect: ${status.error}`
}); });
} }
} catch (error) {
console.error('Error testing Transmission connection:', error);
res.status(500).json({
success: false,
message: `Error testing connection: ${error.message}`
});
}
} catch (error) { } catch (error) {
res.status(500).json({ res.status(500).json({
success: false, success: false,