diff --git a/.pdm-python b/.pdm-python deleted file mode 100644 index cf1cebf..0000000 --- a/.pdm-python +++ /dev/null @@ -1 +0,0 @@ -/home/runner/work/paste.py/paste.py/.venv/bin/python \ No newline at end of file diff --git a/src/paste/main.py b/src/paste/main.py index 18a2130..91270ec 100644 --- a/src/paste/main.py +++ b/src/paste/main.py @@ -36,7 +36,7 @@ from . import __version__, __author__, __contact__, __url__ from .schema import PasteCreate, PasteResponse, PasteDetails -description: str = "paste.py 🐍 - A pastebin written in python." +DESCRIPTION: str = "paste.py 🐍 - A pastebin written in python." limiter = Limiter(key_func=get_remote_address) app: FastAPI = FastAPI( @@ -54,16 +54,13 @@ app.state.limiter = limiter -def rate_limit_exceeded_handler(request: Request, exc: Exception) -> Union[Response, Awaitable[Response]]: +def rate_limit_exceeded_handler( + request: Request, exc: Exception +) -> Union[Response, Awaitable[Response]]: if isinstance(exc, RateLimitExceeded): - return Response( - content="Rate limit exceeded", - status_code=429 - ) - return Response( - content="An error occurred", - status_code=500 - ) + return Response(content="Rate limit exceeded", status_code=429) + return Response(content="An error occurred", status_code=500) + app.add_exception_handler(RateLimitExceeded, rate_limit_exceeded_handler) @@ -84,13 +81,14 @@ def rate_limit_exceeded_handler(request: Request, exc: Exception) -> Union[Respo BASE_DIR: Path = Path(__file__).resolve().parent -templates: Jinja2Templates = Jinja2Templates( - directory=str(Path(BASE_DIR, "templates"))) +templates: Jinja2Templates = Jinja2Templates(directory=str(Path(BASE_DIR, "templates"))) @app.post("/file") @limiter.limit("100/minute") -async def post_as_a_file(request: Request, file: UploadFile = File(...)) -> PlainTextResponse: +async def post_as_a_file( + request: Request, file: UploadFile = File(...) +) -> PlainTextResponse: try: uuid: str = generate_uuid() if uuid in large_uuid_storage: @@ -119,7 +117,9 @@ async def post_as_a_file(request: Request, file: UploadFile = File(...)) -> Plai @app.get("/paste/{uuid}") -async def get_paste_data(uuid: str, user_agent: Optional[str] = Header(None)) -> Response: +async def get_paste_data( + request: Request, uuid: str, user_agent: Optional[str] = Header(None) +) -> Response: if not "." in uuid: uuid = _find_without_extension(uuid) path: str = f"data/{uuid}" @@ -143,104 +143,26 @@ async def get_paste_data(uuid: str, user_agent: Optional[str] = Header(None)) -> try: lexer = get_lexer_by_name(file_extension, stripall=True) except ClassNotFound: - lexer = get_lexer_by_name( - "text", stripall=True) # Default lexer + lexer = get_lexer_by_name("text", stripall=True) # Default lexer + formatter = HtmlFormatter( - style="colorful", full=True, linenos="inline", cssclass="code") + style="monokai", # Dark theme base + linenos="inline", + cssclass="highlight", + nowrap=False, + ) + highlighted_code: str = highlight(content, lexer, formatter) - # print(highlighted_code) - custom_style = """ - .code pre span.linenos { - color: #999; - padding-right: 10px; - -webkit-user-select: none; - -webkit-touch-callout: none; - -moz-user-select: none; - -ms-user-select: none; - user-select: none; - } - - span { - font-size: 1.1em !important; - } - - pre { - line-height: 1.4 !important; - } - - .code pre span.linenos::after { - content: ""; - border-right: 1px solid #999; - height: 100%; - margin-left: 10px; - } - - .code { - background-color: #fff; - border: 1.5px solid #ddd; - border-radius: 5px; - margin-bottom: 20px; - overflow: auto; - } - - pre { - font-family: 'Consolas','Monaco','Andale Mono','Ubuntu Mono','monospace;' !important; - } - .copy-button { - position: fixed; - top: 10px; - right: 10px; - padding: 10px; - background-color: #4CAF50; - color: #fff; - cursor: pointer; - border: none; - border-radius: 5px; - outline: none; - } - """ - custom_script = """ - function copyAllText() { - // Create a range object to select the entire document - const range = document.createRange(); - range.selectNode(document.body); - - // Create a selection object and add the range to it - const selection = window.getSelection(); - selection.removeAllRanges(); - selection.addRange(range); - - // Copy the selected text to the clipboard - document.execCommand('copy'); - - // Clear the selection to avoid interfering with the user's selection - selection.removeAllRanges(); - - // You can customize the copied message - alert('All text copied to clipboard!'); - } - - """ - response_content: str = f""" - -
--- - + setTimeout(typeWriter, 800); +}); +{% endblock %} \ No newline at end of file diff --git a/src/paste/templates/paste.html b/src/paste/templates/paste.html new file mode 100644 index 0000000..b6c0187 --- /dev/null +++ b/src/paste/templates/paste.html @@ -0,0 +1,393 @@ +{% extends 'base.html' %} + +{% block title %} {{ uuid }} | paste.py 🐍 {% endblock %} + +{% block headlinks %} + +{% endblock %} + +{% block style %} + +@import url('https://cdnjs.cloudflare.com/ajax/libs/firacode/6.2.0/fira_code.min.css'); +@import url('https://fonts.cdnfonts.com/css/vt323'); + +:root { + --terminal-green: #00ff00; + --terminal-dark: #0c0c0c; + --terminal-shadow: rgba(0, 255, 0, 0.2); + --terminal-font: 'VT323', 'Fira Code', monospace; +} + +* { + box-sizing: border-box; + margin: 0; + padding: 0; +} + +body { + background-color: var(--terminal-dark); + margin: 0; + padding: 20px; + font-family: var(--terminal-font); + line-height: 1.6; + font-size: 20px; + color: var(--terminal-green); + position: relative; + overflow-x: hidden; +} + +/* Matrix Rain Effect */ +#matrix-bg { + position: fixed; + top: 0; + left: 0; + width: 100vw; + height: 100vh; + z-index: -1; + opacity: 0.15; +} + +.container { + max-width: 90%; + margin: 20px auto; + background-color: rgba(12, 12, 12, 0.95); + border: 1px solid var(--terminal-green); + border-radius: 0; + box-shadow: 0 0 20px var(--terminal-shadow); + position: relative; + backdrop-filter: blur(5px); +} + +/* Terminal Window Header */ +.terminal-header { + background: var(--terminal-green); + color: var(--terminal-dark); + padding: 12px; + font-size: 22px; + display: flex; + justify-content: space-between; + align-items: center; +} + +.terminal-header .controls { + display: flex; + gap: 8px; +} + +.terminal-header .control { + width: 14px; + height: 14px; + border-radius: 50%; + border: 1px solid var(--terminal-dark); +} + +.terminal-header .control.close { + background: #ff5f56; +} + +.terminal-header .control.minimize { + background: #ffbd2e; +} + +.terminal-header .control.maximize { + background: #27c93f; +} + +.glitch-text { + position: relative; + display: inline-block; +} + +.glitch-text::before, +.glitch-text::after { + content: attr(data-text); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; +} + +.glitch-text::before { + left: 2px; + text-shadow: -2px 0 #ff00ff; + animation: glitch-1 2s infinite linear alternate-reverse; +} + +.glitch-text::after { + left: -2px; + text-shadow: 2px 0 #00ffff; + animation: glitch-2 2s infinite linear alternate-reverse; +} + +/* Code Display Styles */ +.code { + background-color: rgba(0, 0, 0, 0.7); + border: 1px solid var(--terminal-green); + margin: 20px; + overflow: auto; + position: relative; +} + +.code pre { + padding: 20px; + font-family: 'Fira Code', monospace !important; + font-size: 18px !important; + line-height: 1.5 !important; +} + +.code pre span.linenos { + color: rgba(0, 255, 0, 0.6); + padding-right: 20px; + user-select: none; + border-right: 1px solid rgba(0, 255, 0, 0.3); + margin-right: 20px; +} + +/* Syntax Highlighting Override */ +.highlight, +.highlight pre, +.highlight span { + background-color: transparent !important; + color: var(--terminal-green) !important; +} + +.highlight .k, +.highlight .kd { + color: #ff79c6 !important; +} + +.highlight .s, +.highlight .s1, +.highlight .s2 { + color: #f1fa8c !important; +} + +.highlight .nb, +.highlight .bp { + color: #8be9fd !important; +} + +.highlight .c, +.highlight .c1 { + color: #6272a4 !important; +} + +.highlight .o { + color: #ff79c6 !important; +} + +.highlight .n { + color: #f8f8f2 !important; +} + +.highlight .mi { + color: #bd93f9 !important; +} + +/* Copy Button */ +.copy-button { + position: fixed; + top: 90px; + right: 7%; + padding: 12px 20px; + background-color: rgba(0, 255, 0, 0.2); + color: var(--terminal-green); + cursor: pointer; + border: 1px solid var(--terminal-green); + font-family: var(--terminal-font); + font-size: 18px; + outline: none; + transition: all 0.3s ease; + z-index: 100; + display: flex; + align-items: center; + gap: 8px; +} + +.copy-button:hover { + background-color: var(--terminal-green); + color: var(--terminal-dark); + box-shadow: 0 0 15px var(--terminal-shadow); +} + +/* Animation Keyframes */ +@keyframes glitch-1 { + 0% { + clip-path: inset(20% 0 30% 0); + } + + 20% { + clip-path: inset(65% 0 1% 0); + } + + 40% { + clip-path: inset(43% 0 1% 0); + } + + 60% { + clip-path: inset(25% 0 58% 0); + } + + 80% { + clip-path: inset(75% 0 5% 0); + } + + 100% { + clip-path: inset(10% 0 85% 0); + } +} + +@keyframes glitch-2 { + 0% { + clip-path: inset(25% 0 58% 0); + } + + 20% { + clip-path: inset(75% 0 5% 0); + } + + 40% { + clip-path: inset(10% 0 85% 0); + } + + 60% { + clip-path: inset(20% 0 30% 0); + } + + 80% { + clip-path: inset(65% 0 1% 0); + } + + 100% { + clip-path: inset(43% 0 1% 0); + } +} + +@media only screen and (max-width: 768px) { + body { + padding: 10px; + font-size: 16px; + } + + .container { + max-width: 95%; + margin: 10px auto; + } + + .code pre { + font-size: 16px !important; + padding: 15px; + } + + .copy-button { + top: 80px; + right: 5%; + padding: 10px 15px; + font-size: 16px; + } +} + +{{ pygments_css }} + +{% endblock %} + +{% block content %} + + +ABOUT
+ } +{% endblock %} + +{% block content %} + +++{% endblock %} -+++ + + ++paste.py 🐍+ +++ABOUT
+A simple pastebin powered by FastAPI.
+paste.py 🐍 is Fully Free and Open-Source Source Code
++
+ +- Simple API
+- CLI
+- Web form
+> Web Form: https://paste.fosscu.org/web
+ +API USAGE
+> POST: https://paste.fosscu.org/paste
+Send the raw data along. Will respond with a link to the paste.
+ ++
-- 201 (CREATED): entire paste uploaded
+- 206 (PARTIAL): exceeded server limit
+- Other codes: error
+A simple pastebin powered by FastAPI.
-paste is Fully Free and Open-Source Source Code.
--
+- Simple API
-- CLI
-- Web form
-Pasting is heavily rate limited.
- Web Form: https://paste.fosscu.org/web +> GET: https://paste.fosscu.org/paste/<id>
+Retrieve the paste with the given id as plain-text.
-API USAGE
+> DELETE: https://paste.fosscu.org/paste/<id>
+Delete the paste with the given id.
-POST: https://paste.fosscu.org/paste
-Send the raw data along. Will respond with a link to the paste.
+EXAMPLES
+> cURL: Paste a file named 'file.txt'
+-curl -X POST -F "file=@file.txt" https://paste.fosscu.org/file-
+- 201 (CREATED): entire paste uploaded
-- 206 (PARTIAL): exceeded server limit
-- Other codes: error
-> cURL: Paste from stdin
+-echo "Hello, world." | curl -X POST -F "file=@-" https://paste.fosscu.org/filePasting is heavily rate limited.
+> cURL: Delete an existing paste
+-curl -X DELETE https://paste.fosscu.org/paste/<id>GET: https://paste.fosscu.org/paste/<id>
-Retrieve the paste with the given id as plain-text.
+> Shell function:
+-function paste() { + local file=${1:-/dev/stdin} + curl -X POST -F "file=@${file}" https://paste.fosscu.org/file +}DELETE: https://paste.fosscu.org/paste/<id>
-Delete the paste with the given id.
+A shell function that can be added to .bashrc or .bash_profile or .zshrc for + quick pasting from the command line. The command takes a filename or reads + from stdin if none was supplied and outputs the URL of the paste to stdout:
-EXAMPLES
++paste file.txtcURL: Paste a file named 'file.txt'
+{% block script %} +document.addEventListener('DOMContentLoaded', function() { + // Matrix rain effect + const canvas = document.getElementById('matrix-bg'); + const ctx = canvas.getContext('2d'); -curl -X POST -F "file=@file.txt" https://paste.fosscu.org/file+ canvas.width = window.innerWidth; + canvas.height = window.innerHeight; -cURL: Paste from stdin
+ const characters = "ヲアウエオカキケコサシスセソタツテナニヌネハヒホマミムメモヤユラリワ0123456789".split(""); + const fontSize = 16; + const columns = canvas.width / fontSize; + const drops = []; -echo "Hello, world." | curl -X POST -F "file=@-" https://paste.fosscu.org/file+ for (let i = 0; i < columns; i++) { + drops[i] = 1; + } -cURL: Delete an existing paste
+ function draw() { + ctx.fillStyle = "rgba(0, 0, 0, 0.05)"; + ctx.fillRect(0, 0, canvas.width, canvas.height); -curl -X DELETE https://paste.fosscu.org/paste/<id>+ ctx.fillStyle = "#0F0"; + ctx.font = fontSize + "px monospace"; -Shell function: + for (let i = 0; i < drops.length; i++) { + const text = characters[Math.floor(Math.random() * characters.length)]; + ctx.fillText(text, i * fontSize, drops[i] * fontSize); -
function paste() { - local file=${1:-/dev/stdin} - curl -X POST -F "file=@${file}" https://paste.fosscu.org/file -}+ if (drops[i] * fontSize > canvas.height && Math.random() > 0.975) { + drops[i] = 0; + } - A shell function that can be added to .bashrc or .bash_profle or .zshrc for - quick pasting from the command line. The command takes a filename or reads - from stdin if none was supplied and outputs the URL of the paste to - stdout:paste file.txt+ drops[i]++; + } + } + + window.addEventListener('resize', () => { + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + }); + + setInterval(draw, 35); + + // Terminal boot sequence effect + const container = document.querySelector('.terminal-container'); + container.style.opacity = '0'; + + setTimeout(() => { + container.style.transition = 'opacity 0.5s'; + container.style.opacity = '1'; + }, 300); + + // Add typing effect to the first paragraph + const firstPara = document.querySelector('.terminal-content p'); + const originalText = firstPara.innerHTML; + firstPara.innerHTML = ''; + let i = 0; + + function typeWriter() { + if (i < originalText.length) { + firstPara.innerHTML += originalText.charAt(i); + i++; + setTimeout(typeWriter, 50); + } + } - -