diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a039a0f --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.pyc +__pycache__ +venv \ No newline at end of file diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..c5f75fe --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM python:3.9-alpine3.15 + +COPY requirements.txt /app/ +RUN pip install -r /app/requirements.txt + +COPY assets /app/assets +COPY templates /app/templates +COPY rickroller.py server.py /app/ + +ENTRYPOINT ["python", "/app/server.py"] \ No newline at end of file diff --git a/assets/style.css b/assets/style.css new file mode 100644 index 0000000..71f2c55 --- /dev/null +++ b/assets/style.css @@ -0,0 +1,56 @@ +:root { + --main-font: monospace; + --main-letter-spacing: -0.5px; + --background: #EFEFEF; + --text-color: #111; + + --primary: #333; + --input-background: #F9F9F9; /* #CECECE */ +} + + +body { + font-family: var(--main-font); + letter-spacing: var(--main-letter-spacing); + font-size: 1.3rem; + line-height: 1.3rem; + padding: 10px; + background: var(--background); + color: var(--text-color); + text-align: center; + + background-image: url('https://cdn.vox-cdn.com/thumbor/9j-s_MPUfWM4bWdZfPqxBxGkvlw=/1400x1050/filters:format(jpeg)/cdn.vox-cdn.com/uploads/chorus_asset/file/22312759/rickroll_4k.jpg'); + background-blend-mode: color-burn; + background-size: cover; +} + +form { + margin-top: 3em; +} + + +input[type=url] { + display: block; + margin: 10pt auto; + background: var(--input-background); + border: none; + font-family: monospace; + font-size: .9em; + color: var(--text-color); + padding: 8px 5px; + outline: none !important; +} + +input:-webkit-autofill, +input:-webkit-autofill:hover, +input:-webkit-autofill:active, +input:-webkit-autofill:focus { + background-color: var(--input-background) !important; + color: var(--text-color) !important; + -webkit-box-shadow: 0 0 0 1000px var(--input-background) inset !important; + -webkit-text-fill-color: var(--text-color) !important; +} + +input:-webkit-autofill::first-line { + font-family: var(--main-font) !important; +} \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..5f8ab56 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,4 @@ +flask +beautifulsoup4 +requests +validators \ No newline at end of file diff --git a/rickroller.py b/rickroller.py new file mode 100644 index 0000000..de1e8f1 --- /dev/null +++ b/rickroller.py @@ -0,0 +1,58 @@ +import requests +from bs4 import BeautifulSoup +from urllib.parse import urljoin +import re + +class RickRoller: + + __RICK_ROLL_URL__ = 'https://www.youtube.com/watch?v=dQw4w9WgXcQ' + + @classmethod + def rickroll(self, url: str) -> str: + soup = self.__get_soup(url) + + for a in soup.find('body').find_all('a'): + a.attrs['href'] =self.__RICK_ROLL_URL__ + + args = [soup, url] + self.__absolutize('link', 'href', *args) + self.__absolutize('script', 'src', *args) + self.__absolutize('img', 'src', *args) + + self.__fix_srcset(*args) + + return str(soup) + + @staticmethod + def __absolutize(tagname, attr, soup, url): + for elt in soup.find_all(tagname, **{attr: True}): + elt.attrs[attr] = urljoin(url, elt.attrs[attr]) + + @staticmethod + def __fix_srcset(soup, url): + # for responsive images + # e.g. "/static/563761cc22ded851baff4921ecc27649/e4a55/python-url-decode.jpg 256w, /static/563761cc22ded851baff4921ecc27649/36dd4/python-url-decode.jpg 512w, /static/563761cc22ded851baff4921ecc27649/72e01/python-url-decode.jpg 1024w, /static/563761cc22ded851baff4921ecc27649/ac99c/python-url-decode.jpg 1536w, /static/563761cc22ded851baff4921ecc27649/0f98f/python-url-decode.jpg 1920w" + for elt in soup.find_all('img', srcset=True): + srcset = elt.attrs['srcset'] + + transformed = [] + for entry in re.split(" *, *", srcset): + items = re.split(" +", entry) + transformed.append(" ".join([urljoin(url, items[0])] + items[1:])) + + elt.attrs['srcset'] = ",".join(transformed) + print(srcset) + print(elt.attrs['srcset']) + print("----") + + + @staticmethod + def __get_soup(url: str) -> BeautifulSoup: + try: + response = requests.get(url) + if response.status_code != 200: + raise + return BeautifulSoup(response.text, 'html.parser') + + except Exception as e: + pass \ No newline at end of file diff --git a/server.py b/server.py new file mode 100644 index 0000000..fc9b573 --- /dev/null +++ b/server.py @@ -0,0 +1,25 @@ +from flask import Flask, request, render_template +from validators.url import url as urlvalidate +from rickroller import RickRoller +import urllib + +app = Flask(__name__, static_folder='assets') + +@app.route('/') +def rickroll(): + if (url := request.args.get('u')) is not None: + url = urllib.parse.unquote(url) # may be url-encoded + if not urlvalidate(url): + return f'Invalid URL {url}' + + return RickRoller.rickroll(url) + + return render_template('index.html') + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('-d', '--debug', action='store_true') + args = parser.parse_args() + + app.run(host='0.0.0.0', port=8080, debug=args.debug) \ No newline at end of file diff --git a/templates/index.html b/templates/index.html new file mode 100644 index 0000000..5a0dbb1 --- /dev/null +++ b/templates/index.html @@ -0,0 +1,30 @@ + + + + + + + + URL RickRolling + + + + + + + + + + + +

Rick Roll Any URL

+
+ + + +
+ + \ No newline at end of file