From 245486b95c3438c23c5314910bba4ee12e095841 Mon Sep 17 00:00:00 2001 From: YuanYu Date: Sun, 27 Aug 2023 02:36:05 +0800 Subject: [PATCH] first deploy --- clicker.py | 48 +++++++++++++++++++++++++++++++++++++++++++ dockerfile | 15 ++++++++++++++ mail_server.py | 35 +++++++++++++++++++++++++++++++ netflix_clicker.yaml | 26 +++++++++++++++++++++++ pyproject.toml | 17 +++++++++++++++ pyproject.txt | 19 +++++++++++++++++ requirements.txt | Bin 0 -> 928 bytes 7 files changed, 160 insertions(+) create mode 100644 clicker.py create mode 100644 dockerfile create mode 100644 mail_server.py create mode 100644 netflix_clicker.yaml create mode 100644 pyproject.toml create mode 100644 pyproject.txt create mode 100644 requirements.txt diff --git a/clicker.py b/clicker.py new file mode 100644 index 0000000..6902ded --- /dev/null +++ b/clicker.py @@ -0,0 +1,48 @@ +from selenium import webdriver +from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.common.by import By +from loguru import logger +from fake_useragent import UserAgent +from functools import cache +import time + + +class Clicker: + + def __init__(self, headless: bool = True): + self.chrome_options = webdriver.ChromeOptions() + self.chrome_options.add_argument(f'user-agent={self._user_aget}') + self.chrome_options.add_experimental_option('excludeSwitches', ['enable-logging']) + + if headless: + self.chrome_options.add_argument('--mute-audio') + self.chrome_options.add_argument('--auto-open-devtools-for-tabs') + self.chrome_options.add_argument('--headless') + self.chrome_options.add_argument('--window-size=1440,900') + self.chrome_options.add_argument('--disable-gpu') + self.chrome_options.add_argument('--disable-dev-shm-usage') + self.chrome_options.add_argument("--log-level=3") + self.driver = webdriver.Chrome( + options=self.chrome_options + ) + + def click(self, auth_url: str): + self.driver.get(auth_url) + try: + element = self.driver.find_element(By.CSS_SELECTOR, '[data-uia="set-primary-location-action"]') + element.click() + except NoSuchElementException as e: + self.driver.save_screenshot(f'{time.time()}.png') + logger.error(e) + + def __enter__(self): + return self + + def __exit__(self, type, value, traceback): + self.driver.close() + + @property + @cache + def _user_aget(self): + ua = UserAgent() + return ua.googlechrome diff --git a/dockerfile b/dockerfile new file mode 100644 index 0000000..10a4ff7 --- /dev/null +++ b/dockerfile @@ -0,0 +1,15 @@ +from selenium/standalone-chrome +USER root +RUN useradd -ms /bin/bash netflix +RUN apt update && apt install software-properties-common -y +RUN add-apt-repository ppa:deadsnakes/ppa +RUN apt install -y \ +python3.11 \ +curl +RUN curl -sS https://bootstrap.pypa.io/get-pip.py | python3.11 + +COPY --chown=netflix:netflix . /app +WORKDIR /app +RUN pip install -r requirements.txt +USER root +CMD python3.11 mail_server.py \ No newline at end of file diff --git a/mail_server.py b/mail_server.py new file mode 100644 index 0000000..bda0bbf --- /dev/null +++ b/mail_server.py @@ -0,0 +1,35 @@ +from aiosmtpd.controller import Controller +import quopri +from loguru import logger +import re +from clicker import Clicker +import asyncio + +URL_PATTERN = re.compile(b'"(https://www.netflix.com/account/update-primary-location.*?)"', re.DOTALL) + +class NetflixHandler: + + async def handle_DATA(self, session, envelope, *args): + logger.info('Message from %s' % envelope.mail_from) + data = quopri.decodestring( + envelope.content.decode('utf8', errors='replace') + ) + if urls := URL_PATTERN.findall(data): + with Clicker() as browser: + url = urls[0] + logger.info(f'Found Update link: {url}') + try: + browser.click(url.decode()) + except Exception as e: + logger.error(e) + return '250 Message accepted for delivery' + + +server = Controller(handler=NetflixHandler, hostname='0.0.0.0', port=1025) +server.start() +logger.info('Netflix-clicker start.') +while True: + try: + asyncio.run(asyncio.sleep(3)) + except KeyboardInterrupt: + server.stop() diff --git a/netflix_clicker.yaml b/netflix_clicker.yaml new file mode 100644 index 0000000..6bff6df --- /dev/null +++ b/netflix_clicker.yaml @@ -0,0 +1,26 @@ +apiVersion: v1 +kind: Pod +metadata: + name: netflix-clicker + labels: + app: netflix-clicker +spec: + containers: + - name: netflix-clicker + image: netflix-clicker:latest + imagePullPolicy: IfNotPresent + ports: + - containerPort: 1025 +--- +apiVersion: v1 +kind: Service +metadata: + name: netflix-clicker-service +spec: + type: NodePort + selector: + app: netflix-clicker + ports: + - protocol: TCP + port: 1025 + targetPort: 1025 diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7887237 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,17 @@ +[tool.poetry] +name = "netflix-clicker" +version = "0.1.0" +description = "" +authors = ["YuanYu "] +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.11" +selenium = "^4.11.2" +loguru = "^0.7.0" +fake-useragent = "^1.2.1" +aiosmtpd = "^1.4.4.post2" + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/pyproject.txt b/pyproject.txt new file mode 100644 index 0000000..15ae923 --- /dev/null +++ b/pyproject.txt @@ -0,0 +1,19 @@ +[tool.poetry] +name = "netflix-clicker" +version = "0.1.0" +description = "" +authors = ["YuanYu "] +readme = "README.md" +packages = [{include = "netflix_clicker"}] + +[tool.poetry.dependencies] +python = "^3.11" +selenium = "^4.11.2" +loguru = "^0.7.0" +fake-useragent = "^1.2.1" +aiosmtpd = "^1.4.4.post2" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000000000000000000000000000000000000..ac85526e881775626d749bdc3366fe51b87439b5 GIT binary patch literal 928 zcmY+C;ZDLp5QO))iH}l43&vl*gNaX2N`XdfYdJuDcy+$r9>kEg;dXXrc5Z)vYU^yU zqrF?Q(Khz1Uuh4vnxE0D$tt_IJF6Xavb7!5*EkyF;#y5Mi4B&@ma4!N)y7)YlKQrK z0XdM=-t2MZ zc)abzJn6w3E|T00a@+pnk9kHhH1dOo&Yi=T^M+xxFCoB1R+F>fu$n!-2=OWfc;dd8 zmV1a9U`R@vWD2<+^pAPZS3k@aekN5u