Compare commits

...

27 Commits

Author SHA1 Message Date
9907d6b484 2022.01.30 버그 픽스 2023-01-30 19:41:18 +09:00
cae6985aec 2022.01.30 버그 픽스 2023-01-30 19:26:57 +09:00
a9ea8f193f 2022.01.29 bug fix 2023-01-29 21:21:50 +09:00
ab346ccb19 최신화 정렬 부분 구현(2023. 01. 29)[01] 2023-01-29 00:42:01 +09:00
7a529aa27b ohli24 api update 2023.01.18(01.)
anilife api update 2023.01.18(02-03)
2023-01-28 23:27:16 +09:00
4527e54647 ohli24 api update 2023.01.18(01.)
anilife api update 2023.01.18(02-03)
2023-01-28 20:10:41 +09:00
d6aa3ff42b ohli24 api update 2023.01.18(01.)
anilife api update 2023.01.18(02-03)
2023-01-28 20:03:58 +09:00
1ec1100f52 ohli24 api update 2023.01.18(01.)
anilife api update 2023.01.18(02-02)
2023-01-28 19:59:30 +09:00
dffddb7d28 ohli24 api update 2023.01.18(01.)
anilife api update 2023.01.18(02-01)
2023-01-28 19:57:08 +09:00
21ef7c4bfc ohli24 api update 2023.01.18(01.)
anilife api update 2023.01.18(02.)
2023-01-28 19:50:26 +09:00
af965a7ef9 ohli24 api update 2023.01.18(01.) 2023-01-28 19:31:44 +09:00
09bb3e4a8a ohli24 api update 2023.01.18(01.) 2023-01-28 19:25:16 +09:00
3ac8f3af8e ohli24 api update 2023.01.15(02.) 2023-01-15 17:43:12 +09:00
a3a6a84c97 ohli24 api update 2023.01.15(02.) 2023-01-15 17:10:34 +09:00
1111d37074 ohli24 api update 2023.01.15(02.) 2023-01-15 17:05:52 +09:00
48bb5dd489 ohli24 api update 2023.01.15(02.) 2023-01-15 17:02:14 +09:00
6a309e0e11 ohli24 api update 2023.01.15(01.) 2023-01-15 16:46:48 +09:00
7a82dc2fc7 ohli24 api update 2023.01.13(01.) 2023-01-14 18:22:57 +09:00
b4b567704c ohli24 api update 2023.01.13(01.) 2023-01-13 23:30:54 +09:00
8a78d40c15 ohli24 api update 2023.01.13(01.) 2023-01-13 21:57:59 +09:00
11afb7bf38 ohli24 api update 2023.01.13(01.) 2023-01-13 20:14:11 +09:00
2af1e6d738 ohli24 api update 2022.12.21(01.) 2022-12-21 21:25:56 +09:00
9f1de7aa8c ohli24 api update 2022.11.25(01.) 2022-11-25 19:20:52 +09:00
bfa64d4b8f anilife update 2022.11.09(01.) 2022-11-09 17:27:09 +09:00
027e41be46 2022-10-30 (일부수정) 2022-10-30 05:22:00 +09:00
ce13a3e829 ohli24.net update 2022.10.30(01.) 2022-10-30 00:14:17 +09:00
8e5c73c686 first commit 2022-10-29 16:50:40 +09:00
22 changed files with 5743 additions and 1221 deletions

BIN
.DS_Store vendored Normal file

Binary file not shown.

7
.gitignore vendored
View File

@@ -1,2 +1,7 @@
*.pyo *.pyo
*.pyc *.pyc
.idea
.vscode
.gitignore
test.ipynb

BIN
bin/.DS_Store vendored Normal file

Binary file not shown.

25
lib/utils.py Normal file
View File

@@ -0,0 +1,25 @@
import os
import time
from functools import wraps
try:
from loguru import logger
except:
os.system(f"pip install loguru")
from loguru import logger
def yommi_timeit(func):
@wraps(func)
def timeit_wrapper(*args, **kwargs):
start_time = time.perf_counter()
result = func(*args, **kwargs)
end_time = time.perf_counter()
total_time = end_time - start_time
# print(f"Function {func.__name__}{args} {kwargs} Took {total_time:.4f} secs")
logger.debug(
f"Function {func.__name__}{args} {kwargs} Took {total_time:.4f} secs"
)
return result
return timeit_wrapper

73
linkey.py Normal file
View File

@@ -0,0 +1,73 @@
def get_html_selenium(url, referer):
from selenium.webdriver.common.by import By
from selenium import webdriver
from selenium_stealth import stealth
from webdriver_manager.chrome import ChromeDriverManager
import time
import platform
import os
os_platform = platform.system()
options = webdriver.ChromeOptions()
# 크롬드라이버 헤더 옵션추가 (리눅스에서 실행시 필수)
options.add_argument("start-maximized")
# options.add_argument("--headless")
options.add_argument("--no-sandbox")
options.add_experimental_option("excludeSwitches", ["enable-automation"])
options.add_experimental_option("useAutomationExtension", False)
if os_platform == "Darwin":
# 크롬드라이버 경로
driver_path = "./bin/Darwin/chromedriver"
# driver = webdriver.Chrome(executable_path=driver_path, chrome_options=options)
driver = webdriver.Chrome(
ChromeDriverManager().install(), chrome_options=options
)
else:
driver_bin_path = os.path.join(
os.path.dirname(__file__), "bin", f"{os_platform}"
)
driver_path = f"{driver_bin_path}/chromedriver"
driver = webdriver.Chrome(executable_path=driver_path, chrome_options=options)
stealth(
driver,
languages=["en-US", "en"],
vendor="Google Inc.",
platform="Win32",
webgl_vendor="Intel Inc.",
renderer="Intel Iris OpenGL Engine",
fix_hairline=True,
)
driver.get(url)
driver.refresh()
print(f"current_url:: {driver.current_url}")
# logger.debug(f"current_cookie:: {driver.get_cookies()}")
cookies_list = driver.get_cookies()
cookies_dict = {}
for cookie in cookies_list:
cookies_dict[cookie["name"]] = cookie["value"]
print(cookies_dict)
# LogicAniLife.cookies = cookies_list
# # LogicAniLife.headers["Cookie"] = driver.get_cookies()
# LogicAniLife.episode_url = driver.current_url
time.sleep(1)
elem = driver.find_element(By.XPATH, "//*")
source_code = elem.get_attribute("outerHTML")
li_elem = driver.find_element(By.XPATH, "//li[@class='-qHwcFXhj0']//a")
li_elem.click()
time.sleep(20.0)
return source_code.encode("utf-8")
url = "https://smartstore.naver.com/flamingo_k"
get_html_selenium(url=url, referer=None)

View File

@@ -1,4 +1,5 @@
import os import os
import subprocess
import sys import sys
import threading import threading
import traceback import traceback
@@ -17,12 +18,17 @@ from lxml import html
from urllib import parse from urllib import parse
import urllib import urllib
# my
from .lib.utils import yommi_timeit
packages = [ packages = [
"beautifulsoup4", "beautifulsoup4",
"requests-cache", "requests-cache",
"cloudscraper", "cloudscraper",
"selenium_stealth", "selenium_stealth",
"webdriver_manager", "webdriver_manager",
"html-to-json",
"playwright-har-tracer",
] ]
for package in packages: for package in packages:
try: try:
@@ -577,12 +583,28 @@ class LogicAniLife(LogicModuleBase):
return vod_url return vod_url
except Exception as e: except Exception as e:
logger.error("Exception:%s", e) logger.error("Exception:%s", e)
result = subprocess.run(
["playwright", "install"], stdout=subprocess.PIPE, text=True
)
print(result.stdout)
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
finally: finally:
await browser.close() await browser.close()
@staticmethod @staticmethod
def get_html_selenium(url: str, referer: str) -> bytes: @yommi_timeit
def get_html_selenium(
url: str,
referer: str,
headless=True,
linux=True,
maximize=True,
user_agent=False,
lang_kr=False,
secret_mode=False,
download_path=None,
) -> bytes:
from selenium.webdriver.common.by import By from selenium.webdriver.common.by import By
from selenium import webdriver from selenium import webdriver
from selenium_stealth import stealth from selenium_stealth import stealth
@@ -590,16 +612,44 @@ class LogicAniLife(LogicModuleBase):
import time import time
options = webdriver.ChromeOptions() options = webdriver.ChromeOptions()
# options.add_experimental_option('excludeSwitches', ['enable-logging'])
# 크롬드라이버 헤더 옵션추가 (리눅스에서 실행시 필수) # 크롬드라이버 헤더 옵션추가 (리눅스에서 실행시 필수)
options.add_argument("start-maximized")
options.add_argument("--headless") if headless:
options.add_argument("--headless")
options.add_argument("--no-sandbox") options.add_argument("--no-sandbox")
options.add_argument("window-size=1920x1080") options.add_argument("window-size=1920x1080")
options.add_argument("disable-gpu") options.add_argument("disable-gpu")
# options.add_argument('--no-sandbox') # options.add_argument('--no-sandbox')
options.add_argument("--disable-dev-shm-usage") options.add_argument("--disable-dev-shm-usage")
options.add_experimental_option("excludeSwitches", ["enable-automation"]) # 크롬 드라이버에 setuid를 하지 않음으로써 크롬의 충돌 막음
options.add_argument("--disable-setuid-sandbox")
# disabling extensions
options.add_argument("--disable-extensions")
if download_path:
pass
if maximize:
options.add_argument("start-maximized")
# 일단 좀 더 확인 필요
options.add_experimental_option(
"excludeSwitches", ["enable-automation", "enable-logging"]
)
options.add_experimental_option("useAutomationExtension", False) options.add_experimental_option("useAutomationExtension", False)
options.add_argument("--single-process")
if user_agent:
options.add_argument(
"user-agent=Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/105.0.0.0 "
"Safari/537.36"
)
if lang_kr:
options.add_argument("--lang=ko_KR")
if secret_mode:
options.add_argument("--incognito")
if LogicAniLife.os_platform == "Darwin": if LogicAniLife.os_platform == "Darwin":
# 크롬드라이버 경로 # 크롬드라이버 경로
@@ -608,15 +658,21 @@ class LogicAniLife(LogicModuleBase):
driver = webdriver.Chrome( driver = webdriver.Chrome(
ChromeDriverManager().install(), chrome_options=options ChromeDriverManager().install(), chrome_options=options
) )
else: else:
driver_bin_path = os.path.join( # driver_bin_path = os.path.join(
os.path.dirname(__file__), "bin", f"{LogicAniLife.os_platform}" # os.path.dirname(__file__), "bin", f"{LogicAniLife.os_platform}"
) # )
driver_path = f"{driver_bin_path}/chromedriver" # driver_path = f"{driver_bin_path}/chromedriver"
# driver = webdriver.Chrome(
# executable_path=driver_path, chrome_options=options
# )
driver = webdriver.Chrome( driver = webdriver.Chrome(
executable_path=driver_path, chrome_options=options ChromeDriverManager().install(), chrome_options=options
) )
driver.implicitly_wait(5)
stealth( stealth(
driver, driver,
languages=["ko-KR", "ko"], languages=["ko-KR", "ko"],
@@ -771,6 +827,7 @@ class LogicAniLife(LogicModuleBase):
return render_template("sample.html", title="%s - %s" % (P.package_name, sub)) return render_template("sample.html", title="%s - %s" % (P.package_name, sub))
def process_ajax(self, sub, req): def process_ajax(self, sub, req):
data = []
try: try:
if sub == "analysis": if sub == "analysis":
# code = req.form['code'] # code = req.form['code']
@@ -779,7 +836,6 @@ class LogicAniLife(LogicModuleBase):
wr_id = request.form.get("wr_id", None) wr_id = request.form.get("wr_id", None)
bo_table = request.form.get("bo_table", None) bo_table = request.form.get("bo_table", None)
data = []
# logger.info("code::: %s", code) # logger.info("code::: %s", code)
P.ModelSetting.set("anilife_current_code", code) P.ModelSetting.set("anilife_current_code", code)
@@ -787,7 +843,6 @@ class LogicAniLife(LogicModuleBase):
self.current_data = data self.current_data = data
return jsonify({"ret": "success", "data": data, "code": code}) return jsonify({"ret": "success", "data": data, "code": code})
elif sub == "anime_list": elif sub == "anime_list":
data = []
cate = request.form["type"] cate = request.form["type"]
page = request.form["page"] page = request.form["page"]
@@ -797,7 +852,6 @@ class LogicAniLife(LogicModuleBase):
{"ret": "success", "cate": cate, "page": page, "data": data} {"ret": "success", "cate": cate, "page": page, "data": data}
) )
elif sub == "complete_list": elif sub == "complete_list":
data = []
cate = request.form["type"] cate = request.form["type"]
logger.debug("cate:: %s", cate) logger.debug("cate:: %s", cate)
@@ -809,9 +863,7 @@ class LogicAniLife(LogicModuleBase):
{"ret": "success", "cate": cate, "page": page, "data": data} {"ret": "success", "cate": cate, "page": page, "data": data}
) )
elif sub == "search": elif sub == "search":
data = []
# cate = request.form["type"]
# page = request.form["page"]
cate = request.form["type"] cate = request.form["type"]
query = request.form["query"] query = request.form["query"]
page = request.form["page"] page = request.form["page"]
@@ -1038,7 +1090,7 @@ class LogicAniLife(LogicModuleBase):
"ep_num": ep_num, "ep_num": ep_num,
"title": f"{main_title} {ep_num}화 - {title}", "title": f"{main_title} {ep_num}화 - {title}",
"link": link, "link": link,
"thumbnail": image, "thumbnail": thumbnail,
"date": date, "date": date,
"day": date, "day": date,
"_id": title, "_id": title,
@@ -1049,21 +1101,6 @@ class LogicAniLife(LogicModuleBase):
} }
) )
# print(lxml.etree.tostring(des_items, method="text"))
#
# for idx, item in enumerate(des_items):
# span = item.xpath(".//b/text()")
# logger.info(f"0: {span[0]}")
# key = description_dict[span[0].replace(":", "")]
# logger.debug(f"key:: {key}")
# try:
# print(item.xpath(".//text()")[1].strip())
# des[key] = item.xpath(".//text()")[1].strip()
# except IndexError:
# if item.xpath(".//a"):
# des[key] = item.xpath(".//a")[0]
# des[key] = ""
ser_description = "작품 설명 부분" ser_description = "작품 설명 부분"
des = "" des = ""
des1 = "" des1 = ""
@@ -1224,7 +1261,7 @@ class AniLifeQueueEntity(FfmpegQueueEntity):
tmp["epi_queue"] = self.epi_queue tmp["epi_queue"] = self.epi_queue
return tmp return tmp
def donwload_completed(self): def download_completed(self):
db_entity = ModelAniLifeItem.get_by_anilife_id(self.info["_id"]) db_entity = ModelAniLifeItem.get_by_anilife_id(self.info["_id"])
if db_entity is not None: if db_entity is not None:
db_entity.status = "completed" db_entity.status = "completed"
@@ -1244,13 +1281,11 @@ class AniLifeQueueEntity(FfmpegQueueEntity):
ourls = parse.urlparse(url) ourls = parse.urlparse(url)
self.headers = { self.headers = {
"Referer": f"{ourls.scheme}://{ourls.netloc}", "Referer": LogicAniLife.episode_url,
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Whale/3.12.129.46 Safari/537.36", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/96.0.4664.110 Whale/3.12.129.46 Safari/537.36",
} }
headers["Referer"] = "https://anilife.live/detail/id/471"
headers["Referer"] = LogicAniLife.episode_url
logger.debug("make_episode_info()::url==> %s", url) logger.debug("make_episode_info()::url==> %s", url)
logger.info(f"self.info:::> {self.info}") logger.info(f"self.info:::> {self.info}")
@@ -1276,13 +1311,9 @@ class AniLifeQueueEntity(FfmpegQueueEntity):
) )
) )
# vod_1080p_url = text
# logger.debug(text)
soup = BeautifulSoup(text, "lxml") soup = BeautifulSoup(text, "lxml")
all_scripts = soup.find_all("script") all_scripts = soup.find_all("script")
# print(all_scripts)
regex = r"(?P<jawcloud_url>http?s:\/\/.*=jawcloud)" regex = r"(?P<jawcloud_url>http?s:\/\/.*=jawcloud)"
match = re.compile(regex).search(text) match = re.compile(regex).search(text)
@@ -1355,10 +1386,9 @@ class AniLifeQueueEntity(FfmpegQueueEntity):
vod_1080p_url = asyncio.run( vod_1080p_url = asyncio.run(
LogicAniLife.get_vod_url(jawcloud_url, headless=True) LogicAniLife.get_vod_url(jawcloud_url, headless=True)
) )
print(f"vod_1080p_url:: {vod_1080p_url}") logger.debug(f"vod_1080p_url:: {vod_1080p_url}")
self.url = vod_1080p_url self.url = vod_1080p_url
logger.info(self.url)
except Exception as e: except Exception as e:
P.logger.error("Exception:%s", e) P.logger.error("Exception:%s", e)
P.logger.error(traceback.format_exc()) P.logger.error(traceback.format_exc())

