leetcode2notion

Save LeetCode problems to Notion after clicking a button.

Per 08-09-2024. Zie de nieuwste versie.

// ==UserScript==
// @name         leetcode2notion
// @namespace    wuyifff
// @version      1.0
// @description  Save LeetCode problems to Notion after clicking a button.
// @author       wuyifff
// @match        https://leetcode.cn/problems/*
// @match        https://leetcode.com/problems/*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=leetcode.com
// @grant        GM_xmlhttpRequest
// @license      MIT
// @homepage     https://github.com/wuyifff/leetcode2notion
// ==/UserScript==

(function() {
    'use strict';
    // replace to your own token and ID
    const notionToken = '';
    const databaseId = '';

    // 1. add save button
    // select language button (optional)
    function addUIElements() {
        const button = document.createElement("button");
        button.innerHTML = "Save to Notion";
        button.style.position = "fixed";
        button.style.bottom = "10px";
        button.style.right = "10px";
        button.style.zIndex = 1000;
        button.style.padding = "10px 20px";
        button.style.backgroundColor = "#4CAF50";
        button.style.color = "white";
        button.style.border = "none";
        button.style.borderRadius = "5px";
        button.style.cursor = "pointer";
        button.onclick = saveProblemToNotion;

        const select = document.createElement("select");
        select.id = "languageSelect";
        select.style.position = "fixed";
        select.style.bottom = "50px";
        select.style.right = "10px";
        select.style.zIndex = 1000;
        select.style.padding = "10px";
        select.style.backgroundColor = "#4CAF50";
        select.style.color = "white";
        select.style.border = "none";
        select.style.borderRadius = "5px";
        select.style.cursor = "pointer";

        const optionPython = document.createElement("option");
        optionPython.value = "python";
        optionPython.innerText = "Python";

        const optionCpp = document.createElement("option");
        optionCpp.value = "cpp";
        optionCpp.innerText = "C++";

        select.appendChild(optionPython);
        select.appendChild(optionCpp);

        const container = document.createElement("div");
        container.style.display = "flex";
        container.style.flexDirection = "column";
        container.style.alignItems = "center";
        container.style.marginLeft = "10px";
        //container.appendChild(select);
        container.appendChild(button);

        container.style.position = "fixed";
        container.style.bottom = "10px";
        container.style.right = "10px";
        document.body.appendChild(container);
    }

    // 2. get leetcode problem info
    function getProblemData() {
        const title = document.querySelector('.text-title-large a')?.innerText || 'No title found';
        const difficultyElement = document.querySelector("div[class*='text-difficulty-']");
        const difficulty = difficultyElement ? difficultyElement.innerText : 'No difficulty found';
        const url = window.location.href;
        const tagElements = document.querySelectorAll("a[href*='/tag/']");
        const tagTexts = Array.from(tagElements).map(element => element.innerText);

        const codeDiv = document.querySelector('.view-lines.monaco-mouse-cursor-text[role="presentation"]');
        let codeText = '';
        if (codeDiv) {
            const codeLines = codeDiv.querySelectorAll('div');
            codeText = Array.from(codeLines).map(line => line.innerText).join('\n');
        } else {
            codeText = 'No code found';
        }
        //console.log(codeText);
        //const selectedLanguage = document.getElementById("languageSelect").value;
        const selectedLanguage = 'python';
        return {
            title: title,
            difficulty: difficulty,
            url: url,
            tag: tagTexts,
            code: codeText,
            language: selectedLanguage
        };
    }

    // 3. save to notion and check if duplicate
    async function saveProblemToNotion() {
        const problemData = getProblemData();
        console.log(problemData);

        const searchUrl = `https://api.notion.com/v1/search`;
        const searchBody = {
            "query": problemData.title,
            "filter": {
                "value": "page",
                "property": "object"
            },
            "sort": {
                "direction": "ascending",
                "timestamp": "last_edited_time"
            }
        };

        GM_xmlhttpRequest({
            method: 'POST',
            url: searchUrl,
            headers: {
                'Authorization': `Bearer ${notionToken}`,
                'Content-Type': 'application/json',
                'Notion-Version': '2022-06-28'
            },
            data: JSON.stringify(searchBody),
            onload: function(searchResponse) {
                if (searchResponse.status === 200) {
                    const searchResult = JSON.parse(searchResponse.responseText);
                    const existingPage = searchResult.results.find(result => result.properties?.Title?.title[0]?.text?.content === problemData.title);

                    if (existingPage) {
                        const existingPageUrl = existingPage.url;
                        alert('Problem already exists in Notion! Opening existing page...');
                        window.open(existingPageUrl, '_blank');
                    } else {
                        createNewNotionPage(problemData);
                    }
                } else {
                    console.error('Error searching Notion database', searchResponse.responseText);
                    alert('Failed to search Notion database. Check the console for details.');
                }
            },
            onerror: function(error) {
                console.error('Error in searching Notion database', error);
                alert('An error occurred while searching Notion database.');
            }
        });
    }

    // 4. create new page
    function createNewNotionPage(problemData) {
        const tags = problemData.tag.map(tag => ({
            name: tag
        }));

        const url = `https://api.notion.com/v1/pages`;
        const body = {
            parent: { database_id: databaseId },
            properties: {
                'Title': {
                    title: [
                        {
                            text: {
                                content: problemData.title
                            }
                        }
                    ]
                },
                'Difficulty': {
                    select: {
                        name: problemData.difficulty
                    }
                },
                'Link': {
                    url: problemData.url
                },
                'Date': {
                    date: {
                        start: new Date().toISOString().split('T')[0] // format YYYY-MM-DD
                    }
                },
                'Tags': {
                    multi_select: tags
                }
            },
            children: [
                {
                    object: 'block',
                    type: 'code',
                    code: {
                        rich_text: [
                            {
                                type: 'text',
                                text: {
                                    content: problemData.code
                                }
                            }
                        ],
                        language: problemData.language
                    }
                }
            ]
        };

        GM_xmlhttpRequest({
            method: 'POST',
            url: url,
            headers: {
                'Authorization': `Bearer ${notionToken}`,
                'Content-Type': 'application/json',
                'Notion-Version': '2022-06-28'
            },
            data: JSON.stringify(body),
            onload: function(response) {
                if (response.status === 200) {
                    const responseData = JSON.parse(response.responseText);
                    const notionPageUrl = responseData.url;
                    alert('Problem saved to Notion!');
                    window.open(notionPageUrl, '_blank');
                } else {
                    console.error('Failed to save to Notion', response.responseText);
                    alert('Failed to save to Notion. Check the console for more details.');
                }
            },
            onerror: function(error) {
                console.error('Error in saving to Notion', error);
                alert('An error occurred while saving to Notion.');
            }
        });
    }

    addUIElements();

})();