Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SUPPORT] Moving / renaming media files with QOwnNotes scripting #3205

Open
elreb opened this issue Jan 7, 2025 · 4 comments
Open

[SUPPORT] Moving / renaming media files with QOwnNotes scripting #3205

elreb opened this issue Jan 7, 2025 · 4 comments

Comments

@elreb
Copy link

elreb commented Jan 7, 2025

Question

How could I move / rename a media file with the scripting function in QOwnNotes.

I have a question regarding when pasting an image from the clipboard. Instead of the default action of pasting the image and it saving to the ./media folder with a file name similar to qownnotes-media-.*\.png$ I would like to name it using the file name it is being pasted into with a suffix of "whichever number of screenshot".

I think this helps organize the media folder a bit more.

Here is an attempt I made but it is reading the original file and writing the new file as text instead of a binary.

import QtQml 2.0

QtObject {
    function insertMediaHook(fileName, markdownText) {
        script.log("Starting insertMediaHook");

        const note = script.currentNote();
        if (!note) return markdownText;

        const noteName = note.fileName.replace(/\.[^/.]+$/, "");
        const noteText = note.noteText;

        let counter = 1;
        const regex = new RegExp(`!\\[.*?\\]\\(media\\/${noteName}(\\d+)\\.png\\)`, 'g');
        let match;
        while ((match = regex.exec(noteText)) !== null) {
            const num = parseInt(match[1]);
            if (num >= counter) counter = num + 1;
        }

        const newFileName = noteName + counter + ".png";
        const origFileName = fileName.split('/').pop();

        if (origFileName.match(/qownnotes-media-.*\.png$/)) {
            try {
                const mediaPath = script.currentNoteFolderPath() + "/media/";
                script.log("Media path: " + mediaPath);
                const oldPath = mediaPath + origFileName;
                script.log("Old path: " + oldPath);
                const newPath = mediaPath + newFileName;
                script.log("New path: " + newPath);

                if (script.fileExists(oldPath)) {
                    script.log("Source file exists");
                    const fileData = script.readFromFile(oldPath, true);
                    //script.log("Read result: " + fileData);
                    if (fileData !== null) {
                        const writeResult = script.writeToFile(newPath, fileData, true);
                        script.log("Wrote result: " + writeResult);
                        if (writeResult) {
                            // script.removeFile(oldPath);
                            if (script.fileExists(newPath)) {
                                script.log("New file exists at " + newPath);
                            } else {
                                script.log("New file does not exist at " + newPath);
                            }
                            return `![${noteName}_${counter}](media/${newFileName})`;
                        }
                    }
                }
            } catch (error) {
                script.log("Error: " + error);
                return markdownText;
            }
        }

        return markdownText;
    }

    function init() {
        script.registerCustomAction("renameScreenshots", "Rename Screenshots", "Rename screenshots to match note name", "");
    }

    function customActionInvoked(action) {
        if (action === "renameScreenshots") {
            script.log("Screenshot renaming script is active");
        }
    }
}

Relevant log output in the Log panel

[Jan 07 09:38:59] [scripting]: Starting insertMediaHook
[Jan 07 09:38:59] [scripting]: Media path: /Users/username/Documents/QOwnNotes/media/
[Jan 07 09:38:59] [scripting]: Old path: /Users/username/Documents/QOwnNotes/media/qownnotes-media-jjfIOs.png
[Jan 07 09:38:59] [scripting]: New path: /Users/username/Documents/QOwnNotes/media/2025-01-06_note1.png
[Jan 07 09:38:59] [scripting]: Source file exists
[Jan 07 09:38:59] [scripting]: Wrote result: true
[Jan 07 09:38:59] [scripting]: New file exists at /Users/username/Documents/QOwnNotes/media/2025-01-06_note1.png

When I printed the log of the file it is obviously non-sensical:

[Jan 07 09:22:00] [scripting]: Read result: �PNG

IHDR]�I	pHYs

8����"GcKN(/...

