diff --git a/plugins/RenameFile/renamefile.css b/plugins/RenameFile/renamefile.css index e50d7828..b1289d2a 100644 --- a/plugins/RenameFile/renamefile.css +++ b/plugins/RenameFile/renamefile.css @@ -1,7 +1,7 @@ .renamefile { - color: unset; + cursor: pointer; &:hover { - text-decoration: unset; + text-decoration: underline; } &:active { color: white; diff --git a/plugins/RenameFile/renamefile.js b/plugins/RenameFile/renamefile.js index cc485b2f..2a438ac8 100644 --- a/plugins/RenameFile/renamefile.js +++ b/plugins/RenameFile/renamefile.js @@ -72,30 +72,46 @@ } } - function wrapElement(element) { - var text = element.textContent.trim(); - var anchor = document.createElement('a'); - anchor.href = '#'; - anchor.textContent = text; - anchor.classList.add('renamefile'); - anchor.title = 'Click to append title to [Title] input field; OR ctrl-key & mouse click to copy title to clipboard; OR shift-key click to copy to [Title] input field; OR alt-key click to copy file URI to clipboard.'; - anchor.addEventListener('click', function(event) { - event.preventDefault(); - AppendTitleField(text, event); - }); - element.innerHTML = ''; - element.appendChild(anchor); + var TITLE_SELECTOR = '.scene-header div.TruncatedText'; + var TOOLTIP = 'Click to append title to [Title] input field; OR ctrl-key & mouse click to copy title to clipboard; OR shift-key click to copy to [Title] input field; OR alt-key click to copy file URI to clipboard.'; + + // Use event delegation instead of replacing the title element. The scene + // title is a React-controlled component; restructuring its DOM (e.g. + // wrapping it in an ) detaches the text node React updates, so the title + // freezes on the previous scene when navigating with Next. By listening on + // document and reading the title at click time, we never touch React's DOM. + document.addEventListener('click', function(event) { + var title = event.target.closest(TITLE_SELECTOR); + if (!title) return; + event.preventDefault(); + AppendTitleField(title.textContent.trim(), event); + }); + + // Non-destructive affordance: add the styling class and tooltip without + // touching the element's children, so React's text node stays intact. + function decorate(element) { + if (!element.classList.contains('renamefile')) { + element.classList.add('renamefile'); + } + if (element.getAttribute('title') !== TOOLTIP) { + element.setAttribute('title', TOOLTIP); + } } - function handleMutations(mutationsList, observer) { - for(const mutation of mutationsList) { - for(const addedNode of mutation.addedNodes) { - if (addedNode.nodeType === Node.ELEMENT_NODE && addedNode.querySelector('.scene-header div.TruncatedText')) { - wrapElement(addedNode.querySelector('.scene-header div.TruncatedText')); - } + function handleMutations(mutationsList) { + for (const mutation of mutationsList) { + for (const addedNode of mutation.addedNodes) { + if (addedNode.nodeType !== Node.ELEMENT_NODE) continue; + var title = addedNode.matches && addedNode.matches(TITLE_SELECTOR) + ? addedNode + : addedNode.querySelector && addedNode.querySelector(TITLE_SELECTOR); + if (title) decorate(title); } } } const observer = new MutationObserver(handleMutations); observer.observe(document.body, { childList: true, subtree: true }); + + var existing = document.querySelector(TITLE_SELECTOR); + if (existing) decorate(existing); })(); diff --git a/plugins/RenameFile/renamefile.py b/plugins/RenameFile/renamefile.py index 3dfd3571..139855f0 100644 --- a/plugins/RenameFile/renamefile.py +++ b/plugins/RenameFile/renamefile.py @@ -388,12 +388,12 @@ def rename_scene(scene_id): original_file_name = Path(original_file_path).name new_filename = form_filename(original_file_stem, scene_details) max_filename_length = int(config["max_filename_length"]) - if len(new_filename) > max_filename_length: - extension_length = len(Path(original_file_path).suffix) - max_base_filename_length = max_filename_length - extension_length - truncated_filename = new_filename[:max_base_filename_length] + extension_length = len(Path(original_file_path).suffix) + if len(new_filename) + extension_length > max_filename_length: hash_suffix = hashlib.md5(new_filename.encode()).hexdigest() - new_filename = truncated_filename + '_' + hash_suffix + Path(original_file_path).suffix + max_base_filename_length = max_filename_length - extension_length - len(hash_suffix) - 1 + truncated_filename = new_filename[:max_base_filename_length] + new_filename = truncated_filename + '_' + hash_suffix newFilenameWithExt = new_filename + Path(original_file_path).suffix new_file_path = f"{original_parent_directory}{os.sep}{new_filename}{Path(original_file_name).suffix}" org_file_root_stem = f"{original_parent_directory}{os.sep}{original_file_stem}" @@ -444,15 +444,15 @@ def rename_scene(scene_id): stash.Trace(f"Calling [metadata_scan] for path {original_parent_directory.resolve().as_posix()}") stash.metadata_scan(paths=[original_parent_directory.resolve().as_posix()]) if targetDidExist: - raise + return None if os.path.isfile(new_file_path): if os.path.isfile(original_file_path): os.remove(original_file_path) pass else: # ToDo: Add delay rename here - raise - + return None + if dry_run: stash.Log("Dry-Run, so skipping DB renaming") elif stash.renameFileNameInDB(scene_details['files'][0]['id'], original_file_name, newFilenameWithExt): diff --git a/plugins/RenameFile/renamefile.yml b/plugins/RenameFile/renamefile.yml index 70ec5e24..e9420ad5 100644 --- a/plugins/RenameFile/renamefile.yml +++ b/plugins/RenameFile/renamefile.yml @@ -1,6 +1,6 @@ name: RenameFile description: Renames video (scene) file names when the user edits the [Title] field located in the scene [Edit] tab. -version: 1.0.0 +version: 1.0.2 url: https://discourse.stashapp.cc/t/renamefile/1334 ui: css: diff --git a/plugins/RenameFile/version_history/README.md b/plugins/RenameFile/version_history/README.md index ab2bb205..c67189d2 100644 --- a/plugins/RenameFile/version_history/README.md +++ b/plugins/RenameFile/version_history/README.md @@ -16,3 +16,6 @@ - Fixed Dry-Run bug, which changed the file name in the database when Dry-Run was enabled. ### 1.0.1 - +### 1.0.2 +- Fixed OSError "File name too long" (macOS) caused by the long-filename truncation logic appending the file extension twice and not reserving space for the hash suffix. +- Rename/move failures now log a single clear error message instead of also dumping a raw Python traceback to the log.