// ==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();
})();