Save Leetcode Problem to Obsidian

Save the current leetcode problem as new obsidian note.

Vous devrez installer une extension telle que Tampermonkey, Greasemonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Violentmonkey pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey ou Userscripts pour installer ce script.

Vous devrez installer une extension telle que Tampermonkey pour installer ce script.

Vous devrez installer une extension de gestionnaire de script utilisateur pour installer ce script.

(J'ai déjà un gestionnaire de scripts utilisateur, laissez-moi l'installer !)

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension telle que Stylus pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

Vous devrez installer une extension du gestionnaire de style pour utilisateur pour installer ce style.

(J'ai déjà un gestionnaire de style utilisateur, laissez-moi l'installer!)

// ==UserScript==
// @name         Save Leetcode Problem to Obsidian
// @namespace    http://tampermonkey.net/
// @version      2024-07-26
// @description  Save the current leetcode problem as new obsidian note.
// @author       miscde
// @match        https://leetcode.com/problems/*
// @icon         data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==
// @grant        GM_getValue
// @grant        GM_setValue
// @grant        GM_registerMenuCommand
// @grant        GM_notification
// @grant        GM_openInTab
// @run-at       context-menu
// @license      MIT
// ==/UserScript==

(function() {
    'use strict';

    // Function to find and return the timer value
    let containerElement = document.querySelector('#ide-top-btns');

    function getTimerValue() {
        if (containerElement) {
            // Find the timer element within the container
            let timerElement = containerElement.querySelector('.select-none.pr-2.text-sm.text-text-secondary.dark\\:text-text-secondary');

            if (timerElement) {
                let timerValue = timerElement.textContent || timerElement.innerText;
                console.log('Current Timer Value:', timerValue);
                return timerValue;
            } else {
                console.log('Timer element not found within the container');
                return null;
            }
        } else {
            console.log('Container element not found');
            return null;
        }
    }

// Call the function to capture and log the timer value
    let timerValue = getTimerValue();
    let [hours, minutes, seconds] = timerValue.split(':').map(Number);
    let minutesSpent = hours * 60 + minutes + Math.round(seconds / 60);

    let currentUrl = window.location.href;

    let difficultyElement = document.querySelector('[class*="text-difficulty-"]');

    // Function to get the difficulty level
    function getDifficulty() {
        if (difficultyElement) {
            let difficultyText = difficultyElement.textContent || difficultyElement.innerText;
            difficultyText = difficultyText.toLowerCase();
            console.log('Problem Difficulty:', difficultyText);
            return difficultyText;
        } else {
            console.log('Difficulty element not found');
            return null;
        }
    }

    // Call the function to capture and log the difficulty
    let difficultyValue = getDifficulty();

    let fullPath = window.location.pathname;

    // Extract the relevant part (/problems/xxxx)
    let matchedPath = fullPath.match(/\/problems\/[^\/]+/)[0];

    // Find the <a> element with the matching href attribute
    let linkElement = document.querySelector(`a[href*="${matchedPath}"]`);

    // Function to get the text of the <a> element
    function getProblemName() {
        if (linkElement) {
            let linkText = linkElement.textContent || linkElement.innerText;
            linkText = linkText.replace(/\?/g, "");
            console.log('Link Text:', linkText);
            return linkText;
        } else {
            console.log('Link element not found for href:', matchedPath);
            return null;
        }
    }

    // Call the function to capture and log the link text
    let problemName = getProblemName();
    let today = new Date().toISOString().split('T')[0];

    let content = `---
lc-link: ${currentUrl}
minutes-spent: ${minutesSpent}
attempts:
difficulty: ${difficultyValue}
solved-on: ${today}
comment:
review-on:
---
# Algorithm


# Complexities

- Time:
- Space:

# Alternative Approach


# New Functions`;


    async function createObsidianDocument(obsidianUrl, documentPath, content, token) {
        // check if exists
        let fileExists = false;
        try {
            let response = await fetch(obsidianUrl + '/vault' + documentPath, {
                method: 'GET',
                headers: {
                    'Content-Type': 'text/markdown',
                    'Authorization': `Bearer ${token}`
                }
            });
            if (response.ok) {
                fileExists = true;
            }
        } catch (error) {
            console.error('Error:', error);
        }

        // not exist, create it
        if (!fileExists) {
            try {
                let response = await fetch(obsidianUrl + '/vault' + documentPath, {
                    method: 'PUT',
                    headers: {
                        'Content-Type': 'text/markdown',
                        'Authorization': `Bearer ${token}`
                    },
                    body: content
                });

                if (response.ok) {
                    console.log('Document created successfully:', response.statusText);
                } else {
                    console.error('Error creating document:', response.statusText);
                }
            } catch (error) {
                console.error('Error:', error);
            }
        }

        function openObsidianLink() {
            GM_openInTab('obsidian://', { active: true, insert: true });
        }

        // open the file in obsidian
        try {
            let response = await fetch(obsidianUrl + '/open' + documentPath, {
                method: 'POST',
                headers: {
                    'Authorization': `Bearer ${token}`
                }
            });
            if (!fileExists) {
                GM_notification({ title: 'Problem Imported Successfully', text: `Please open your Obsidian editor to see it.`, timeout: 5000, onclick: openObsidianLink });
            } else {
                GM_notification({ title: 'Problem Exists!', text: `Please open your Obsidian editor to see it.`, timeout: 5000, onclick: openObsidianLink });
            }
        } catch (error) {
            console.error('Error:', error);
            GM_notification({ title: 'Error Occurred', text: `${error} Do you have Obsidian opened?`, timeout: 5000 });
        }
    }

    // Function to get the bearer token
    function getOrPromptForKey(key, promptText) {
        let token = GM_getValue(key, null);
        if (!token) {
            token = prompt(promptText);
            if (token) {
                GM_setValue(key, token);
                GM_notification({ title: 'Input Saved', text: `Your input for ${key} has been saved.`, timeout: 5000 });
            }
        }
        return token;
    }

    function saveToObsidian() {
        let token = getOrPromptForKey('obsidian_web_api_key', 'Please enter your Obsidian API key:');
        let obsidianUrl = getOrPromptForKey('obsidian_api_url', 'Please enter the obsidian HTTPS API URL').replace(/\/$/, '');
        let documentPath = `/Algorithms/LeetCode/${problemName}.md`

        if (token) {
            // Call the function to create the Obsidian document
            createObsidianDocument(obsidianUrl, documentPath, content, token);
        } else {
            console.error('Bearer token is not available.');
        }
    }

    saveToObsidian();

})();