MovieMapper/utils/renderer/FileManager.js
Jarian Cottingham be887c3855 Refactor renderer.js into modular class-based structure
- Split large renderer.js file into 8 separate class files:
  - AppState.js: Manages application state
  - FileListManager.js: Handles file list display and manipulation
  - TagManager.js: Manages file tagging functionality
  - EpisodeManager.js: Handles episode number editing and highlighting
  - SearchManager.js: Manages TVDB search and show selection
  - FileManager.js: Handles file operations
  - ModalManager.js: Manages video preview modal
  - ProgressManager.js: Manages progress display
  - UIManager.js: Main coordinator for UI functionality
- Follows SOLID principles and single responsibility
- Improves code maintainability and testability
- All syntax verified with node --check
2026-02-25 02:32:08 -06:00

195 lines
5.2 KiB
JavaScript

const path = require('path');
const { ipcRenderer } = require('electron');
/**
* FileManager - Handles file operations
*/
class FileManager {
constructor() {
}
/**
* Select directory
* @returns {Promise<Object>} Selection result
*/
async selectDirectory() {
try {
// Use IPC to handle directory selection
const result = await ipcRenderer.invoke('select-directory');
if (result.success) {
return result;
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('Error selecting directory:', error);
return { success: false, error: error.message };
}
}
/**
* Scan directory for media files
* @param {string} directoryPath - Directory path
* @returns {Promise<Object>} Scan result
*/
async scanDirectory(directoryPath) {
try {
const result = await ipcRenderer.invoke('scan-directory', directoryPath);
if (result.success) {
return result;
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('Error scanning directory:', error);
return { success: false, error: error.message };
}
}
/**
* Rename a file
* @param {string} oldPath - Old file path
* @param {string} newName - New file name
* @returns {Promise<Object>} Rename result
*/
async renameFile(oldPath, newName) {
try {
const result = await ipcRenderer.invoke('rename-file', {
oldPath: oldPath,
newName: newName
});
if (result.success) {
return result;
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('Error renaming file:', error);
return { success: false, error: error.message };
}
}
/**
* Begin mapping files to Jellyfin naming convention
* @param {string} directory - Directory path
* @param {Array} files - Files to map
* @param {string|null} tvdbId - TVDB ID
* @returns {Promise<Object>} Mapping result
*/
async beginMapping(directory, files, tvdbId) {
try {
const result = await ipcRenderer.invoke('begin-mapping', {
directory: directory,
files: files,
tvdbId: tvdbId
});
if (result.success) {
return result;
} else {
throw new Error(result.error);
}
} catch (error) {
console.error('Mapping error:', error);
return { success: false, error: error.message };
}
}
/**
* Log audit event
* @param {string} directoryPath - Directory path
* @param {string} action - Action type
* @param {Object} details - Event details
* @returns {Promise<Object>} Audit result
*/
async logAuditEvent(directoryPath, action, details) {
try {
const result = await ipcRenderer.invoke('log-audit-event', {
directoryPath: directoryPath,
action: action,
details: details
});
return result;
} catch (error) {
console.error('Failed to log audit event:', error);
return { success: false, error: error.message };
}
}
/**
* Move file to folder
* @param {string} filePath - File path
* @param {string} folderName - Folder name
* @returns {Promise<Object>} Move result
*/
async moveFileToFolder(filePath, folderName) {
try {
const result = await ipcRenderer.invoke('move-file-to-folder', {
filePath: filePath,
folderName: folderName
});
return result;
} catch (error) {
console.error('Error moving file:', error);
return { success: false, error: error.message };
}
}
/**
* Log file info for debugging
* @param {string} filePath - File path
* @returns {Promise<Object>} File info result
*/
async logFileInfo(filePath) {
try {
const result = await ipcRenderer.invoke('log-file-info', filePath);
return result;
} catch (error) {
console.error('Error logging file info:', error);
return { success: false, error: error.message };
}
}
/**
* Open file in player
* @param {string} filePath - File path
*/
openFileInPlayer(filePath) {
ipcRenderer.invoke('open-file-in-player', filePath);
}
/**
* Collect file data with episode ranges from UI order
* @param {HTMLElement} fileListEl - File list element
* @returns {Array} Array of file data objects
*/
collectFileData(fileListEl) {
const fileItems = fileListEl.querySelectorAll('.file-item:not(.folder-item)');
const filesToMap = [];
fileItems.forEach((item, index) => {
const fileNameEl = item.querySelector('.file-name');
const qualityEl = item.querySelector('.file-quality');
const episodeNumEl = item.querySelector('.episode-number');
if (fileNameEl && fileNameEl.dataset.filePath) {
const episodeStart = episodeNumEl ? parseInt(episodeNumEl.dataset.episodeStart || (index + 1)) : (index + 1);
const episodeEnd = episodeNumEl ? parseInt(episodeNumEl.dataset.episodeEnd || episodeStart) : episodeStart;
filesToMap.push({
filePath: fileNameEl.dataset.filePath,
quality: qualityEl ? qualityEl.textContent : '',
episodeStart: episodeStart,
episodeEnd: episodeEnd
});
}
});
return filesToMap;
}
}
module.exports = FileManager;