File diff suppressed because it is too large Load Diff

View File

@@ -61,25 +61,29 @@ logger = P.logger
class LogicOhli24(LogicModuleBase): class LogicOhli24(LogicModuleBase):
db_default = { db_default = {
"ohli24_db_version": "1", "ohli24_db_version": "1",
"ohli24_url": "https://ohli24.net", "ohli24_url": "https://ohli24.org",
"ohli24_download_path": os.path.join(path_data, P.package_name, "ohli24"), "ohli24_download_path": os.path.join(path_data, P.package_name, "ohli24"),
"ohli24_auto_make_folder": "True", "ohli24_auto_make_folder": "True",
"ohli24_auto_make_season_folder": "True", "ohli24_auto_make_season_folder": "True",
"ohli24_finished_insert": "[완결]", "ohli24_finished_insert": "[완결]",
"ohli24_max_ffmpeg_process_count": "1", "ohli24_max_ffmpeg_process_count": "1",
"ohli24_order_desc": "False", "ohli24_order_desc": "True",
"ohli24_auto_start": "False", "ohli24_auto_start": "False",
"ohli24_interval": "* 5 * * *", "ohli24_interval": "* 5 * * *",
"ohli24_auto_mode_all": "False", "ohli24_auto_mode_all": "False",
"ohli24_auto_code_list": "all", "ohli24_auto_code_list": "all",
"ohli24_current_code": "", "ohli24_current_code": "",
"ohli24_uncompleted_auto_enqueue": "False", "ohli24_uncompleted_auto_enqueue": "False",
"ohli24_image_url_prefix_series": "https://www.jetcloud.cc/series/", "ohli24_image_url_prefix_series": "",
"ohli24_image_url_prefix_episode": "https://www.jetcloud-list.cc/thumbnail/", "ohli24_image_url_prefix_episode": "",
"ohli24_discord_notify": "True", "ohli24_discord_notify": "True",
} }
current_headers = None current_headers = None
current_data = None current_data = None
referer = None
origin_url = None
episode_url = None
cookies = None
session = requests.Session() session = requests.Session()
headers = { headers = {
@@ -87,7 +91,8 @@ class LogicOhli24(LogicModuleBase):
"Chrome/71.0.3578.98 Safari/537.36", "Chrome/71.0.3578.98 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8",
"Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7", "Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
"Referer": "", # "Referer": "",
# "Cookie": "PHPSESSID=hhhnrora8o9omv1tljq4efv216; 2a0d2363701f23f8a75028924a3af643=NDkuMTYzLjExMS4xMDk=; e1192aefb64683cc97abb83c71057733=aW5n",
} }
useragent = { useragent = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, " "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, "
@@ -100,6 +105,200 @@ class LogicOhli24(LogicModuleBase):
self.queue = None self.queue = None
default_route_socketio(P, self) default_route_socketio(P, self)
@staticmethod
async def get_html_playwright(
url: str,
headless: bool = False,
referer: str = "",
engine: str = "chrome",
stealth: bool = False,
):
try:
from playwright.sync_api import sync_playwright
from playwright.async_api import async_playwright
from playwright_stealth import stealth_sync, stealth_async
import time
cookie = None
# browser_args = [
# "--window-size=1300,570",
# "--window-position=000,000",
# "--disable-dev-shm-usage",
# "--no-sandbox",
# "--disable-web-security",
# "--disable-features=site-per-process",
# "--disable-setuid-sandbox",
# "--disable-accelerated-2d-canvas",
# "--no-first-run",
# "--no-zygote",
# # '--single-process',
# "--disable-gpu",
# # "--use-gl=egl",
# "--disable-blink-features=AutomationControlled",
# # "--disable-background-networking",
# # "--enable-features=NetworkService,NetworkServiceInProcess",
# "--disable-background-timer-throttling",
# "--disable-backgrounding-occluded-windows",
# "--disable-breakpad",
# "--disable-client-side-phishing-detection",
# "--disable-component-extensions-with-background-pages",
# "--disable-default-apps",
# "--disable-extensions",
# "--disable-features=Translate",
# "--disable-hang-monitor",
# "--disable-ipc-flooding-protection",
# "--disable-popup-blocking",
# "--disable-prompt-on-repost",
# # "--disable-renderer-backgrounding",
# "--disable-sync",
# "--force-color-profile=srgb",
# # "--metrics-recording-only",
# # "--enable-automation",
# "--password-store=basic",
# # "--use-mock-keychain",
# # "--hide-scrollbars",
# "--mute-audio",
# ]
browser_args = [
"--window-size=1300,570",
"--window-position=0,0",
# "--disable-dev-shm-usage",
"--no-sandbox",
# "--disable-web-security",
# "--disable-features=site-per-process",
# "--disable-setuid-sandbox",
# "--disable-accelerated-2d-canvas",
# "--no-first-run",
# "--no-zygote",
# "--single-process",
"--disable-gpu",
# "--use-gl=egl",
"--mute-audio",
]
# scraper = cloudscraper.create_scraper(
# browser={"browser": "chrome", "platform": "windows", "desktop": True},
# debug=False,
# # sess=LogicAniLife.session,
# delay=10,
# )
#
# cookie_value, user_agent = scraper.get_cookie_string(url)
#
# logger.debug(f"cookie_value:: {cookie_value}")
start = time.time()
ua = (
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/69.0.3497.100 Safari/537.36"
)
# from playwright_stealth import stealth_sync
def set_cookie(req):
nonlocal cookie
if "cookie" in req.headers:
cookie = req.headers["cookie"]
async with async_playwright() as p:
try:
if engine == "chrome":
browser = await p.chromium.launch(
channel="chrome", args=browser_args, headless=headless
)
elif engine == "webkit":
browser = await p.webkit.launch(
headless=headless,
args=browser_args,
)
else:
browser = await p.firefox.launch(
headless=headless,
args=browser_args,
)
# context = browser.new_context(
# user_agent=ua,
# )
LogicOhli24.headers[
"Referer"
] = "https://anilife.live/detail/id/471"
# print(LogicAniLife.headers)
LogicOhli24.headers["Referer"] = LogicOhli24.episode_url
if referer is not None:
LogicOhli24.headers["Referer"] = referer
# logger.debug(f"LogicAniLife.headers::: {LogicOhli24.headers}")
context = await browser.new_context(
extra_http_headers=LogicOhli24.headers, ignore_https_errors=True
)
# await context.add_cookies(LogicOhli24.cookies)
# LogicAniLife.headers["Cookie"] = cookie_value
# await context.set_extra_http_headers(LogicOhli24.headers)
page = await context.new_page()
# page.set_extra_http_headers(LogicAniLife.headers)
if stealth:
await stealth_async(page)
# page.on("request", set_cookie)
# stealth_sync(page)
# print(LogicOhli24.headers["Referer"])
# page.on("request", set_cookie)
print(f'Referer:: {LogicOhli24.headers["Referer"]}')
# await page.set_extra_http_headers(LogicAniLife.headers)
# domcontentloaded
# load
# networkidle
await page.goto(
url,
wait_until="load",
# referer=LogicOhli24.headers["Referer"],
)
# await page.wait_for_url(url, wait_until="domcontentloaded")
# page.wait_for_timeout(10000)
# await asyncio.sleep(2.9)
await asyncio.sleep(1)
# await page.reload()
# time.sleep(10)
# cookies = context.cookies
# print(cookies)
print(f"page.url:: {page.url}")
LogicOhli24.origin_url = page.url
temp_content = await page.content()
#
# print(temp_content)
print(f"run at {time.time() - start} sec")
return temp_content
except Exception as e:
logger.error("Exception:%s", e)
logger.error(traceback.format_exc())
finally:
await browser.close()
except Exception as e:
logger.error("Exception:%s", e)
logger.error(traceback.format_exc())
finally:
# browser.close()
pass
@staticmethod @staticmethod
def db_init(): def db_init():
pass pass
@@ -188,6 +387,7 @@ class LogicOhli24(LogicModuleBase):
} }
) )
elif sub == "add_queue": elif sub == "add_queue":
logger.debug(f"linkkf add_queue routine ===============")
ret = {} ret = {}
info = json.loads(request.form["data"]) info = json.loads(request.form["data"])
logger.info(f"info:: {info}") logger.info(f"info:: {info}")
@@ -244,9 +444,48 @@ class LogicOhli24(LogicModuleBase):
logger.error("Exception:%s", e) logger.error("Exception:%s", e)
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
except Exception as e: except Exception as e:
P.logger.error("Exception:%s", e) P.logger.error(f"Exception: {str(e)}")
P.logger.error(traceback.format_exc()) P.logger.error(traceback.format_exc())
def process_api(self, sub, req):
logger.debug("here!")
ret = {}
try:
if sub == "anime_list":
logger.debug(f"anime_list =*==")
logger.debug(req)
data = []
cate = req.form["type"]
page = req.form["page"]
data = self.get_anime_info(cate, page)
# self.current_data = data
return jsonify(
{"ret": "success", "cate": cate, "page": page, "data": data}
)
except Exception as exception:
logger.error("Exception:%s", exception)
logger.error(traceback.format_exc())
ret["ret"] = "exception"
ret["data"] = str(exception)
return jsonify(ret)
#########################################################
# API
#########################################################
# @blueprint.route("/api/<sub>", methods=["GET", "POST"])
# @check_api
# def api(self, sub):
# if sub == "ohli24":
# try:
# logger.debug("api ohli24")
# data = {"aaaa"}
# except Exception as e:
# logger.error("Exception:%s", e)
# logger.error(traceback.format_exc())
# return data
@staticmethod @staticmethod
def add_whitelist(*args): def add_whitelist(*args):
ret = {} ret = {}
@@ -486,7 +725,7 @@ class LogicOhli24(LogicModuleBase):
+ li.xpath('.//a[@class="item-subject"]/@href')[0] + li.xpath('.//a[@class="item-subject"]/@href')[0]
) )
# logger.debug(f"link:: {link}") # logger.debug(f"link:: {link}")
date = li.xpath('.//div[@class="wr-date"]/text()')[0] _date = li.xpath('.//div[@class="wr-date"]/text()')[0]
m = hashlib.md5(title.encode("utf-8")) m = hashlib.md5(title.encode("utf-8"))
# _vi = hashlib.md5(title.encode('utf-8').hexdigest()) # _vi = hashlib.md5(title.encode('utf-8').hexdigest())
# logger.info(m.hexdigest()) # logger.info(m.hexdigest())
@@ -496,8 +735,8 @@ class LogicOhli24(LogicModuleBase):
"title": title, "title": title,
"link": link, "link": link,
"thumbnail": image, "thumbnail": image,
"date": date, "date": _date,
"day": date, "day": _date,
"_id": title, "_id": title,
"va": link, "va": link,
"_vi": _vi, "_vi": _vi,
@@ -505,7 +744,12 @@ class LogicOhli24(LogicModuleBase):
} }
) )
logger.info("des_items length:: %s", len(des_items)) logger.debug(P.ModelSetting.get("ohli24_order_desc"))
# if P.ModelSetting.get("ohli24_order_desc") == "False":
# print("Here....")
# episodes.reverse()
# logger.info("des_items length:: %s", len(des_items))
for idx, item in enumerate(des_items): for idx, item in enumerate(des_items):
# key = des_key[idx] # key = des_key[idx]
span = item.xpath(".//span//text()") span = item.xpath(".//span//text()")
@@ -534,7 +778,7 @@ class LogicOhli24(LogicModuleBase):
"episode": episodes, "episode": episodes,
} }
if P.ModelSetting.get_bool("ohli24_order_desc"): if not P.ModelSetting.get_bool("ohli24_order_desc"):
data["episode"] = list(reversed(data["episode"])) data["episode"] = list(reversed(data["episode"]))
data["list_order"] = "desc" data["list_order"] = "desc"
@@ -576,6 +820,16 @@ class LogicOhli24(LogicModuleBase):
logger.info("url:::> %s", url) logger.info("url:::> %s", url)
data = {} data = {}
response_data = LogicOhli24.get_html(url, timeout=10) response_data = LogicOhli24.get_html(url, timeout=10)
# response_data = asyncio.run(
# LogicOhli24.get_html_playwright(
# url,
# headless=False,
# # referer=referer_url,
# engine="chrome",
# # stealth=True,
# )
# )
# print(response_data)
tree = html.fromstring(response_data) tree = html.fromstring(response_data)
tmp_items = tree.xpath('//div[@class="list-row"]') tmp_items = tree.xpath('//div[@class="list-row"]')
data["anime_count"] = len(tmp_items) data["anime_count"] = len(tmp_items)
@@ -704,23 +958,56 @@ class LogicOhli24(LogicModuleBase):
return True return True
@staticmethod @staticmethod
def get_html(url, referer=None, stream=False, timeout=5): def get_html(
url, headers=None, referer=None, stream=False, timeout=5, stealth=False
):
# global response_data
data = "" data = ""
# response_date = ""
try: try:
print("cloudflare protection bypass ==================P")
response_date = ""
if headers is not None:
LogicOhli24.headers = headers
logger.debug(f"headers: {LogicOhli24.headers}")
# response_data = asyncio.run(
# LogicOhli24.get_html_playwright(
# url,
# headless=True,
# # referer=referer_url,
# engine="chrome",
# # stealth=True,
# )
# )
# # print(response_data)
#
# logger.debug(len(response_data))
# return response_data
if LogicOhli24.session is None: if LogicOhli24.session is None:
LogicOhli24.session = requests.session() LogicOhli24.session = requests.session()
# logger.debug('get_html :%s', url) # logger.debug('get_html :%s', url)
headers["Referer"] = "" if referer is None else referer # LogicOhli24.headers["Referer"] = "" if referer is None else referer
logger.debug(f"referer:: {referer}")
if referer:
LogicOhli24.headers["Referer"] = referer
# logger.info(headers)
logger.debug(f"LogicOhli24.headers:: {LogicOhli24.headers}")
page_content = LogicOhli24.session.get( page_content = LogicOhli24.session.get(
url, headers=headers, timeout=timeout url, headers=LogicOhli24.headers, timeout=timeout
) )
data = page_content.text response_data = page_content.text
# logger.debug(response_data)
return response_data
except Exception as e: except Exception as e:
logger.error("Exception:%s", e) logger.error("Exception:%s", e)
logger.error(traceback.format_exc()) logger.error(traceback.format_exc())
return data # return response_data
######################################################### #########################################################
def add(self, episode_info): def add(self, episode_info):
@@ -792,25 +1079,29 @@ class Ohli24QueueEntity(FfmpegQueueEntity):
db_entity.save() db_entity.save()
# Get episode info from OHLI24 site # Get episode info from OHLI24 site
def make_episode_info_old(self): def make_episode_info(self):
try: try:
# url = 'https://ohli24.net/e/' + self.info['va'] base_url = "https://ohli24.org"
base_url = "https://ohli24.net"
iframe_url = "" iframe_url = ""
# https://ohli24.net/e/%EB%85%B9%EC%9D%84%20%EB%A8%B9%EB%8A%94%20%EB%B9%84%EC%8A%A4%EC%BD%94%206%ED%99%94 # https://ohli24.org/e/%EB%85%B9%EC%9D%84%20%EB%A8%B9%EB%8A%94%20%EB%B9%84%EC%8A%A4%EC%BD%94%206%ED%99%94
url = self.info["va"] url = self.info["va"]
ourls = parse.urlparse(url) ourls = parse.urlparse(url)
headers = { headers = {
"Referer": f"{ourls.scheme}://{ourls.netloc}", "Referer": f"{ourls.scheme}://{ourls.netloc}",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Whale/3.12.129.46 Safari/537.36", "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/96.0.4664.110 Whale/3.12.129.46 Safari/537.36",
} }
logger.debug(headers)
logger.debug("make_episode_info()::url==> %s", url) logger.debug("make_episode_info()::url==> %s", url)
logger.info(f"self.info:::> {self.info}") logger.info(f"self.info:::> {self.info}")
text = requests.get(url, headers=headers).text # text = requests.get(url, headers=headers).text
text = LogicOhli24.get_html(
url, headers=headers, referer=f"{ourls.scheme}://{ourls.netloc}"
)
# logger.debug(text) # logger.debug(text)
soup1 = BeautifulSoup(text, "lxml") soup1 = BeautifulSoup(text, "lxml")
pattern = re.compile(r"url : \"\.\.(.*)\"") pattern = re.compile(r"url : \"\.\.(.*)\"")
@@ -822,221 +1113,15 @@ class Ohli24QueueEntity(FfmpegQueueEntity):
iframe_url = match.group(1) iframe_url = match.group(1)
logger.info("iframe_url::> %s", iframe_url) logger.info("iframe_url::> %s", iframe_url)
resp = requests.get(base_url + iframe_url, headers=headers, timeout=20).text
soup2 = BeautifulSoup(resp, "lxml")
iframe_src = soup2.find("iframe")["src"]
# print(resp1)
logger.debug(f"iframe_src:::> {iframe_src}")
resp1 = requests.get(iframe_src, headers=headers, timeout=600).text
# logger.info('resp1::>> %s', resp1)
soup3 = BeautifulSoup(resp1, "lxml")
# packed_pattern = re.compile(r'\\{*(eval.+)*\\}', re.MULTILINE | re.DOTALL)
s_pattern = re.compile(r"(eval.+)", re.MULTILINE | re.DOTALL)
packed_pattern = re.compile(
r"if?.([^{}]+)\{.*(eval.+)\}.+else?.{.(eval.+)\}", re.DOTALL
)
packed_script = soup3.find("script", text=s_pattern)
# packed_script = soup3.find('script')
# logger.info('packed_script>>> %s', packed_script.text)
unpack_script = None
if packed_script is not None:
# logger.debug('zzzzzzzzzzzz')
match = packed_pattern.search(packed_script.text)
# match = re.search(packed_pattern, packed_script.text)
# logger.debug("match::: %s", match.group())
unpack_script = jsbeautifier.beautify(match.group(3))
# logger.info('match groups:: %s', match.groups())
# logger.info('match group3:: %s', match.group(3))
# print('packed_script==>', packed_script)
# logger.debug(unpack_script)
p1 = re.compile(r"(\"tracks\".*\])\,\"captions\"", re.MULTILINE | re.DOTALL)
m2 = re.search(
r"(\"tracks\".*\]).*\"captions\"",
unpack_script,
flags=re.MULTILINE | re.DOTALL,
)
# print(m2.group(1))
dict_string = "{" + m2.group(1) + "}"
logger.info(f"dict_string::> {dict_string}")
tracks = json.loads(dict_string)
self.srt_url = tracks["tracks"][0]["file"]
logger.debug(f'srt_url::: {tracks["tracks"][0]["file"]}')
video_hash = iframe_src.split("/")
video_hashcode = re.sub(r"index\.php\?data=", "", video_hash[-1])
self._vi = video_hashcode
video_info_url = f"{video_hash[0]}//{video_hash[2]}/player/index.php?data={video_hashcode}&do=getVideo"
# print('hash:::', video_hash)
logger.debug(f"video_info_url::: {video_info_url}")
headers = {
"referer": f"{iframe_src}",
"user-agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/96.0.4664.110 Whale/3.12.129.46 Safari/537.36"
"Mozilla/5.0 (Macintosh; Intel "
"Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 "
"Whale/3.12.129.46 Safari/537.36",
"X-Requested-With": "XMLHttpRequest",
}
# print(headers)
payload = {
"hash": video_hash[-1],
}
resp2 = requests.post(
video_info_url, headers=headers, data=payload, timeout=20
).json()
logger.debug("resp2::> %s", resp2)
hls_url = resp2["videoSource"]
logger.debug(f"video_url::> {hls_url}")
resp3 = requests.get(hls_url, headers=headers).text
# logger.debug(resp3)
# stream_url = hls_url.split('\n')[-1].strip()
stream_info = resp3.split("\n")[-2:]
# logger.debug('stream_url:: %s', stream_url)
logger.debug(f"stream_info:: {stream_info}")
self.headers = {
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/71.0.3554.0 Safari/537.36Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/71.0.3554.0 Safari/537.36",
"Referer": "https://ndoodle.xyz/video/03a3655fff3e9bdea48de9f49e938e32",
}
self.url = stream_info[1].strip()
match = re.compile(r'NAME="(?P<quality>.*?)"').search(stream_info[0])
self.quality = "720P"
if match is not None:
self.quality = match.group("quality")
logger.info(self.quality)
match = re.compile(
r"(?P<title>.*?)\s*((?P<season>\d+)%s)?\s*((?P<epi_no>\d+)%s)"
% ("", "")
).search(self.info["title"])
# epi_no 초기값
epi_no = 1
if match:
self.content_title = match.group("title").strip()
if "season" in match.groupdict() and match.group("season") is not None:
self.season = int(match.group("season"))
# epi_no = 1
epi_no = int(match.group("epi_no"))
ret = "%s.S%sE%s.%s-OHNI24.mp4" % (
self.content_title,
"0%s" % self.season if self.season < 10 else self.season,
"0%s" % epi_no if epi_no < 10 else epi_no,
self.quality,
)
else:
self.content_title = self.info["title"]
P.logger.debug("NOT MATCH")
ret = "%s.720p-OHNI24.mp4" % self.info["title"]
# logger.info('self.content_title:: %s', self.content_title)
self.epi_queue = epi_no
self.filename = Util.change_text_for_use_filename(ret)
logger.info(f"self.filename::> {self.filename}")
self.savepath = P.ModelSetting.get("ohli24_download_path")
logger.info(f"self.savepath::> {self.savepath}")
# TODO: 완결 처리
if P.ModelSetting.get_bool("ohli24_auto_make_folder"):
if self.info["day"].find("완결") != -1:
folder_name = "%s %s" % (
P.ModelSetting.get("ohli24_finished_insert"),
self.content_title,
)
else:
folder_name = self.content_title
folder_name = Util.change_text_for_use_filename(folder_name.strip())
self.savepath = os.path.join(self.savepath, folder_name)
if P.ModelSetting.get_bool("ohli24_auto_make_season_folder"):
self.savepath = os.path.join(
self.savepath, "Season %s" % int(self.season)
)
self.filepath = os.path.join(self.savepath, self.filename)
if not os.path.exists(self.savepath):
os.makedirs(self.savepath)
from framework.common.util import write_file, convert_vtt_to_srt
srt_filepath = os.path.join(
self.savepath, self.filename.replace(".mp4", ".ko.srt")
)
if self.srt_url is not None and not os.path.exists(srt_filepath):
# vtt_data = requests.get(self.vtt, headers=headers).text
# srt_data = convert_vtt_to_srt(vtt_data)
srt_data = requests.get(self.srt_url, headers=headers).text
write_file(srt_data, srt_filepath)
except Exception as e:
P.logger.error("Exception:%s", e)
P.logger.error(traceback.format_exc())
def make_episode_info(self):
try:
# url = 'https://ohli24.net/e/' + self.info['va']
base_url = "https://ohli24.net"
iframe_url = ""
# https://ohli24.net/e/%EB%85%B9%EC%9D%84%20%EB%A8%B9%EB%8A%94%20%EB%B9%84%EC%8A%A4%EC%BD%94%206%ED%99%94
url = self.info["va"]
ourls = parse.urlparse(url)
headers = {
"referer": f"{ourls.scheme}://{ourls.netloc}",
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Whale/3.12.129.46 Safari/537.36",
}
logger.debug("make_episode_info()::url==> %s", url)
logger.info(f"self.info:::> {self.info}")
text = requests.get(url, headers=headers).text
# logger.debug(text)
soup1 = BeautifulSoup(text, "lxml")
pattern = re.compile(r"url : \"\.\.(.*)\"")
script = soup1.find("script", text=pattern)
if script:
match = pattern.search(script.text)
if match:
iframe_url = match.group(1)
logger.info("iframe_url::> %s", iframe_url)
logger.debug(soup1.find("iframe"))
iframe_url = soup1.find("iframe")["src"] iframe_url = soup1.find("iframe")["src"]
logger.info("iframe_url::> %s", iframe_url)
print(base_url)
print(iframe_url)
# exit()
# resp = requests.get(iframe_url, headers=headers, timeout=20).text
# soup2 = BeautifulSoup(resp, "lxml")
# iframe_src = soup2.find("iframe")["src"]
iframe_src = iframe_url iframe_src = iframe_url
# print(resp1)
logger.debug(f"iframe_src:::> {iframe_src}") logger.debug(f"iframe_src:::> {iframe_src}")
resp1 = requests.get(iframe_src, headers=headers, timeout=600).text # resp1 = requests.get(iframe_src, headers=headers, timeout=600).text
# logger.info('resp1::>> %s', resp1) resp1 = LogicOhli24.get_html(iframe_src, headers=headers, timeout=600)
logger.info("resp1::>> %s", resp1)
soup3 = BeautifulSoup(resp1, "lxml") soup3 = BeautifulSoup(resp1, "lxml")
# packed_pattern = re.compile(r'\\{*(eval.+)*\\}', re.MULTILINE | re.DOTALL) # packed_pattern = re.compile(r'\\{*(eval.+)*\\}', re.MULTILINE | re.DOTALL)
s_pattern = re.compile(r"(eval.+)", re.MULTILINE | re.DOTALL) s_pattern = re.compile(r"(eval.+)", re.MULTILINE | re.DOTALL)
@@ -1045,19 +1130,17 @@ class Ohli24QueueEntity(FfmpegQueueEntity):
) )
packed_script = soup3.find("script", text=s_pattern) packed_script = soup3.find("script", text=s_pattern)
# packed_script = soup3.find('script') # packed_script = soup3.find('script')
# logger.info('packed_script>>> %s', packed_script.text) # logger.info("packed_script>>> %s", packed_script.text)
unpack_script = None unpack_script = None
if packed_script is not None: if packed_script is not None:
# logger.debug('zzzzzzzzzzzz') # logger.debug('zzzzzzzzzzzz')
match = packed_pattern.search(packed_script.text) match = packed_pattern.search(packed_script.text)
# match = re.search(packed_pattern, packed_script.text) # match = re.search(packed_pattern, packed_script.text)
# logger.debug("match::: %s", match.group()) # logger.debug("match::: %s", match.group())
unpack_script = jsbeautifier.beautify(match.group(3)) # unpack_script = jsbeautifier.beautify(match.group(3))
# logger.info('match groups:: %s', match.groups()) logger.debug(type(packed_script))
# logger.info('match group3:: %s', match.group(3)) unpack_script = jsbeautifier.beautify(str(packed_script))
# print('packed_script==>', packed_script)
# logger.debug(unpack_script)
p1 = re.compile(r"(\"tracks\".*\])\,\"captions\"", re.MULTILINE | re.DOTALL) p1 = re.compile(r"(\"tracks\".*\])\,\"captions\"", re.MULTILINE | re.DOTALL)
m2 = re.search( m2 = re.search(
@@ -1068,7 +1151,7 @@ class Ohli24QueueEntity(FfmpegQueueEntity):
# print(m2.group(1)) # print(m2.group(1))
dict_string = "{" + m2.group(1) + "}" dict_string = "{" + m2.group(1) + "}"
logger.info(f"dict_string::> {dict_string}") # logger.info(f"dict_string::> {dict_string}")
tracks = json.loads(dict_string) tracks = json.loads(dict_string)
self.srt_url = tracks["tracks"][0]["file"] self.srt_url = tracks["tracks"][0]["file"]
@@ -1089,8 +1172,9 @@ class Ohli24QueueEntity(FfmpegQueueEntity):
"Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 " "Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 "
"Whale/3.12.129.46 Safari/537.36", "Whale/3.12.129.46 Safari/537.36",
"X-Requested-With": "XMLHttpRequest", "X-Requested-With": "XMLHttpRequest",
"Cookie": "PHPSESSID=hhhnrora8o9omv1tljq4efv216; 2a0d2363701f23f8a75028924a3af643=NDkuMTYzLjExMS4xMDk=; e1192aefb64683cc97abb83c71057733=aW5n",
} }
# print(headers)
payload = { payload = {
"hash": video_hash[-1], "hash": video_hash[-1],
} }
@@ -1183,10 +1267,11 @@ class Ohli24QueueEntity(FfmpegQueueEntity):
self.savepath, self.filename.replace(".mp4", ".ko.srt") self.savepath, self.filename.replace(".mp4", ".ko.srt")
) )
if self.srt_url is not None and not os.path.exists(srt_filepath): if (
# vtt_data = requests.get(self.vtt, headers=headers).text self.srt_url is not None
# srt_data = convert_vtt_to_srt(vtt_data) and not os.path.exists(srt_filepath)
and not ("thumbnails.vtt" in self.srt_url)
):
srt_data = requests.get(self.srt_url, headers=headers).text srt_data = requests.get(self.srt_url, headers=headers).text
write_file(srt_data, srt_filepath) write_file(srt_data, srt_filepath)

View File

@@ -89,9 +89,10 @@ def initialize():
PluginUtil.make_info_json(P.plugin_info, __file__) PluginUtil.make_info_json(P.plugin_info, __file__)
from .logic_ohli24 import LogicOhli24 from .logic_ohli24 import LogicOhli24
from .logic_anilife import LogicAniLife from .logic_anilife import LogicAniLife
from .logic_linkkf import LogicLinkkf
# P.module_list = [LogicOhli24(P), LogicLinkkf(P)] # P.module_list = [LogicOhli24(P), LogicLinkkf(P)]
P.module_list = [LogicOhli24(P), LogicAniLife(P)] P.module_list = [LogicOhli24(P), LogicAniLife(P), LogicLinkkf(P)]
P.logic = Logic(P) P.logic = Logic(P)
default_route(P) default_route(P)
except Exception as e: except Exception as e:

243
static/css/linkkf.css Normal file
View File

@@ -0,0 +1,243 @@
button.code-button {
min-width: 82px !important;
}
.tooltip {
position: relative;
display: block;
}
[data-tooltip-text]:hover {
position: relative;
}
[data-tooltip-text]:after {
-webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
-moz-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
background-color: rgba(0, 0, 0, 0.8);
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
color: #ffffff;
font-size: 12px;
margin-bottom: 10px;
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
z-index: 9999;
opacity: 0;
left: -9999px;
top: 90%;
content: attr(data-tooltip-text);
}
[data-tooltip-text]:hover:after {
top: 230%;
left: 0;
opacity: 1;
}
[data-tooltip-text]:hover {
position: relative;
}
[data-tooltip-text]:after {
-webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
-moz-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
background-color: rgba(0, 0, 0, 0.8);
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
color: #ffffff;
font-size: 12px;
margin-bottom: 10px;
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
z-index: 9999;
opacity: 0;
left: -9999px;
top: -210% !important;
content: attr(data-tooltip-text);
}
[data-tooltip-text]:hover:after {
top: 130%;
left: 0;
opacity: 1;
}
#airing_list {
display: none;
}
.cut-text {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
}
@media (min-width: 576px) {
.container {
max-width: 100%;
}
}
@media (min-width: 1280px) {
#yommi_wrapper {
max-width: 80%;
margin: 0 auto;
}
}
#screen_movie_list {
margin-top: 10px;
}
/* .spinner {*/
/* width: 40px;*/
/* height: 40px;*/
/* background-color: #333;*/
/* margin: 100px auto;*/
/* -webkit-animation: sk-rotateplane 1.2s infinite ease-in-out;*/
/* animation: sk-rotateplane 1.2s infinite ease-in-out;*/
/*}*/
/*@-webkit-keyframes sk-rotateplane {*/
/* 0% { -webkit-transform: perspective(120px) }*/
/* 50% { -webkit-transform: perspective(120px) rotateY(180deg) }*/
/* 100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) }*/
/*}*/
/*@keyframes sk-rotateplane {*/
/* 0% {*/
/* transform: perspective(120px) rotateX(0deg) rotateY(0deg);*/
/* -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg)*/
/* } 50% {*/
/* transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);*/
/* -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg)*/
/* } 100% {*/
/* transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);*/
/* -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);*/
/* }*/
/*}*/
.spinner {
width: 40px;
height: 40px;
position: relative;
margin: 100px auto;
}
.double-bounce1,
.double-bounce2 {
width: 100%;
height: 100%;
border-radius: 50%;
background-color: #333;
opacity: 0.6;
position: absolute;
top: 0;
left: 0;
-webkit-animation: sk-bounce 2s infinite ease-in-out;
animation: sk-bounce 2s infinite ease-in-out;
}
.double-bounce2 {
-webkit-animation-delay: -1s;
animation-delay: -1s;
}
@-webkit-keyframes sk-bounce {
0%,
100% {
-webkit-transform: scale(0);
}
50% {
-webkit-transform: scale(1);
}
}
@keyframes sk-bounce {
0%,
100% {
transform: scale(0);
-webkit-transform: scale(0);
}
50% {
transform: scale(1);
-webkit-transform: scale(1);
}
}
.badge-on-image {
position: absolute;
top: 2px;
/*bottom: 2px; !* position where you want it *!*/
right: 2px;
padding: 5px 12px;
}
#inner_screen_movie > div {
margin-bottom: 10px;
}
.card-body {
padding: 0!important;
}
.new-anime {
border-color: darksalmon;
border-width: 4px;
border-style: dashed;
}
.card-title {
padding: 1rem!important;
}
button#add_whitelist {
float: right;
}
button.btn-favorite {
background-color: #e0ff42;
}
body {
font-family: NanumSquareNeo,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans,Liberation Sans,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;
}
body {
background-image: linear-gradient(90deg, #233f48, #6c6fa2, #768dae);
}

View File

@@ -56,11 +56,6 @@
<form id="screen_movie_list_form"> <form id="screen_movie_list_form">
<div id="screen_movie_list" class="container"></div> <div id="screen_movie_list" class="container"></div>
</form> </form>
<div class="text-center">
<div id="spinner" class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<form id="program_auto_form"> <form id="program_auto_form">
<div id="episode_list"></div> <div id="episode_list"></div>
</form> </form>

View File

@@ -192,6 +192,7 @@
} else { } else {
document.getElementById("code").value = params.code document.getElementById("code").value = params.code
document.getElementById("analysis_btn").click(); document.getElementById("analysis_btn").click();
return;
} }
if ("{{arg['anilife_current_code']}}" !== "") { if ("{{arg['anilife_current_code']}}" !== "") {

View File

@@ -1,49 +1,57 @@
{% extends "base.html" %} {% block content %} {% extends "base.html" %} {% block content %}
<div id="preloader" class="loader">
<div class="input-group mb-2"> <div class="loader-inner">
<input <div class="loader-line-wrap">
id="input_search" <div class="loader-line"></div>
type="search" </div>
class="form-control rounded" <div class="loader-line-wrap">
placeholder="Search" <div class="loader-line"></div>
aria-label="Search" </div>
aria-describedby="search-addon" <div class="loader-line-wrap">
/> <div class="loader-line"></div>
<button id="btn_search" type="button" class="btn btn-outline-primary"> </div>
search <div class="loader-line-wrap">
</button> <div class="loader-line"></div>
</div>
<div class="loader-line-wrap">
<div class="loader-line"></div>
</div>
</div>
</div> </div>
<div id="yommi_wrapper">
<div class="input-group mb-2">
<input
id="input_search"
type="search"
class="form-control rounded"
placeholder="Search"
aria-label="Search"
aria-describedby="search-addon"
/>
<button id="btn_search" type="button" class="btn btn-primary">search</button>
</div>
<div> <div>
<div <div id="anime_category" class="btn-group" role="group" aria-label="Basic example">
id="anime_category" <button id="ing" type="button" class="btn btn-success">방영중</button>
class="btn-group" <button id="theater" type="button" class="btn btn-primary">극장판</button>
role="group" <button id="complete_anilist" type="button" class="btn btn-dark">완결</button>
aria-label="Basic example"
>
<button id="ing" type="button" class="btn btn-success">방영중</button>
<button id="theater" type="button" class="btn btn-primary">극장판</button>
<button id="complete_anilist" type="button" class="btn btn-dark">
완결
</button>
</div> </div>
<form id="airing_list_form"> <form id="airing_list_form">
<div id="airing_list"></div> <div id="airing_list"></div>
</form> </form>
<form id="screen_movie_list_form"> <form id="screen_movie_list_form">
<div id="screen_movie_list" class="container"></div> <div id="screen_movie_list" class="container"></div>
</form> </form>
<div class="text-center">
<div id="spinner" class="spinner-border" role="status">
<span class="sr-only">Loading...</span>
</div>
</div>
<form id="program_auto_form"> <form id="program_auto_form">
<div id="episode_list"></div> <div id="episode_list"></div>
</form> </form>
</div>
</div> </div>
<!--전체--> <!--전체-->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"></script>
<script <script
type="text/javascript" type="text/javascript"
src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js" src="https://cdn.jsdelivr.net/npm/lozad/dist/lozad.min.js"
@@ -127,28 +135,30 @@
} }
function make_airing_list(data, page) { function make_airing_list(data, page) {
console.log("call make_airing_list()")
let str = '' let str = ''
let tmp = '' let tmp = ''
//console.log(data)
str += '<div>'; str += '<div>';
str += '<button type="button" class="btn btn-info">Page <span class="badge bg-warning">' + page + '</span></button>'; str += '<button type="button" class="btn btn-info">Page <span class="badge bg-warning">' + page + '</span></button>';
str += '</div>'; str += '</div>';
// str += '<div class="card-columns">' // str += '<div class="card-columns">'
str += '<div id="inner_screen_movie" class="row infinite-scroll">'; str += '<div id="inner_screen_movie" class="row infinite-scroll">';
for (let i in data.anime_list) { for (let i in data.episode) {
tmp = '<div class="col-6 col-sm-4 col-md-3">'; tmp = '<div class="col-6 col-sm-4 col-md-3">';
tmp += '<div class="card">'; tmp += '<div class="card">';
// tmp += '<img class="lozad" data-src="' + data.anime_list[i].image_link + '" />'; // tmp += '<img class="lozad" data-src="' + data.episode[i].image_link + '" />';
tmp += '<img class="lazyload" src="../static/img_loader_x200.svg" data-original="' + data.anime_list[i].image_link + '" style="cursor: pointer" onclick="location.href=\'./request?code=' + data.anime_list[i].code + '\'"/>'; tmp += '<img class="lazyload" src="../static/img_loader_x200.svg" data-original="' + data.episode[i].image_link + '" style="cursor: pointer" onclick="location.href=\'./request?code=' + data.episode[i].code + '\'"/>';
tmp += '<div class="card-body">' tmp += '<div class="card-body">'
// {#tmp += '<button id="code_button" data-code="' + data.episode[i].code + '" type="button" class="btn btn-primary code-button bootstrap-tooltip" data-toggle="button" data-tooltip="true" aria-pressed="true" autocomplete="off" data-placement="top">' +#} // {#tmp += '<button id="code_button" data-code="' + data.episode[i].code + '" type="button" class="btn btn-primary code-button bootstrap-tooltip" data-toggle="button" data-tooltip="true" aria-pressed="true" autocomplete="off" data-placement="top">' +#}
// {# '<span data-tooltip-text="'+data.episode[i].title+'">' + data.episode[i].code + '</span></button></div>';#} // {# '<span data-tooltip-text="'+data.episode[i].title+'">' + data.episode[i].code + '</span></button></div>';#}
tmp += '<h5 class="card-title">' + data.anime_list[i].title + '</h5>'; tmp += '<h5 class="card-title">' + data.episode[i].title + '</h5>';
tmp += '<p class="card-text">' + data.anime_list[i].code + '<button id="add_whitelist" name="add_whitelist" class="btn btn-sm btn-favorite mb-1" data-code="' + tmp += '<p class="card-text">' + data.episode[i].code + '<button id="add_whitelist" name="add_whitelist" class="btn btn-sm btn-favorite mb-1" data-code="' +
data.anime_list[i].code + data.episode[i].code +
'"><i class="bi bi-heart-fill"></i></button></p>'; '"><i class="bi bi-heart-fill"></i></button></p>';
tmp += '<a href="./request?code=' + data.anime_list[i].code + '" class="btn btn-primary cut-text">' + data.anime_list[i].title + '</a>'; tmp += '<a href="./request?code=' + data.episode[i].code + '" class="btn btn-primary cut-text">' + data.episode[i].title + '</a>';
// tmp += // tmp +=
// '<button id="add_whitelist" name="add_whitelist" class="btn btn-sm btn-favorite mb-1" data-code="' + // '<button id="add_whitelist" name="add_whitelist" class="btn btn-sm btn-favorite mb-1" data-code="' +
// data.anime_list[i].code + // data.anime_list[i].code +
@@ -406,7 +416,7 @@
let data_code = $(this).attr("data-code"); let data_code = $(this).attr("data-code");
console.log(data_code); console.log(data_code);
$.ajax({ $.ajax({
url: "/" + package_name + "/ajax/"+sub+"/add_whitelist", url: "/" + package_name + "/ajax/" + sub + "/add_whitelist",
type: "POST", type: "POST",
cache: false, cache: false,
data: JSON.stringify({data_code: data_code}), data: JSON.stringify({data_code: data_code}),
@@ -642,6 +652,14 @@
opacity: 1; opacity: 1;
} }
.badge-on-image {
position: absolute;
top: 2px;
/*bottom: 2px; !* position where you want it *!*/
right: 2px;
padding: 5px 12px;
}
#airing_list { #airing_list {
display: none; display: none;
} }
@@ -672,6 +690,7 @@
button.btn-favorite { button.btn-favorite {
background-color: #e0ff42; background-color: #e0ff42;
} }
/*.card-columns {*/ /*.card-columns {*/
/* @include media-breakpoint-only(lg) {*/ /* @include media-breakpoint-only(lg) {*/
/* column-count: 4;*/ /* column-count: 4;*/
@@ -684,10 +703,12 @@
.container { .container {
max-width: 100%; max-width: 100%;
} }
.card-columns { .card-columns {
column-count: 2; column-count: 2;
column-gap: 1.25rem; column-gap: 1.25rem;
} }
.card-columns .card { .card-columns .card {
display: inline-block; display: inline-block;
} }
@@ -695,12 +716,16 @@
@media (min-width: 768px) { @media (min-width: 768px) {
.card-columns {column-count: 3;} .card-columns {
column-count: 3;
}
} }
/* Large devices (desktops, 992px and up) */ /* Large devices (desktops, 992px and up) */
@media (min-width: 992px) { @media (min-width: 992px) {
.card-columns {column-count: 3;} .card-columns {
column-count: 3;
}
} }
/* Extra large devices (large desktops, 1200px and up) */ /* Extra large devices (large desktops, 1200px and up) */
@@ -709,22 +734,28 @@
column-count: 5; column-count: 5;
} }
} }
.card { .card {
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
} }
.card-columns .card { .card-columns .card {
margin-bottom: 0.75rem; margin-bottom: 0.75rem;
} }
.card-columns .card img{
.card-columns .card img {
width: 100%; width: 100%;
} }
button#add_whitelist { button#add_whitelist {
/*top: -70px;*/ /*top: -70px;*/
position: relative; position: relative;
} }
body { body {
font-family: NanumSquareNeo,system-ui,-apple-system,Segoe UI,Roboto,Helvetica Neue,Noto Sans,Liberation Sans,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji; font-family: NanumSquareNeo, system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Noto Sans, Liberation Sans, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
} }
body { body {
background-image: linear-gradient(90deg, #233f48, #6c6fa2, #768dae); background-image: linear-gradient(90deg, #233f48, #6c6fa2, #768dae);
} }

View File

@@ -0,0 +1,144 @@
{% extends "base.html" %}
{% block content %}
<div>
<form id="form_search" class="form-inline" style="text-align:left">
<div class="container-fluid">
<div class="row show-grid">
<span class="col-md-4">
<select id="order" name="order" class="form-control form-control-sm">
<option value="desc">최근순</option>
<option value="asc">오래된순</option>
</select>
<select id="option" name="option" class="form-control form-control-sm">
<option value="all">전체</option>
<option value="completed">완료</option>
</select>
</span>
<span class="col-md-8">
<input id="search_word" name="search_word" class="form-control form-control-sm w-75" type="text" placeholder="" aria-label="Search">
<button id="search" class="btn btn-sm btn-outline-success">검색</button>
<button id="reset_btn" class="btn btn-sm btn-outline-success">리셋</button>
</span>
</div>
</div>
</form>
<div id='page1'></div>
{{ macros.m_hr_head_top() }}
{{ macros.m_row_start('0') }}
{{ macros.m_col(2, macros.m_strong('Poster')) }}
{{ macros.m_col(10, macros.m_strong('Info')) }}
{{ macros.m_row_end() }}
{{ macros.m_hr_head_bottom() }}
<div id="list_div"></div>
<div id='page2'></div>
</div>
<script type="text/javascript">
var package_name = "{{arg['package_name']}}";
var sub = "{{arg['sub']}}";
var current_data = null;
$(document).ready(function(){
global_sub_request_search('1');
});
$("#search").click(function(e) {
e.preventDefault();
global_sub_request_search('1');
});
$("body").on('click', '#page', function(e){
e.preventDefault();
global_sub_request_search($(this).data('page'));
});
$("#reset_btn").click(function(e) {
e.preventDefault();
document.getElementById("order").value = 'desc';
document.getElementById("option").value = 'all';
document.getElementById("search_word").value = '';
global_sub_request_search('1')
});
$("body").on('click', '#json_btn', function(e){
e.preventDefault();
var id = $(this).data('id');
for (i in current_data.list) {
if (current_data.list[i].id == id) {
m_modal(current_data.list[i])
}
}
});
$("body").on('click', '#self_search_btn', function(e){
e.preventDefault();
var search_word = $(this).data('title');
document.getElementById("search_word").value = search_word;
global_sub_request_search('1')
});
$("body").on('click', '#remove_btn', function(e) {
e.preventDefault();
id = $(this).data('id');
$.ajax({
url: '/'+package_name+'/ajax/'+sub+ '/db_remove',
type: "POST",
cache: false,
data: {id:id},
dataType: "json",
success: function (data) {
if (data) {
$.notify('<strong>삭제되었습니다.</strong>', {
type: 'success'
});
global_sub_request_search(current_data.paging.current_page, false)
} else {
$.notify('<strong>삭제 실패</strong>', {
type: 'warning'
});
}
}
});
});
$("body").on('click', '#request_btn', function(e){
e.preventDefault();
var content_code = $(this).data('content_code');
$(location).attr('href', '/' + package_name + '/' + sub + '/request?content_code=' + content_code)
});
function make_list(data) {
//console.log(data)
str = '';
for (i in data) {
//console.log(data[i])
str += m_row_start();
str += m_col(1, data[i].id);
tmp = (data[i].status == 'completed') ? '완료' : '미완료';
str += m_col(1, tmp);
tmp = data[i].created_time + '(추가)';
if (data[i].completed_time != null)
tmp += data[i].completed_time + '(완료)';
str += m_col(3, tmp)
tmp = data[i].savepath + '<br>' + data[i].filename + '<br><br>';
tmp2 = m_button('json_btn', 'JSON', [{'key':'id', 'value':data[i].id}]);
tmp2 += m_button('request_btn', '작품 검색', [{'key':'content_code', 'value':data[i].content_code}]);
tmp2 += m_button('self_search_btn', '목록 검색', [{'key':'title', 'value':data[i].title}]);
tmp2 += m_button('remove_btn', '삭제', [{'key':'id', 'value':data[i].id}]);
tmp += m_button_group(tmp2)
str += m_col(7, tmp)
str += m_row_end();
if (i != data.length -1) str += m_hr();
}
document.getElementById("list_div").innerHTML = str;
}
</script>
{% endblock %}

View File

@@ -0,0 +1,131 @@
{% extends "base.html" %}
{% block content %}
<div>
{{ macros.m_button_group([['reset_btn', '초기화'], ['delete_completed_btn', '완료 목록 삭제'], ['go_ffmpeg_btn', 'Go FFMPEG']])}}
{{ macros.m_row_start('0') }}
{{ macros.m_row_end() }}
{{ macros.m_hr_head_top() }}
{{ macros.m_row_start('0') }}
{{ macros.m_col(1, macros.m_strong('Idx')) }}
{{ macros.m_col(2, macros.m_strong('CreatedTime')) }}
{{ macros.m_col(4, macros.m_strong('Filename')) }}
{{ macros.m_col(3, macros.m_strong('Status')) }}
{{ macros.m_col(2, macros.m_strong('Action')) }}
{{ macros.m_row_end() }}
{{ macros.m_hr_head_bottom() }}
<div id="download_list_div"></div>
</div> <!--전체-->
<script type="text/javascript">
var package_name = "{{arg['package_name'] }}";
var sub = "{{arg['sub'] }}";
var current_data = null;
socket = io.connect(window.location.protocol + "//" + document.domain + ":" + location.port + "/" + package_name + '/' + sub);
$(document).ready(function(){
});
socket.on('start', function(data){
on_start();
});
socket.on('list_refresh', function(data){
on_start()
});
socket.on('status', function(data){
console.log(data);
on_status(data)
});
function on_start() {
$.ajax({
url: '/' + package_name + '/ajax/' + sub + '/entity_list',
type: "POST",
cache: false,
data: {},
dataType: "json",
success: function (data) {
make_download_list(data)
}
});
}
function on_status(data) {
//console.log(data)
tmp = document.getElementById("progress_"+data.entity_id)
if (tmp != null) {
document.getElementById("progress_"+data.entity_id).style.width = data.ffmpeg_percent+ '%';
document.getElementById("progress_"+data.entity_id+"_label").innerHTML = data.ffmpeg_status_kor + "(" + data.ffmpeg_percent + "%)" + ' ' + ((data.ffmpeg_arg != null)?data.ffmpeg_arg.data.current_speed:'')
}
}
function make_download_list(data) {
str = '';
for (i in data) {
str += m_row_start();
str += m_col(1, data[i].entity_id);
str += m_col(2, data[i].created_time);
str += m_col(4, (data[i].filename != null) ? data[i].filename : '');
label = data[i].ffmpeg_status_kor
if (data[i].ffmpeg_percent != 0) {
label += '(' + data[i].ffmpeg_percent + '%)'
}
tmp = m_progress('progress_'+data[i].entity_id, data[i].ffmpeg_percent, label)
str += m_col(3, tmp);
tmp = m_button('program_cancel_btn', '취소', [{'key':'id', 'value':data[i].entity_id}]);
tmp = m_button_group(tmp)
str += m_col(2, tmp)
str += m_row_end();
if (i != data.length -1) str += m_hr(0);
}
document.getElementById("download_list_div").innerHTML = str;
}
$("body").on('click', '#program_cancel_btn', function(e){
e.preventDefault();
entity_id = $(this).data('id')
send_data = {'command':'cancel', 'entity_id':entity_id}
queue_command(send_data)
});
$("body").on('click', '#reset_btn', function(e){
e.preventDefault();
entity_id = $(this).data('id')
send_data = {'command':'reset', 'entity_id':-1}
queue_command(send_data)
});
$("body").on('click', '#delete_completed_btn', function(e){
e.preventDefault();
entity_id = $(this).data('id')
send_data = {'command':'delete_completed', 'entity_id':-1}
queue_command(send_data)
});
function queue_command(data) {
$.ajax({
url: '/' + package_name + '/ajax/' + sub + '/queue_command',
type: "POST",
cache: false,
data: data,
dataType: "json",
success: function (ret) {
if (ret.ret == 'notify') {
$.notify('<strong>'+ ret.log +'</strong>', {type: 'warning'});
}
on_start();
}
});
}
$("body").on('click', '#go_ffmpeg_btn', function(e){
e.preventDefault();
$(location).attr('href', '/ffmpeg')
});
</script>
{% endblock %}

View File

@@ -0,0 +1,639 @@
{% extends "base.html" %} {% block content %}
<div id="anime_downloader_wrapper">
<div id="preloader">
<div class='demo'>
<!-- <div class="loader-inner">-->
<div class='circle'>
<div class='inner'></div>
</div>
<div class='circle'>
<div class='inner'></div>
</div>
<div class='circle'>
<div class='inner'></div>
</div>
<div class='circle'>
<div class='inner'></div>
</div>
<div class='circle'>
<div class='inner'></div>
</div>
<!-- </div>-->
</div>
</div>
<div>
<form id="program_list">
{{ macros.setting_input_text_and_buttons('code', '작품 Code',
[['analysis_btn', '분석'], ['go_ohli24_btn', 'Go OHLI24']], desc='예)
"https://ohli24.net/c/녹을 먹는 비스코" 이나 "녹을 먹는 비스코"') }}
</form>
<form id="program_auto_form">
<div id="episode_list"></div>
</form>
</div>
</div>
<!--전체-->
<link
href="{{ url_for('.static', filename='css/%s.css' % arg['sub'])
}}"
type="text/css"
rel="stylesheet"
/>
<script src="{{ url_for('.static', filename='js/sjva_ui14.js') }}"></script>
<script type="text/javascript">
const package_name = "{{arg['package_name'] }}";
const sub = "{{arg['sub'] }}";
const ohli24_url = "{{arg['ohli24_url']}}";
const params = new Proxy(new URLSearchParams(window.location.search), {
get: (searchParams, prop) => searchParams.get(prop),
})
const loader = document.getElementById("preloader");
const dismissLoadingScreen = function () {
loader.style.display = "none";
$('.demo').css("display", "none")
};
const wait3seconds = function () {
// REFERENCE: https://www.w3schools.com/jsref/met_win_settimeout.asp
const result = setTimeout(dismissLoadingScreen, 2000);
};
window.addEventListener("load", wait3seconds);
function findGetParameter(parameterName) {
let result = null,
tmp = [];
const items = location.search.substr(1).split("&");
for (let index = 0; index < items.length; index++) {
tmp = items[index].split("=");
if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]);
}
return result;
}
function analyze(wr_id, bo_table) {
// e.preventDefault();
const code = document.getElementById("code").value
console.log(code)
$.ajax({
url: '/' + package_name + '/ajax/' + sub + '/analysis',
type: "POST",
cache: false,
data: {code: code, wr_id: wr_id, bo_table: bo_table},
dataType: "json",
success: function (ret) {
if (ret.ret === 'success' && ret.data != null) {
// {#console.log(ret.code)#}
console.log(ret.data)
make_program(ret.data)
} else {
$.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'});
}
}
});
}
function make_program(data) {
current_data = data;
// $("body").css({"background": "url(" + data.poster_url + ")"})
// console.log('current_data:: ', data)
str = "";
tmp = '<div class="form-inline w-100">';
tmp += m_button("check_download_btn", "선택 다운로드 추가", []);
tmp += m_button("all_check_on_btn", "전체 선택", []);
tmp += m_button("all_check_off_btn", "전체 해제", []);
tmp += m_button("down_subtitle_btn", "자막만 전체 받기", [])
tmp +=
'&nbsp;&nbsp;&nbsp;<input id="new_title" name="new_title" class="form-control form-control-sm" value="' +
data.title +
'">';
tmp += "</div>";
tmp += '<div class="form-inline">';
tmp += m_button("apply_new_title_btn", "저장폴더명 변경", []);
tmp +=
'&nbsp;&nbsp;&nbsp;<input id="new_season" name="new_season" class="form-control form-control-sm" value="' +
data.season +
'">';
tmp += m_button("apply_new_season_btn", "시즌 변경 (숫자만 가능)", []);
tmp += m_button("search_tvdb_btn", "TVDB", []);
tmp += m_button("add_whitelist", "스케쥴링 추가", []);
tmp += "</div>";
tmp = m_button_group(tmp);
str += tmp;
// program
// str += m_hr_black();
str += "<div class='card p-lg-5 mt-md-3 p-md-3 border-light'>"
str += m_row_start(0);
tmp = "";
if (data.poster_url != null)
tmp = '<img src="' + data.poster_url + '" class="img-fluid">';
str += m_col(3, tmp);
tmp = "";
tmp += m_row_start(0);
tmp += m_col(3, "제목", "right");
tmp += m_col(9, data.title);
tmp += m_row_end();
tmp += m_row_start(0);
tmp += m_col(3, "시즌", "right");
tmp += m_col(9, data.season);
tmp += m_row_end();
for (i in data.detail) {
tmp += m_row_start(0);
key = Object.keys(data.detail[i])[0];
value = data.detail[i][key];
tmp += m_col(3, key, "right");
tmp += m_col(9, value);
tmp += m_row_end();
}
str += m_col(9, tmp);
str += m_row_end();
// str += m_hr_black();
str += "</div>"
for (i in data.episode) {
str += m_row_start();
// tmp = '<img src="' + data.episode[i].image + '" class="img-fluid">'
// str += m_col(3, tmp)
tmp = "<strong>" + data.episode[i].title + "</strong><span>화. </span>";
tmp += data.episode[i].filename + "<br><p></p>";
tmp += '<div class="form-inline">';
tmp +=
'<input id="checkbox_' +
data.episode[i].code +
'" name="checkbox_' +
data.episode[i].code +
'" type="checkbox" checked data-toggle="toggle" data-on="선 택" data-off="-" data-onstyle="success" data-offstyle="danger" data-size="small">&nbsp;&nbsp;&nbsp;&nbsp;';
// tmp += m_button('add_queue_btn', '다운로드 추가', [{'key': 'code', 'value': data.episode[i].code}])
tmp += m_button("add_queue_btn", "다운로드 추가", [
{key: "idx", value: i},
]);
tmp += j_button('insert_download_btn', '다운로드 추가', {
code: data.episode[i]._id,
});
tmp += j_button(
'force_insert_download_btn',
'다운로드 추가 (DB무시)',
{code: data.episode[i]._id}
);
// tmp += '<button id="play_video" name="play_video" class="btn btn-sm btn-outline-primary" data-idx="'+i+'">바로보기</button>';
tmp += "</div>";
str += m_col(12, tmp);
str += m_row_end();
if (i != data.length - 1) str += m_hr(0);
}
document.getElementById("episode_list").innerHTML = str;
$('input[id^="checkbox_"]').bootstrapToggle();
}
$(function () {
console.log(params.wr_id)
console.log(findGetParameter('wr_id'))
console.log(params.code)
if (params.code === '') {
} else {
document.getElementById("code").value = params.code
// {#document.getElementById("analysis_btn").click();#}
}
if ("{{arg['ohli24_current_code']}}" !== "") {
if (params.code === null) {
console.log('params.code === null')
document.getElementById("code").value = "{{arg['ohli24_current_code']}}";
} else if (params.code === '') {
document.getElementById("code").value = "{{arg['ohli24_current_code']}}";
} else {
console.log('params code exist')
console.log(params.code)
document.getElementById("code").value = params.code
analyze(params.wr_id, params.bo_table)
// document.getElementById("analysis_btn").click();
// $('#analysis_btn').trigger('click')
}
// 값이 공백이 아니면 분석 버튼 계속 누름
// {#document.getElementById("analysis_btn").click();#}
} else {
}
})
$(document).ready(function () {
console.log('wr_id::', params.wr_id)
});
$("#analysis_btn").unbind("click").bind('click', function (e) {
e.preventDefault();
e.stopPropagation()
const code = document.getElementById("code").value
console.log(code)
$.ajax({
url: '/' + package_name + '/ajax/' + sub + '/analysis',
type: "POST",
cache: false,
data: {code: code},
dataType: "json",
success: function (ret) {
if (ret.ret === 'success' && ret.data != null) {
// {#console.log(ret.code)#}
console.log(ret.data)
make_program(ret.data)
} else {
$.notify('<strong>분석 실패</strong><br>' + ret.log, {type: 'warning'});
}
}
});
});
$("body").on('click', '#go_ohli24_btn', function (e) {
e.preventDefault();
window.open("{{arg['ohli24_url']}}", "_blank");
});
$("body").on('click', '#all_check_on_btn', function (e) {
e.preventDefault();
$('input[id^="checkbox_"]').bootstrapToggle('on')
});
$("body").on('click', '#all_check_off_btn', function (e) {
e.preventDefault();
$('input[id^="checkbox_"]').bootstrapToggle('off')
});
$("body").on('click', '#add_queue_btn', function (e) {
e.preventDefault();
data = current_data.episode[$(this).data('idx')];
console.log('data:::>', data)
$.ajax({
url: '/' + package_name + '/ajax/' + sub + '/add_queue',
type: "POST",
cache: false,
data: {data: JSON.stringify(data)},
dataType: "json",
success: function (data) {
console.log('#add_queue_btn::data >>', data)
if (data.ret == 'enqueue_db_append' || data.ret == 'enqueue_db_exist') {
$.notify('<strong>다운로드 작업을 추가 하였습니다.</strong>', {type: 'success'});
} else if (data.ret == 'queue_exist') {
$.notify('<strong>이미 큐에 있습니다. 삭제 후 추가하세요.</strong>', {type: 'warning'});
} else if (data.ret == 'db_completed') {
$.notify('<strong>DB에 완료 기록이 있습니다.</strong>', {type: 'warning'});
} else {
$.notify('<strong>추가 실패</strong><br>' + ret.log, {type: 'warning'});
}
}
});
});
$("body").on('click', '#check_download_btn', function (e) {
e.preventDefault();
all = $('input[id^="checkbox_"]');
let data = [];
let idx;
for (let i in all) {
if (all[i].checked) {
idx = parseInt(all[i].id.split('_')[1])
data.push(current_data.episode[idx]);
}
}
if (data.length == 0) {
$.notify('<strong>선택하세요.</strong>', {type: 'warning'});
return;
}
$.ajax({
url: '/' + package_name + '/ajax/' + sub + '/add_queue_checked_list',
type: "POST",
cache: false,
data: {data: JSON.stringify(data)},
dataType: "json",
success: function (data) {
$.notify('<strong>백그라운드로 작업을 추가합니다.</strong>', {type: 'success'});
}
});
});
</script>
<style>
#anime_downloader_wrapper {
font-family: NanumSquareNeo, system-ui, -apple-system, Segoe UI, Roboto, Helvetica Neue, Noto Sans, Liberation Sans, Arial, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji;
}
body {
background-image: linear-gradient(90deg, #33242c, #263341, #17273a);
}
#anime_downloader_wrapper {
color: #d6eaf8;
}
button.code-button {
min-width: 82px !important;
}
.tooltip {
position: relative;
display: block;
}
[data-tooltip-text]:hover {
position: relative;
}
[data-tooltip-text]:after {
-webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
-moz-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
background-color: rgba(0, 0, 0, 0.8);
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
color: #ffffff;
font-size: 12px;
margin-bottom: 10px;
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
z-index: 9999;
opacity: 0;
left: -9999px;
top: 90%;
content: attr(data-tooltip-text);
}
[data-tooltip-text]:hover:after {
top: 230%;
left: 0;
opacity: 1;
}
[data-tooltip-text]:hover {
position: relative;
}
[data-tooltip-text]:after {
-webkit-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
-moz-transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
transition: bottom 0.3s ease-in-out, opacity 0.3s ease-in-out;
background-color: rgba(0, 0, 0, 0.8);
-webkit-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-moz-box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
box-shadow: 0px 0px 3px 1px rgba(50, 50, 50, 0.4);
-webkit-border-radius: 5px;
-moz-border-radius: 5px;
border-radius: 5px;
color: #ffffff;
font-size: 12px;
margin-bottom: 10px;
padding: 7px 12px;
position: absolute;
width: auto;
min-width: 50px;
max-width: 300px;
word-wrap: break-word;
z-index: 9999;
opacity: 0;
left: -9999px;
top: -210% !important;
content: attr(data-tooltip-text);
}
[data-tooltip-text]:hover:after {
top: 130%;
left: 0;
opacity: 1;
}
.card {
border: none;
box-shadow: inset 1px 1px hsl(0deg 0% 100% / 20%), inset -1px -1px hsl(0deg 0% 100% / 10%), 1px 3px 24px -1px rgb(0 0 0 / 15%);
background-color: transparent;
background-image: linear-gradient(125deg, hsla(0, 0%, 100%, .3), hsla(0, 0%, 100%, .2) 70%);
backdrop-filter: blur(5px);
}
.card.border-light {
border-radius: 30px 10px;
--bs-border-opacity: 1;
border-color: rgba(var(--bs-light-rgb), var(--bs-border-opacity)) !important;
}
#airing_list {
display: none;
}
.cut-text {
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
width: 100%;
}
#screen_movie_list {
margin-top: 10px;
}
/*@import url(https://fonts.googleapis.com/css?family=Lato);*/
/*a {*/
/* position: fixed;*/
/* bottom: 2%;*/
/* display: block;*/
/* text-align: center;*/
/* color: #0fa;*/
/* font-family: "Lato", sans-serif;*/
/* text-decoration: none !important;*/
/* width: 100%;*/
/*}*/
/*body, html {*/
/* width: 100%;*/
/* height: 100%;*/
/* overflow: hidden;*/
/*}*/
/*body {*/
/* background: linear-gradient(90deg, #00b377, #00d68f);*/
/* box-shadow: inset 0px 0px 90px rgba(0, 0, 0, 0.5);*/
/* margin: 0px;*/
/* padding: 0px;*/
/*}*/
.demo {
width: 100px;
height: 102px;
border-radius: 100%;
position: absolute;
top: 45%;
left: calc(50% - 50px);
}
.circle {
width: 100%;
height: 100%;
position: absolute;
}
.circle .inner {
width: 100%;
height: 100%;
border-radius: 100%;
border: 5px solid rgba(0, 255, 170, 0.7);
border-right: none;
border-top: none;
backgroudn-clip: padding;
box-shadow: inset 0px 0px 10px rgba(0, 255, 170, 0.15);
}
@-webkit-keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@keyframes spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
.circle:nth-of-type(0) {
transform: rotate(0deg);
}
.circle:nth-of-type(0) .inner {
-webkit-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
.circle:nth-of-type(1) {
transform: rotate(70deg);
}
.circle:nth-of-type(1) .inner {
-webkit-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
.circle:nth-of-type(2) {
transform: rotate(140deg);
}
.circle:nth-of-type(2) .inner {
-webkit-animation: spin 2s infinite linear;
animation: spin 2s infinite linear;
}
.demo {
-webkit-animation: spin 5s infinite linear;
animation: spin 5s infinite linear;
background: rgba(0, 0, 0, 0.2);
background: radial-gradient(#222, #000);
bottom: 0;
left: 0;
overflow: hidden;
/*position: fixed;*/
right: 0;
/*top: 0;*/
z-index: 99999;
opacity: 0.5;
margin: 0 auto;
transform: translate(-50%, -50%);
position: absolute;
top: 50%;
}
.circle {
width: 100%;
height: 100%;
position: absolute;
}
.circle .inner {
width: 100%;
height: 100%;
border-radius: 100%;
border: 5px solid rgba(0, 255, 170, 0.7);
border-right: none;
border-top: none;
backgroudn-clip: padding;
box-shadow: inset 0px 0px 10px rgba(0, 255, 170, 0.15);
}
.loader-inner {
bottom: 0;
height: 60px;
left: 0;
margin: auto;
position: absolute;
right: 0;
top: 0;
width: 100px;
}
#preloader {
/*background-color: green;*/
/*color: white;*/
/*height: 100vh;*/
/*width: 100%;*/
/*position: fixed;*/
/*z-index: 100;*/
background: rgba(0, 0, 0, 0.2);
background: radial-gradient(#222, #000);
bottom: 0;
left: 0;
overflow: hidden;
position: fixed;
right: 0;
top: 0;
z-index: 99999;
opacity: 0.5;
}
</style>
{% endblock %}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,68 @@
{% extends "base.html" %}
{% block content %}
<div>
{{ macros.m_button_group([['global_setting_save_btn', '설정 저장']])}}
{{ macros.m_row_start('5') }}
{{ macros.m_row_end() }}
<nav>
{{ macros.m_tab_head_start() }}
{{ macros.m_tab_head2('normal', '일반', true) }}
{{ macros.m_tab_head2('auto', '홈화면 자동', false) }}
{{ macros.m_tab_head2('action', '기타', false) }}
{{ macros.m_tab_head_end() }}
</nav>
<form id="setting">
<div class="tab-content" id="nav-tabContent">
{{ macros.m_tab_content_start('normal', true) }}
{{ macros.setting_input_text_and_buttons('linkkf_url', 'linkkf URL', [['go_btn', 'GO']], value=arg['linkkf_url']) }}
{{ macros.setting_input_text('linkkf_download_path', '저장 폴더', value=arg['linkkf_download_path'], desc='정상적으로 다운 완료 된 파일이 이동할 폴더 입니다. ') }}
{{ macros.setting_input_int('linkkf_max_ffmpeg_process_count', '동시 다운로드 수', value=arg['linkkf_max_ffmpeg_process_count'], desc='동시에 다운로드 할 에피소드 갯수입니다.') }}
{{ macros.setting_checkbox('linkkf_order_desc', '요청 화면 최신순 정렬', value=arg['linkkf_order_desc'], desc='On : 최신화부터, Off : 1화부터') }}
{{ macros.setting_checkbox('linkkf_auto_make_folder', '제목 폴더 생성', value=arg['linkkf_auto_make_folder'], desc='제목으로 폴더를 생성하고 폴더 안에 다운로드합니다.') }}
<div id="linkkf_auto_make_folder_div" class="collapse">
{{ macros.setting_input_text('linkkf_finished_insert', '완결 표시', col='3', value=arg['linkkf_finished_insert'], desc=['완결된 컨텐츠 폴더명 앞에 넣을 문구입니다.']) }}
{{ macros.setting_checkbox('linkkf_auto_make_season_folder', '시즌 폴더 생성', value=arg['linkkf_auto_make_season_folder'], desc=['On : Season 번호 폴더를 만듭니다.']) }}
</div>
{{ macros.setting_checkbox('linkkf_uncompleted_auto_enqueue', '자동으로 다시 받기', value=arg['linkkf_uncompleted_auto_enqueue'], desc=['On : 플러그인 로딩시 미완료인 항목은 자동으로 다시 받습니다.']) }}
{{ macros.m_tab_content_end() }}
{{ macros.m_tab_content_start('auto', false) }}
{{ macros.setting_global_scheduler_sub_button(arg['scheduler'], arg['is_running']) }}
{{ macros.setting_input_text('linkkf_interval', '스케쥴링 실행 정보', value=arg['linkkf_interval'], col='3', desc=['Inverval(minute 단위)이나 Cron 설정']) }}
{{ macros.setting_checkbox('linkkf_auto_start', '시작시 자동실행', value=arg['linkkf_auto_start'], desc='On : 시작시 자동으로 스케쥴러에 등록됩니다.') }}
{{ macros.setting_input_textarea('linkkf_auto_code_list', '자동 다운로드할 작품 코드', desc=['all 입력시 모두 받기', '구분자 | 또는 엔터'], value=arg['linkkf_auto_code_list'], row='10') }}
{{ macros.setting_checkbox('linkkf_auto_mode_all', '에피소드 모두 받기', value=arg['linkkf_auto_mode_all'], desc=['On : 이전 에피소드를 모두 받습니다.', 'Off : 최신 에피소드만 받습니다.']) }}
{{ macros.m_tab_content_end() }}
{{ macros.m_tab_content_start('action', false) }}
{{ macros.setting_button([['global_one_execute_sub_btn', '1회 실행']], left='1회 실행' ) }}
{{ macros.setting_button([['global_reset_db_sub_btn', 'DB 초기화']], left='DB정리' ) }}
{{ macros.m_tab_content_end() }}
</div><!--tab-content-->
</form>
</div> <!--전체-->
<script type="text/javascript">
var package_name = "{{arg['package_name'] }}";
var sub = "{{arg['sub'] }}";
var current_data = null;
$(document).ready(function(){
use_collapse('linkkf_auto_make_folder');
});
$('#ani365_auto_make_folder').change(function() {
use_collapse('linkkf_auto_make_folder');
});
$("body").on('click', '#go_btn', function(e){
e.preventDefault();
let url = document.getElementById("linkkf_url").value
window.open(url, "_blank");
});
</script>
{% endblock %}

File diff suppressed because it is too large Load Diff

605
test.ipynb Normal file

File diff suppressed because one or more lines are too long

94
test.py Normal file
View File

@@ -0,0 +1,94 @@
from playwright.sync_api import sync_playwright
from playwright.async_api import async_playwright
# from playwright_stealth import stealth_sync
import asyncio
import html_to_json
async def run(playwright):
headers = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/104.0.0.0 Safari/537.36",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"Accept-Language": "ko-KR,ko;q=0.9,en-US;q=0.8,en;q=0.7",
"Referer": "https://anilife.live/",
# "Cookie": "SPSI=ef307b8c976fac3363cdf420c9ca40a9; SPSE=+PhK0/uGUBMCZIgXplNjzqW3K2kXLybiElDTtOOiboHiBXO7Tp/9roMW7FplGZuGCUo3i4Fwx5VIUG57Zj6VVw==; anilife_csrf=b1eb92529839d7486169cd91e4e60cd2; UTGv2=h45f897818578a5664b31004b95a9992d273; _ga=GA1.1.281412913.1662803695; _ga_56VYJJ7FTM=GS1.1.1662803695.1.0.1662803707.0.0.0; DCST=pE9; DSR=w2XdPUpwLWDqkLpWXfs/5TiO4mtNv5O3hqNhEr7GP1kFoRBBzbFRpR+xsJd9A+E29M+we7qIvJxQmHQTjDNLuQ==; DCSS=696763EB4EA5A67C4E39CFA510FE36F19B0912C; DGCC=RgP; spcsrf=8a6b943005d711258f2f145a8404d873; sp_lit=F9PWLXyxvZbOyk3eVmtTlg==; PRLST=wW; adOtr=70fbCc39867"
# "Cookie": ""
# "Cookie": "_ga=GA1.1.578607927.1660813724; __gads=ID=10abb8b98b6828ae-2281c943a9d500fd:T=1660813741:RT=1660813741:S=ALNI_MYU_iB2lBgSrEQUBwhKpNsToaqQ8A; SL_G_WPT_TO=ko; SL_GWPT_Show_Hide_tmp=1; SL_wptGlobTipTmp=1; SPSI=944c237cdd8606d80e5e330a0f332d03; SPSE=itZcXMDuso0ktWnDkV2G0HVwWEctCgDjrcFMlEQ5C745wqvp1pEEddrsAsjPUBjl6/8+9Njpq1IG3wt/tVag7w==; sbtsck=jav9aILa6Ofn0dEQr5DhDq5rpbd1JUoNgKwxBpZrqYd+CM=; anilife_csrf=54ee9d15c87864ee5e2538a63d894ad6; UTGv2=h46b326af644f4ac5d0eb1502881136b3750; DCST=pE9; __gpi=UID=000008ba227e99e0:T=1660813741:RT=1661170429:S=ALNI_MaJHIVJIGpQ5nTE9lvypKQxJnn10A; DSR=GWyTLTvSMF/lQD77ojQkGyl+7JvTudkSwV1GKeNVUcWEBa/msln9zzsBj7lj+89ywSRBM34Ol73AKf+KHZ9bZA==; DCSS=9D44115EC4CE12CADB88A005DC65A3CD74A211E; DGCC=zdV; spcsrf=fba136251afc6b5283109fc920322c70; sp_lit=kw0Xkp66eQ7bV0f0tNClhg==; PRLST=gt; adOtr=2C4H9c4d78d; _ga_56VYJJ7FTM=GS1.1.1661168661.18.1.1661173389.0.0.0",
}
useragent = {
"User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, "
"like Gecko) Chrome/96.0.4664.110 Whale/3.12.129.46 Safari/537.36"
}
browser = await playwright.webkit.launch(headless=False)
# context = browser.new_context(
# user_agent=ua,
# )
# url = "https://anilife.live/h/live?p=7ccd9e49-9f59-4976-b5d8-25725d6a6188&a=none&player=jawcloud"
url = "https://api-svr-01.anilife.live/m3u8/st/MDk5NzUyNjY3NTkwZTc3ZmYwMGRmNGIyMzk3MGZiNzU1YjBkNjk2YTFiMzJiZTVhZWZjYjg3NGY4YmE3NTkyMDRkNTU1Y2RjMDhkZTkwNWZiMzZiMTI3ZjE5Zjk0YzQ3MjgzYmUxMTIzZTM2OTllMWZlMzZjM2I1OTIxMmNkNmZmODUxOWZhY2JiMzUxYmE4ZjVjOTMyNzFiYzA0YWI1OTNjZWU0NzMwOTJmYTA4NGU1ZDM1YTlkODA5NzljOTMxNTVhYjlmMmQwMWIwOGMyMTg1N2UyOWJjYjZjN2UwNzJkNjBiOGQzNzc4NTZlZjlkNTQwMDQ5MjgyOGQzYjQxN2M1YmIzYmZiYWYwNGQ0M2U5YmIwMjc4NjgyN2I4M2M1ZDFjOWUxMjM3MjViZDJlZDM3MGI0ZmJkNDE2MThhYTY2N2JlZDllNjQwNTg4MGIxZjBmYTYzMTU4ZTJlZmI1Zg==/dKtKWqgJFnmS-1XShKtsaJWn_OMY1F_HdGDxH2w38mQ/1662826054"
#
# if referer is not None:
# LogicAniLife.headers["Referer"] = referer
# context = browser.new_context(extra_http_headers=LogicAniLife.headers)
# context = await browser.new_context()
context = await browser.new_context(extra_http_headers=headers)
# LogicAniLife.headers["Cookie"] = cookie_value
# context.set_extra_http_headers(LogicAniLife.headers)
page = await context.new_page()
# page.on("request", set_cookie)
# stealth_sync(page)
await page.goto(url, wait_until="networkidle")
await page.wait_for_timeout(2000)
# time.sleep(1)
# page.reload()
# time.sleep(10)
cookies = context.cookies
# print(cookies)
# print(page.content())
# vod_url = await page.evaluate(
# """() => {
# return console.log(vodUrl_1080p) }"""
# )
# vod_url1 = await page.evaluate(
# """async () =>{
# return _0x55265f(0x99) + alJson[_0x55265f(0x91)]
# }"""
# )
# print(vod_url)
# print(vod_url1)
html_content = await page.content()
# print(await page.content())
# print(f"html_content:: {html_content}")
output_json = html_to_json.convert(html_content)
print(output_json)
print(f"output_json:: {output_json['html'][0]['body'][0]['_value']}")
async def main():
async with async_playwright() as p:
await run(p)
from loguru import logger
import snoop
class Calc:
@staticmethod
# @logger.catch()
@snoop
def add(a, b):
return a + b
cal = Calc()
cal.add(1, 2) # return 3

38
test_sir.py Normal file
View File

@@ -0,0 +1,38 @@
import asyncio
from playwright.async_api import Playwright, async_playwright
async def run(playwright: Playwright) -> None:
browser = await playwright.chromium.launch(headless=False)
context = await browser.new_context()
# Open new page
page = await context.new_page()
# Go to https://sir.kr/
await page.goto("https://sir.kr/")
await asyncio.sleep(1)
# Click [placeholder="아이디"]
await page.locator('[placeholder="아이디"]').click()
# Fill [placeholder="아이디"]
await page.locator('[placeholder="아이디"]').fill("tongki77")
# Press Tab
await page.locator('[placeholder="아이디"]').press("Tab")
# Fill [placeholder="비밀번호"]
await page.locator('[placeholder="비밀번호"]').fill("sir98766")
# Click input:has-text("로그인")
await page.locator('input:has-text("로그인")').click()
# await expect(page).to_have_url("https://sir.kr/")
# Click text=출석 2
await asyncio.sleep(2)
await page.locator("text=출석 2").click()
await asyncio.sleep(2)
# ---------------------
await context.close()
await browser.close()
async def main() -> None:
async with async_playwright() as playwright:
await run(playwright)
asyncio.run(main())