Save LeetCode problems to Notion after clicking a button.
当前为
// ==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();
})();