Any clues would help even.

Thank you in advanced!

@elreb elreb changed the title [SUPPORT] [SUPPORT] Moving / renaming media files with QOwnNotes scripting Jan 7, 2025
@pbek
Copy link
Owner

pbek commented Jan 7, 2025

@elreb
Copy link
Author

elreb commented Jan 7, 2025

Thanks for your reply @pbek

I tried accommodating the changes you suggested but for some reason the terminal command doesn't seem to be wanting to execute via the script (although does if I manually execute the command from the logs it does work as expected: cp -v /Users/username/Documents/QOwnNotes/media/qownnotes-media-BIfdzk.png /Users/username/Documents/QOwnNotes/media/2025-01-06_AH-note_1.png).

Logs:

[Jan 07 11:57:41] [scripting]: Starting insertMediaHook
[Jan 07 11:57:41] [scripting]: Media path: /Users/username/Documents/QOwnNotes/media/
[Jan 07 11:57:41] [scripting]: Old path: /Users/username/Documents/QOwnNotes/media/qownnotes-media-BIfdzk.png
[Jan 07 11:57:41] [scripting]: New path: /Users/username/Documents/QOwnNotes/media/2025-01-06_AH-note_1.png
[Jan 07 11:57:41] [scripting]: Source file exists /Users/username/Documents/QOwnNotes/media/qownnotes-media-BIfdzk.png
[Jan 07 11:57:41] [scripting]: Old path: /Users/username/Documents/QOwnNotes/media/qownnotes-media-BIfdzk.png
[Jan 07 11:57:41] [scripting]: New path: /Users/username/Documents/QOwnNotes/media/2025-01-06_AH-note_1.png
[Jan 07 11:57:41] [scripting]: Process environment:
[Jan 07 11:57:41] [scripting]:
[Jan 07 11:57:41] [scripting]: Executing command: cp -v /Users/username/Documents/QOwnNotes/media/qownnotes-media-BIfdzk.png /Users/username/Documents/QOwnNotes/media/2025-01-06_AH-note_1.png
[Jan 07 11:57:41] [scripting]: Process result details:
[Jan 07 11:57:41] [scripting]: - stdout: none
[Jan 07 11:57:41] [scripting]: - stderr: none
[Jan 07 11:57:41] [scripting]: - exitCode: undefined
[Jan 07 11:57:41] [scripting]: Process copy failed, attempting native file copy...
[Jan 07 11:57:41] [scripting]: Error during copy operation: Type error

Code

import QtQml 2.0

