first deploy
This commit is contained in:
commit
245486b95c
48
clicker.py
Normal file
48
clicker.py
Normal file
@ -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
|
||||||
15
dockerfile
Normal file
15
dockerfile
Normal file
@ -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
|
||||||
35
mail_server.py
Normal file
35
mail_server.py
Normal file
@ -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()
|
||||||
26
netflix_clicker.yaml
Normal file
26
netflix_clicker.yaml
Normal file
@ -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
|
||||||
17
pyproject.toml
Normal file
17
pyproject.toml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "netflix-clicker"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["YuanYu <tearsgundam@gmail.com>"]
|
||||||
|
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"
|
||||||
19
pyproject.txt
Normal file
19
pyproject.txt
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[tool.poetry]
|
||||||
|
name = "netflix-clicker"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = ""
|
||||||
|
authors = ["YuanYu <tearsgundam@gmail.com>"]
|
||||||
|
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"
|
||||||
BIN
requirements.txt
Normal file
BIN
requirements.txt
Normal file
Binary file not shown.
Loading…
Reference in New Issue
Block a user