From 74d682e0f06653d81e08880b5b708b8d87c6780a Mon Sep 17 00:00:00 2001 From: Sangeeth Sudheer Date: Wed, 4 Jan 2023 01:15:36 +0530 Subject: [PATCH] initial commit --- .gitignore | 382 ++++++++++++++++++++++++++++++++++++++++ leetray/LeetRay.user.js | 158 +++++++++++++++++ scripts/bump-version.sh | 7 + 3 files changed, 547 insertions(+) create mode 100644 .gitignore create mode 100644 leetray/LeetRay.user.js create mode 100755 scripts/bump-version.sh diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e7bda8b --- /dev/null +++ b/.gitignore @@ -0,0 +1,382 @@ +# Created by https://www.toptal.com/developers/gitignore/api/node,python,windows,linux,macos +# Edit at https://www.toptal.com/developers/gitignore?templates=node,python,windows,linux,macos + +### Linux ### +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +### macOS ### +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +### macOS Patch ### +# iCloud generated files +*.icloud + +### Node ### +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +lerna-debug.log* +.pnpm-debug.log* + +# Diagnostic reports (https://nodejs.org/api/report.html) +report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json + +# Runtime data +pids +*.pid +*.seed +*.pid.lock + +# Directory for instrumented libs generated by jscoverage/JSCover +lib-cov + +# Coverage directory used by tools like istanbul +coverage +*.lcov + +# nyc test coverage +.nyc_output + +# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) +.grunt + +# Bower dependency directory (https://bower.io/) +bower_components + +# node-waf configuration +.lock-wscript + +# Compiled binary addons (https://nodejs.org/api/addons.html) +build/Release + +# Dependency directories +node_modules/ +jspm_packages/ + +# Snowpack dependency directory (https://snowpack.dev/) +web_modules/ + +# TypeScript cache +*.tsbuildinfo + +# Optional npm cache directory +.npm + +# Optional eslint cache +.eslintcache + +# Optional stylelint cache +.stylelintcache + +# Microbundle cache +.rpt2_cache/ +.rts2_cache_cjs/ +.rts2_cache_es/ +.rts2_cache_umd/ + +# Optional REPL history +.node_repl_history + +# Output of 'npm pack' +*.tgz + +# Yarn Integrity file +.yarn-integrity + +# dotenv environment variable files +.env +.env.development.local +.env.test.local +.env.production.local +.env.local + +# parcel-bundler cache (https://parceljs.org/) +.cache +.parcel-cache + +# Next.js build output +.next +out + +# Nuxt.js build / generate output +.nuxt +dist + +# Gatsby files +.cache/ +# Comment in the public line in if your project uses Gatsby and not Next.js +# https://nextjs.org/blog/next-9-1#public-directory-support +# public + +# vuepress build output +.vuepress/dist + +# vuepress v2.x temp and cache directory +.temp + +# Docusaurus cache and generated files +.docusaurus + +# Serverless directories +.serverless/ + +# FuseBox cache +.fusebox/ + +# DynamoDB Local files +.dynamodb/ + +# TernJS port file +.tern-port + +# Stores VSCode versions used for testing VSCode extensions +.vscode-test + +# yarn v2 +.yarn/cache +.yarn/unplugged +.yarn/build-state.yml +.yarn/install-state.gz +.pnp.* + +### Node Patch ### +# Serverless Webpack directories +.webpack/ + +# Optional stylelint cache + +# SvelteKit build / generate output +.svelte-kit + +### Python ### +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.nox/ +.coverage +.coverage.* +nosetests.xml +coverage.xml +*.cover +*.py,cover +.hypothesis/ +.pytest_cache/ +cover/ + +# Translations +*.mo +*.pot + +# Django stuff: +local_settings.py +db.sqlite3 +db.sqlite3-journal + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +.pybuilder/ +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# IPython +profile_default/ +ipython_config.py + +# pyenv +# For a library or package, you might want to ignore these files since the code is +# intended to run in multiple environments; otherwise, check them in: +# .python-version + +# pipenv +# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control. +# However, in case of collaboration, if having platform-specific dependencies or dependencies +# having no cross-platform support, pipenv may install dependencies that don't work, or not +# install all needed dependencies. +#Pipfile.lock + +# poetry +# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control. +# This is especially recommended for binary packages to ensure reproducibility, and is more +# commonly ignored for libraries. +# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control +#poetry.lock + +# pdm +# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control. +#pdm.lock +# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it +# in version control. +# https://pdm.fming.dev/#use-with-ide +.pdm.toml + +# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm +__pypackages__/ + +# Celery stuff +celerybeat-schedule +celerybeat.pid + +# SageMath parsed files +*.sage.py + +# Environments +.venv +env/ +venv/ +ENV/ +env.bak/ +venv.bak/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ +.dmypy.json +dmypy.json + +# Pyre type checker +.pyre/ + +# pytype static type analyzer +.pytype/ + +# Cython debug symbols +cython_debug/ + +# PyCharm +# JetBrains specific template is maintained in a separate JetBrains.gitignore that can +# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore +# and can be added to the global gitignore or merged into this file. For a more nuclear +# option (not recommended) you can uncomment the following to ignore the entire idea folder. +#.idea/ + +### Python Patch ### +# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration +poetry.toml + + +### Windows ### +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# End of https://www.toptal.com/developers/gitignore/api/node,python,windows,linux,macos +n \ No newline at end of file diff --git a/leetray/LeetRay.user.js b/leetray/LeetRay.user.js new file mode 100644 index 0000000..f222000 --- /dev/null +++ b/leetray/LeetRay.user.js @@ -0,0 +1,158 @@ +// ==UserScript== +// @name LeetRay +// @namespace http://tampermonkey.net/ +// @version 0.1.1 +// @description Take beautiful screenshots of your code in Leetcode instantly with Ray.so +// @updateURL https://git.sangeeth.dev/x/userscripts/raw/branch/main/leetray/LeetRay.user.js +// @downloadURL https://git.sangeeth.dev/x/userscripts/raw/branch/main/leetray/LeetRay.user.js +// @author Sangeeth Sudheer +// @match https://leetcode.com/problems/* +// @match https://www.leetcode.com/problems/* +// @match https://www.ray.so/* +// @match https://ray.so/* +// @icon https://www.google.com/s2/favicons?sz=64&domain=leetcode.com +// @grant GM_registerMenuCommand +// @grant GM_openInTab +// @grant GM_log +// @grant GM_getTab +// @grant GM_setValue +// @grant GM_addValueChangeListener +// @grant GM_removeValueChangeListener +// @grant unsafeWindow +// @grant window.close +// @grant window.focus +// ==/UserScript== + +(function () { + "use strict"; + let uwindow = unsafeWindow; + + function isLeetcode() { + return location.hostname === "leetcode.com"; + } + + function isRayso() { + return location.hostname === "www.ray.so"; + } + + function waitForRaysoLoad() { + return new Promise((resolve) => { + let id = GM_addValueChangeListener("leetray.rayso.loaded", () => { + resolve(); + GM_removeValueChangeListener(id); + }); + }); + } + + function waitForRaysoExit() { + return new Promise((resolve) => { + let id = GM_addValueChangeListener("leetray.rayso.exit", () => { + resolve(); + GM_removeValueChangeListener(id); + }); + }); + } + + function debug(stuff) { + GM_log(`LeetRay DEBUG ${stuff}`); + } + + function error(stuff) { + GM_log(`LeetRay ERROR ${stuff}`); + } + + function leetcodeMain() { + const menu_command_id = GM_registerMenuCommand( + "Copy screenshot", + async function (event) { + if (!uwindow.monaco?.editor) { + error("monaco.editor not found"); + return; + } + + const monacoEditorEl = document.querySelector( + ".monaco-editor[data-uri]" + ); + const editorKey = monacoEditorEl.dataset.uri; + + const monacoModel = uwindow.monaco.editor.getModel(editorKey); + + const colors = { + rust: "sunset", + python: "raindrop", + python3: "raindrop", + cpp: "midnight", + scala: "sunset", + javascript: "sunset", + typescript: "raindrop", + }; + const sourceCode = monacoModel.getValue(); + debug("Source code value from editor:"); + debug(sourceCode); + + const language = + monacoModel._languageId === "python3" + ? "python" + : monacoModel._languageId; + const title = uwindow.__NEXT_DATA__.query.slug; + + const raysoURL = new URL("https://www.ray.so"); + + raysoURL.hash = "__leetray"; + raysoURL.searchParams.append("code", btoa(sourceCode)); + raysoURL.searchParams.append("title", title); + raysoURL.searchParams.append("padding", 16); + language && raysoURL.searchParams.append("language", language); + language && raysoURL.searchParams.append("colors", colors[language]); + + debug(`Opening URL: ${raysoURL.toString()}`, { + active: true, + setParent: true, + }); + const handler = GM_openInTab(raysoURL.toString()); + + await waitForRaysoLoad(); + + GM_setValue("leetray.screenshot", Date.now()); + + await waitForRaysoExit(); + + window.focus(); + + handler.onclose = () => { + alert("Copied screenshot"); + }; + }, + "s" + ); + } + + async function raysoCopyScreenshot() { + debug("Copying screenshot"); + document.querySelector("#app div.setting.export a:nth-child(3)").click(); + // TODO: flaky mostly + await new Promise((resolve) => setTimeout(resolve, 1000)); + } + + function raysoMain() { + GM_setValue("leetray.rayso.loaded", Date.now()); + + let id = GM_addValueChangeListener("leetray.screenshot", async () => { + window.focus(); + + await raysoCopyScreenshot(); + + GM_removeValueChangeListener(id); + GM_setValue("leetray.rayso.exit", Date.now()); + uwindow.close(); + }); + } + + debug("Starting"); + + if (isLeetcode()) { + leetcodeMain(); + } else if (isRayso()) { + raysoMain(); + } +})(); diff --git a/scripts/bump-version.sh b/scripts/bump-version.sh new file mode 100755 index 0000000..ea739a2 --- /dev/null +++ b/scripts/bump-version.sh @@ -0,0 +1,7 @@ +#!/bin/bash + +script=$1 + +echo $script + +find . -name "$script" -exec sed -i "s=\(// @version[ ]*\)[0-9]*.[0-9]*.[0-9]*=\\1$(date -I'seconds')=g" {} \; \ No newline at end of file