QtObject {
    function copyBinaryFile(oldPath, newPath) {
        if (!oldPath || !newPath) {
            script.log("Error: Invalid path parameters");
            return false;
        }
        let result;
        try {
            script.log("Old path: " + oldPath);
            script.log("New path: " + newPath);

            if (script.platformIsLinux() || script.platformIsOSX()) {
                // Use absolute path to cp and add -v for verbose output
                script.log("Process environment:");
                script.log(script.startSynchronousProcess("env", []));
                const command = "cp";
                const args = ["-v", oldPath, newPath];
                script.log("Executing command: " + command + " " + args.join(" "));
                result = script.startSynchronousProcess(command, args);
            } else if (script.platformIsWindows()) {
                const quotedOldPath = `"${oldPath}"`;
                const quotedNewPath = `"${newPath}"`;
                const command = "cmd";
                const args = ["/c", "copy", "/B", quotedOldPath, quotedNewPath];
                script.log("Executing command: " + command + " " + args.join(" "));
                result = script.startSynchronousProcess(command, args);
            } else {
                script.log("Error: Unsupported platform");
                return false;
            }

            script.log("Process result details:");
            script.log("- stdout: " + (result.stdout || "none"));
            script.log("- stderr: " + (result.stderr || "none"));
            script.log("- exitCode: " + (result.exitCode !== undefined ? result.exitCode : "undefined"));

            if (result && result.exitCode === 0) {
                script.log("Copy was successful");
                return true;
            } else {
                // Try to use native file API as fallback
                script.log("Process copy failed, attempting native file copy...");
                const success = script.writeFile(newPath, script.readFile(oldPath));
                if (success) {
                    script.log("Native file copy successful");
                    return true;
                }
                script.log("All copy attempts failed");
                return false;
            }
        } catch (error) {
            script.log("Error during copy operation: " + error.message);
            return false;
        }
    }

    function removeBinaryFile(filePath) {
        let result;

        if (script.platformIsLinux() || script.platformIsOSX()) {
            result = script.startSynchronousProcess("rm", [filePath]);
        } else if (script.platformIsWindows()) {
            result = script.startSynchronousProcess("del", [filePath]);
        }

        script.log("Attempted to remove file: " + filePath);
        script.log("Remove result: " + JSON.stringify(result));

        if (result && result.exitCode === 0) {
            script.log("File removed successfully");
            return true;
        } else {
            script.log("Failed to remove file with exit code: " + (result ? result.exitCode : "undefined"));
            return false;
        }
    }

    function insertMediaHook(fileName, markdownText) {
        script.log("Starting insertMediaHook");

        const note = script.currentNote();
        if (!note) return markdownText;

        const noteName = note.fileName.replace(/\.[^/.]+$/, "");
        const noteText = note.noteText;

        let counter = 1;
        const regex = new RegExp(`!\\[.*?\\]\\(media\\/${noteName}_(\\d+)\\.png\\)`, 'g');
        let match;
        while ((match = regex.exec(noteText)) !== null) {
            const num = parseInt(match[1]);
            if (num >= counter) counter = num + 1;
        }

        const newFileName = `${noteName}_${counter}.png`;
        const origFileName = fileName.split('/').pop();

        if (origFileName.match(/qownnotes-media-.*\.png$/)) {
            try {
                const mediaPath = script.currentNoteFolderPath() + "/media/";
                script.log("Media path: " + mediaPath);
                const oldPath = mediaPath + origFileName;
                script.log("Old path: " + oldPath);
                const newPath = mediaPath + newFileName;
                script.log("New path: " + newPath);

                if (script.fileExists(oldPath)) {
                    script.log("Source file exists " + oldPath);
                    // Use platform-specific binary copy instead of read/write
                    if (copyBinaryFile(oldPath, newPath)) {

                        // Only remove the old file if copy was successful
                        removeBinaryFile(oldPath);

                        if (script.fileExists(newPath)) {
                            script.log("New file exists at " + newPath);
                            return `![${noteName}_${counter}](media/${newFileName})`;
                        } else {
                            script.log("New file does not exist at " + newPath);
                        }
                    }
                }
            } catch (error) {
                script.log("Error: " + error);
                return markdownText;
            }
        }

        return markdownText;
    }

    function init() {
        script.registerCustomAction("renameScreenshots", "Rename Screenshots", "Rename screenshots to match note name", "");
    }

    function customActionInvoked(action) {
        if (action === "renameScreenshots") {
            script.log("Screenshot renaming script is active");
        }
    }
}

When I used the full path to cp /bin/cp it opened terminal with a partial command:

bin/cp ; exit;
usage: cp [-R [-H | -L | -P]] [-fi | -n] [-aclpSsvXx] source_file target_file
       cp [-R [-H | -L | -P]] [-fi | -n] [-aclpSsvXx] source_file ... target_directory

Saving session...completed.

[Process completed]

Are there additional environmental settings I should be making?

@pbek
Copy link
Owner

pbek commented Jan 8, 2025

Why don't you try mv?

Are there additional environmental settings I should be making?

As long as those commands are their own binary, no. If they are a feature of your shell, you need to run your shell with the commands.

@elreb
Copy link
Author

elreb commented Jan 8, 2025

I tried mv as well, for some reason in my case the arguments aren't being passed out of startSynchronousProcess correctly. I am just going to make a shell script to loop through and do it with a cron job.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants